@codemirror/state 0.19.8 → 0.20.1
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 +32 -0
- package/dist/index.cjs +1694 -123
- package/dist/index.d.ts +527 -65
- package/dist/index.js +1664 -102
- package/package.json +1 -4
package/dist/index.cjs
CHANGED
|
@@ -2,7 +2,658 @@
|
|
|
2
2
|
|
|
3
3
|
Object.defineProperty(exports, '__esModule', { value: true });
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
/**
|
|
6
|
+
The data structure for documents. @nonabstract
|
|
7
|
+
*/
|
|
8
|
+
class Text {
|
|
9
|
+
/**
|
|
10
|
+
@internal
|
|
11
|
+
*/
|
|
12
|
+
constructor() { }
|
|
13
|
+
/**
|
|
14
|
+
Get the line description around the given position.
|
|
15
|
+
*/
|
|
16
|
+
lineAt(pos) {
|
|
17
|
+
if (pos < 0 || pos > this.length)
|
|
18
|
+
throw new RangeError(`Invalid position ${pos} in document of length ${this.length}`);
|
|
19
|
+
return this.lineInner(pos, false, 1, 0);
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
Get the description for the given (1-based) line number.
|
|
23
|
+
*/
|
|
24
|
+
line(n) {
|
|
25
|
+
if (n < 1 || n > this.lines)
|
|
26
|
+
throw new RangeError(`Invalid line number ${n} in ${this.lines}-line document`);
|
|
27
|
+
return this.lineInner(n, true, 1, 0);
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
Replace a range of the text with the given content.
|
|
31
|
+
*/
|
|
32
|
+
replace(from, to, text) {
|
|
33
|
+
let parts = [];
|
|
34
|
+
this.decompose(0, from, parts, 2 /* To */);
|
|
35
|
+
if (text.length)
|
|
36
|
+
text.decompose(0, text.length, parts, 1 /* From */ | 2 /* To */);
|
|
37
|
+
this.decompose(to, this.length, parts, 1 /* From */);
|
|
38
|
+
return TextNode.from(parts, this.length - (to - from) + text.length);
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
Append another document to this one.
|
|
42
|
+
*/
|
|
43
|
+
append(other) {
|
|
44
|
+
return this.replace(this.length, this.length, other);
|
|
45
|
+
}
|
|
46
|
+
/**
|
|
47
|
+
Retrieve the text between the given points.
|
|
48
|
+
*/
|
|
49
|
+
slice(from, to = this.length) {
|
|
50
|
+
let parts = [];
|
|
51
|
+
this.decompose(from, to, parts, 0);
|
|
52
|
+
return TextNode.from(parts, to - from);
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
Test whether this text is equal to another instance.
|
|
56
|
+
*/
|
|
57
|
+
eq(other) {
|
|
58
|
+
if (other == this)
|
|
59
|
+
return true;
|
|
60
|
+
if (other.length != this.length || other.lines != this.lines)
|
|
61
|
+
return false;
|
|
62
|
+
let start = this.scanIdentical(other, 1), end = this.length - this.scanIdentical(other, -1);
|
|
63
|
+
let a = new RawTextCursor(this), b = new RawTextCursor(other);
|
|
64
|
+
for (let skip = start, pos = start;;) {
|
|
65
|
+
a.next(skip);
|
|
66
|
+
b.next(skip);
|
|
67
|
+
skip = 0;
|
|
68
|
+
if (a.lineBreak != b.lineBreak || a.done != b.done || a.value != b.value)
|
|
69
|
+
return false;
|
|
70
|
+
pos += a.value.length;
|
|
71
|
+
if (a.done || pos >= end)
|
|
72
|
+
return true;
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
Iterate over the text. When `dir` is `-1`, iteration happens
|
|
77
|
+
from end to start. This will return lines and the breaks between
|
|
78
|
+
them as separate strings.
|
|
79
|
+
*/
|
|
80
|
+
iter(dir = 1) { return new RawTextCursor(this, dir); }
|
|
81
|
+
/**
|
|
82
|
+
Iterate over a range of the text. When `from` > `to`, the
|
|
83
|
+
iterator will run in reverse.
|
|
84
|
+
*/
|
|
85
|
+
iterRange(from, to = this.length) { return new PartialTextCursor(this, from, to); }
|
|
86
|
+
/**
|
|
87
|
+
Return a cursor that iterates over the given range of lines,
|
|
88
|
+
_without_ returning the line breaks between, and yielding empty
|
|
89
|
+
strings for empty lines.
|
|
90
|
+
|
|
91
|
+
When `from` and `to` are given, they should be 1-based line numbers.
|
|
92
|
+
*/
|
|
93
|
+
iterLines(from, to) {
|
|
94
|
+
let inner;
|
|
95
|
+
if (from == null) {
|
|
96
|
+
inner = this.iter();
|
|
97
|
+
}
|
|
98
|
+
else {
|
|
99
|
+
if (to == null)
|
|
100
|
+
to = this.lines + 1;
|
|
101
|
+
let start = this.line(from).from;
|
|
102
|
+
inner = this.iterRange(start, Math.max(start, to == this.lines + 1 ? this.length : to <= 1 ? 0 : this.line(to - 1).to));
|
|
103
|
+
}
|
|
104
|
+
return new LineCursor(inner);
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
@internal
|
|
108
|
+
*/
|
|
109
|
+
toString() { return this.sliceString(0); }
|
|
110
|
+
/**
|
|
111
|
+
Convert the document to an array of lines (which can be
|
|
112
|
+
deserialized again via [`Text.of`](https://codemirror.net/6/docs/ref/#state.Text^of)).
|
|
113
|
+
*/
|
|
114
|
+
toJSON() {
|
|
115
|
+
let lines = [];
|
|
116
|
+
this.flatten(lines);
|
|
117
|
+
return lines;
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
Create a `Text` instance for the given array of lines.
|
|
121
|
+
*/
|
|
122
|
+
static of(text) {
|
|
123
|
+
if (text.length == 0)
|
|
124
|
+
throw new RangeError("A document must have at least one line");
|
|
125
|
+
if (text.length == 1 && !text[0])
|
|
126
|
+
return Text.empty;
|
|
127
|
+
return text.length <= 32 /* Branch */ ? new TextLeaf(text) : TextNode.from(TextLeaf.split(text, []));
|
|
128
|
+
}
|
|
129
|
+
}
|
|
130
|
+
// Leaves store an array of line strings. There are always line breaks
|
|
131
|
+
// between these strings. Leaves are limited in size and have to be
|
|
132
|
+
// contained in TextNode instances for bigger documents.
|
|
133
|
+
class TextLeaf extends Text {
|
|
134
|
+
constructor(text, length = textLength(text)) {
|
|
135
|
+
super();
|
|
136
|
+
this.text = text;
|
|
137
|
+
this.length = length;
|
|
138
|
+
}
|
|
139
|
+
get lines() { return this.text.length; }
|
|
140
|
+
get children() { return null; }
|
|
141
|
+
lineInner(target, isLine, line, offset) {
|
|
142
|
+
for (let i = 0;; i++) {
|
|
143
|
+
let string = this.text[i], end = offset + string.length;
|
|
144
|
+
if ((isLine ? line : end) >= target)
|
|
145
|
+
return new Line(offset, end, line, string);
|
|
146
|
+
offset = end + 1;
|
|
147
|
+
line++;
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
decompose(from, to, target, open) {
|
|
151
|
+
let text = from <= 0 && to >= this.length ? this
|
|
152
|
+
: new TextLeaf(sliceText(this.text, from, to), Math.min(to, this.length) - Math.max(0, from));
|
|
153
|
+
if (open & 1 /* From */) {
|
|
154
|
+
let prev = target.pop();
|
|
155
|
+
let joined = appendText(text.text, prev.text.slice(), 0, text.length);
|
|
156
|
+
if (joined.length <= 32 /* Branch */) {
|
|
157
|
+
target.push(new TextLeaf(joined, prev.length + text.length));
|
|
158
|
+
}
|
|
159
|
+
else {
|
|
160
|
+
let mid = joined.length >> 1;
|
|
161
|
+
target.push(new TextLeaf(joined.slice(0, mid)), new TextLeaf(joined.slice(mid)));
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
else {
|
|
165
|
+
target.push(text);
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
replace(from, to, text) {
|
|
169
|
+
if (!(text instanceof TextLeaf))
|
|
170
|
+
return super.replace(from, to, text);
|
|
171
|
+
let lines = appendText(this.text, appendText(text.text, sliceText(this.text, 0, from)), to);
|
|
172
|
+
let newLen = this.length + text.length - (to - from);
|
|
173
|
+
if (lines.length <= 32 /* Branch */)
|
|
174
|
+
return new TextLeaf(lines, newLen);
|
|
175
|
+
return TextNode.from(TextLeaf.split(lines, []), newLen);
|
|
176
|
+
}
|
|
177
|
+
sliceString(from, to = this.length, lineSep = "\n") {
|
|
178
|
+
let result = "";
|
|
179
|
+
for (let pos = 0, i = 0; pos <= to && i < this.text.length; i++) {
|
|
180
|
+
let line = this.text[i], end = pos + line.length;
|
|
181
|
+
if (pos > from && i)
|
|
182
|
+
result += lineSep;
|
|
183
|
+
if (from < end && to > pos)
|
|
184
|
+
result += line.slice(Math.max(0, from - pos), to - pos);
|
|
185
|
+
pos = end + 1;
|
|
186
|
+
}
|
|
187
|
+
return result;
|
|
188
|
+
}
|
|
189
|
+
flatten(target) {
|
|
190
|
+
for (let line of this.text)
|
|
191
|
+
target.push(line);
|
|
192
|
+
}
|
|
193
|
+
scanIdentical() { return 0; }
|
|
194
|
+
static split(text, target) {
|
|
195
|
+
let part = [], len = -1;
|
|
196
|
+
for (let line of text) {
|
|
197
|
+
part.push(line);
|
|
198
|
+
len += line.length + 1;
|
|
199
|
+
if (part.length == 32 /* Branch */) {
|
|
200
|
+
target.push(new TextLeaf(part, len));
|
|
201
|
+
part = [];
|
|
202
|
+
len = -1;
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
if (len > -1)
|
|
206
|
+
target.push(new TextLeaf(part, len));
|
|
207
|
+
return target;
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
// Nodes provide the tree structure of the `Text` type. They store a
|
|
211
|
+
// number of other nodes or leaves, taking care to balance themselves
|
|
212
|
+
// on changes. There are implied line breaks _between_ the children of
|
|
213
|
+
// a node (but not before the first or after the last child).
|
|
214
|
+
class TextNode extends Text {
|
|
215
|
+
constructor(children, length) {
|
|
216
|
+
super();
|
|
217
|
+
this.children = children;
|
|
218
|
+
this.length = length;
|
|
219
|
+
this.lines = 0;
|
|
220
|
+
for (let child of children)
|
|
221
|
+
this.lines += child.lines;
|
|
222
|
+
}
|
|
223
|
+
lineInner(target, isLine, line, offset) {
|
|
224
|
+
for (let i = 0;; i++) {
|
|
225
|
+
let child = this.children[i], end = offset + child.length, endLine = line + child.lines - 1;
|
|
226
|
+
if ((isLine ? endLine : end) >= target)
|
|
227
|
+
return child.lineInner(target, isLine, line, offset);
|
|
228
|
+
offset = end + 1;
|
|
229
|
+
line = endLine + 1;
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
decompose(from, to, target, open) {
|
|
233
|
+
for (let i = 0, pos = 0; pos <= to && i < this.children.length; i++) {
|
|
234
|
+
let child = this.children[i], end = pos + child.length;
|
|
235
|
+
if (from <= end && to >= pos) {
|
|
236
|
+
let childOpen = open & ((pos <= from ? 1 /* From */ : 0) | (end >= to ? 2 /* To */ : 0));
|
|
237
|
+
if (pos >= from && end <= to && !childOpen)
|
|
238
|
+
target.push(child);
|
|
239
|
+
else
|
|
240
|
+
child.decompose(from - pos, to - pos, target, childOpen);
|
|
241
|
+
}
|
|
242
|
+
pos = end + 1;
|
|
243
|
+
}
|
|
244
|
+
}
|
|
245
|
+
replace(from, to, text) {
|
|
246
|
+
if (text.lines < this.lines)
|
|
247
|
+
for (let i = 0, pos = 0; i < this.children.length; i++) {
|
|
248
|
+
let child = this.children[i], end = pos + child.length;
|
|
249
|
+
// Fast path: if the change only affects one child and the
|
|
250
|
+
// child's size remains in the acceptable range, only update
|
|
251
|
+
// that child
|
|
252
|
+
if (from >= pos && to <= end) {
|
|
253
|
+
let updated = child.replace(from - pos, to - pos, text);
|
|
254
|
+
let totalLines = this.lines - child.lines + updated.lines;
|
|
255
|
+
if (updated.lines < (totalLines >> (5 /* BranchShift */ - 1)) &&
|
|
256
|
+
updated.lines > (totalLines >> (5 /* BranchShift */ + 1))) {
|
|
257
|
+
let copy = this.children.slice();
|
|
258
|
+
copy[i] = updated;
|
|
259
|
+
return new TextNode(copy, this.length - (to - from) + text.length);
|
|
260
|
+
}
|
|
261
|
+
return super.replace(pos, end, updated);
|
|
262
|
+
}
|
|
263
|
+
pos = end + 1;
|
|
264
|
+
}
|
|
265
|
+
return super.replace(from, to, text);
|
|
266
|
+
}
|
|
267
|
+
sliceString(from, to = this.length, lineSep = "\n") {
|
|
268
|
+
let result = "";
|
|
269
|
+
for (let i = 0, pos = 0; i < this.children.length && pos <= to; i++) {
|
|
270
|
+
let child = this.children[i], end = pos + child.length;
|
|
271
|
+
if (pos > from && i)
|
|
272
|
+
result += lineSep;
|
|
273
|
+
if (from < end && to > pos)
|
|
274
|
+
result += child.sliceString(from - pos, to - pos, lineSep);
|
|
275
|
+
pos = end + 1;
|
|
276
|
+
}
|
|
277
|
+
return result;
|
|
278
|
+
}
|
|
279
|
+
flatten(target) {
|
|
280
|
+
for (let child of this.children)
|
|
281
|
+
child.flatten(target);
|
|
282
|
+
}
|
|
283
|
+
scanIdentical(other, dir) {
|
|
284
|
+
if (!(other instanceof TextNode))
|
|
285
|
+
return 0;
|
|
286
|
+
let length = 0;
|
|
287
|
+
let [iA, iB, eA, eB] = dir > 0 ? [0, 0, this.children.length, other.children.length]
|
|
288
|
+
: [this.children.length - 1, other.children.length - 1, -1, -1];
|
|
289
|
+
for (;; iA += dir, iB += dir) {
|
|
290
|
+
if (iA == eA || iB == eB)
|
|
291
|
+
return length;
|
|
292
|
+
let chA = this.children[iA], chB = other.children[iB];
|
|
293
|
+
if (chA != chB)
|
|
294
|
+
return length + chA.scanIdentical(chB, dir);
|
|
295
|
+
length += chA.length + 1;
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
static from(children, length = children.reduce((l, ch) => l + ch.length + 1, -1)) {
|
|
299
|
+
let lines = 0;
|
|
300
|
+
for (let ch of children)
|
|
301
|
+
lines += ch.lines;
|
|
302
|
+
if (lines < 32 /* Branch */) {
|
|
303
|
+
let flat = [];
|
|
304
|
+
for (let ch of children)
|
|
305
|
+
ch.flatten(flat);
|
|
306
|
+
return new TextLeaf(flat, length);
|
|
307
|
+
}
|
|
308
|
+
let chunk = Math.max(32 /* Branch */, lines >> 5 /* BranchShift */), maxChunk = chunk << 1, minChunk = chunk >> 1;
|
|
309
|
+
let chunked = [], currentLines = 0, currentLen = -1, currentChunk = [];
|
|
310
|
+
function add(child) {
|
|
311
|
+
let last;
|
|
312
|
+
if (child.lines > maxChunk && child instanceof TextNode) {
|
|
313
|
+
for (let node of child.children)
|
|
314
|
+
add(node);
|
|
315
|
+
}
|
|
316
|
+
else if (child.lines > minChunk && (currentLines > minChunk || !currentLines)) {
|
|
317
|
+
flush();
|
|
318
|
+
chunked.push(child);
|
|
319
|
+
}
|
|
320
|
+
else if (child instanceof TextLeaf && currentLines &&
|
|
321
|
+
(last = currentChunk[currentChunk.length - 1]) instanceof TextLeaf &&
|
|
322
|
+
child.lines + last.lines <= 32 /* Branch */) {
|
|
323
|
+
currentLines += child.lines;
|
|
324
|
+
currentLen += child.length + 1;
|
|
325
|
+
currentChunk[currentChunk.length - 1] = new TextLeaf(last.text.concat(child.text), last.length + 1 + child.length);
|
|
326
|
+
}
|
|
327
|
+
else {
|
|
328
|
+
if (currentLines + child.lines > chunk)
|
|
329
|
+
flush();
|
|
330
|
+
currentLines += child.lines;
|
|
331
|
+
currentLen += child.length + 1;
|
|
332
|
+
currentChunk.push(child);
|
|
333
|
+
}
|
|
334
|
+
}
|
|
335
|
+
function flush() {
|
|
336
|
+
if (currentLines == 0)
|
|
337
|
+
return;
|
|
338
|
+
chunked.push(currentChunk.length == 1 ? currentChunk[0] : TextNode.from(currentChunk, currentLen));
|
|
339
|
+
currentLen = -1;
|
|
340
|
+
currentLines = currentChunk.length = 0;
|
|
341
|
+
}
|
|
342
|
+
for (let child of children)
|
|
343
|
+
add(child);
|
|
344
|
+
flush();
|
|
345
|
+
return chunked.length == 1 ? chunked[0] : new TextNode(chunked, length);
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
Text.empty = new TextLeaf([""], 0);
|
|
349
|
+
function textLength(text) {
|
|
350
|
+
let length = -1;
|
|
351
|
+
for (let line of text)
|
|
352
|
+
length += line.length + 1;
|
|
353
|
+
return length;
|
|
354
|
+
}
|
|
355
|
+
function appendText(text, target, from = 0, to = 1e9) {
|
|
356
|
+
for (let pos = 0, i = 0, first = true; i < text.length && pos <= to; i++) {
|
|
357
|
+
let line = text[i], end = pos + line.length;
|
|
358
|
+
if (end >= from) {
|
|
359
|
+
if (end > to)
|
|
360
|
+
line = line.slice(0, to - pos);
|
|
361
|
+
if (pos < from)
|
|
362
|
+
line = line.slice(from - pos);
|
|
363
|
+
if (first) {
|
|
364
|
+
target[target.length - 1] += line;
|
|
365
|
+
first = false;
|
|
366
|
+
}
|
|
367
|
+
else
|
|
368
|
+
target.push(line);
|
|
369
|
+
}
|
|
370
|
+
pos = end + 1;
|
|
371
|
+
}
|
|
372
|
+
return target;
|
|
373
|
+
}
|
|
374
|
+
function sliceText(text, from, to) {
|
|
375
|
+
return appendText(text, [""], from, to);
|
|
376
|
+
}
|
|
377
|
+
class RawTextCursor {
|
|
378
|
+
constructor(text, dir = 1) {
|
|
379
|
+
this.dir = dir;
|
|
380
|
+
this.done = false;
|
|
381
|
+
this.lineBreak = false;
|
|
382
|
+
this.value = "";
|
|
383
|
+
this.nodes = [text];
|
|
384
|
+
this.offsets = [dir > 0 ? 1 : (text instanceof TextLeaf ? text.text.length : text.children.length) << 1];
|
|
385
|
+
}
|
|
386
|
+
nextInner(skip, dir) {
|
|
387
|
+
this.done = this.lineBreak = false;
|
|
388
|
+
for (;;) {
|
|
389
|
+
let last = this.nodes.length - 1;
|
|
390
|
+
let top = this.nodes[last], offsetValue = this.offsets[last], offset = offsetValue >> 1;
|
|
391
|
+
let size = top instanceof TextLeaf ? top.text.length : top.children.length;
|
|
392
|
+
if (offset == (dir > 0 ? size : 0)) {
|
|
393
|
+
if (last == 0) {
|
|
394
|
+
this.done = true;
|
|
395
|
+
this.value = "";
|
|
396
|
+
return this;
|
|
397
|
+
}
|
|
398
|
+
if (dir > 0)
|
|
399
|
+
this.offsets[last - 1]++;
|
|
400
|
+
this.nodes.pop();
|
|
401
|
+
this.offsets.pop();
|
|
402
|
+
}
|
|
403
|
+
else if ((offsetValue & 1) == (dir > 0 ? 0 : 1)) {
|
|
404
|
+
this.offsets[last] += dir;
|
|
405
|
+
if (skip == 0) {
|
|
406
|
+
this.lineBreak = true;
|
|
407
|
+
this.value = "\n";
|
|
408
|
+
return this;
|
|
409
|
+
}
|
|
410
|
+
skip--;
|
|
411
|
+
}
|
|
412
|
+
else if (top instanceof TextLeaf) {
|
|
413
|
+
// Move to the next string
|
|
414
|
+
let next = top.text[offset + (dir < 0 ? -1 : 0)];
|
|
415
|
+
this.offsets[last] += dir;
|
|
416
|
+
if (next.length > Math.max(0, skip)) {
|
|
417
|
+
this.value = skip == 0 ? next : dir > 0 ? next.slice(skip) : next.slice(0, next.length - skip);
|
|
418
|
+
return this;
|
|
419
|
+
}
|
|
420
|
+
skip -= next.length;
|
|
421
|
+
}
|
|
422
|
+
else {
|
|
423
|
+
let next = top.children[offset + (dir < 0 ? -1 : 0)];
|
|
424
|
+
if (skip > next.length) {
|
|
425
|
+
skip -= next.length;
|
|
426
|
+
this.offsets[last] += dir;
|
|
427
|
+
}
|
|
428
|
+
else {
|
|
429
|
+
if (dir < 0)
|
|
430
|
+
this.offsets[last]--;
|
|
431
|
+
this.nodes.push(next);
|
|
432
|
+
this.offsets.push(dir > 0 ? 1 : (next instanceof TextLeaf ? next.text.length : next.children.length) << 1);
|
|
433
|
+
}
|
|
434
|
+
}
|
|
435
|
+
}
|
|
436
|
+
}
|
|
437
|
+
next(skip = 0) {
|
|
438
|
+
if (skip < 0) {
|
|
439
|
+
this.nextInner(-skip, (-this.dir));
|
|
440
|
+
skip = this.value.length;
|
|
441
|
+
}
|
|
442
|
+
return this.nextInner(skip, this.dir);
|
|
443
|
+
}
|
|
444
|
+
}
|
|
445
|
+
class PartialTextCursor {
|
|
446
|
+
constructor(text, start, end) {
|
|
447
|
+
this.value = "";
|
|
448
|
+
this.done = false;
|
|
449
|
+
this.cursor = new RawTextCursor(text, start > end ? -1 : 1);
|
|
450
|
+
this.pos = start > end ? text.length : 0;
|
|
451
|
+
this.from = Math.min(start, end);
|
|
452
|
+
this.to = Math.max(start, end);
|
|
453
|
+
}
|
|
454
|
+
nextInner(skip, dir) {
|
|
455
|
+
if (dir < 0 ? this.pos <= this.from : this.pos >= this.to) {
|
|
456
|
+
this.value = "";
|
|
457
|
+
this.done = true;
|
|
458
|
+
return this;
|
|
459
|
+
}
|
|
460
|
+
skip += Math.max(0, dir < 0 ? this.pos - this.to : this.from - this.pos);
|
|
461
|
+
let limit = dir < 0 ? this.pos - this.from : this.to - this.pos;
|
|
462
|
+
if (skip > limit)
|
|
463
|
+
skip = limit;
|
|
464
|
+
limit -= skip;
|
|
465
|
+
let { value } = this.cursor.next(skip);
|
|
466
|
+
this.pos += (value.length + skip) * dir;
|
|
467
|
+
this.value = value.length <= limit ? value : dir < 0 ? value.slice(value.length - limit) : value.slice(0, limit);
|
|
468
|
+
this.done = !this.value;
|
|
469
|
+
return this;
|
|
470
|
+
}
|
|
471
|
+
next(skip = 0) {
|
|
472
|
+
if (skip < 0)
|
|
473
|
+
skip = Math.max(skip, this.from - this.pos);
|
|
474
|
+
else if (skip > 0)
|
|
475
|
+
skip = Math.min(skip, this.to - this.pos);
|
|
476
|
+
return this.nextInner(skip, this.cursor.dir);
|
|
477
|
+
}
|
|
478
|
+
get lineBreak() { return this.cursor.lineBreak && this.value != ""; }
|
|
479
|
+
}
|
|
480
|
+
class LineCursor {
|
|
481
|
+
constructor(inner) {
|
|
482
|
+
this.inner = inner;
|
|
483
|
+
this.afterBreak = true;
|
|
484
|
+
this.value = "";
|
|
485
|
+
this.done = false;
|
|
486
|
+
}
|
|
487
|
+
next(skip = 0) {
|
|
488
|
+
let { done, lineBreak, value } = this.inner.next(skip);
|
|
489
|
+
if (done) {
|
|
490
|
+
this.done = true;
|
|
491
|
+
this.value = "";
|
|
492
|
+
}
|
|
493
|
+
else if (lineBreak) {
|
|
494
|
+
if (this.afterBreak) {
|
|
495
|
+
this.value = "";
|
|
496
|
+
}
|
|
497
|
+
else {
|
|
498
|
+
this.afterBreak = true;
|
|
499
|
+
this.next();
|
|
500
|
+
}
|
|
501
|
+
}
|
|
502
|
+
else {
|
|
503
|
+
this.value = value;
|
|
504
|
+
this.afterBreak = false;
|
|
505
|
+
}
|
|
506
|
+
return this;
|
|
507
|
+
}
|
|
508
|
+
get lineBreak() { return false; }
|
|
509
|
+
}
|
|
510
|
+
if (typeof Symbol != "undefined") {
|
|
511
|
+
Text.prototype[Symbol.iterator] = function () { return this.iter(); };
|
|
512
|
+
RawTextCursor.prototype[Symbol.iterator] = PartialTextCursor.prototype[Symbol.iterator] =
|
|
513
|
+
LineCursor.prototype[Symbol.iterator] = function () { return this; };
|
|
514
|
+
}
|
|
515
|
+
/**
|
|
516
|
+
This type describes a line in the document. It is created
|
|
517
|
+
on-demand when lines are [queried](https://codemirror.net/6/docs/ref/#state.Text.lineAt).
|
|
518
|
+
*/
|
|
519
|
+
class Line {
|
|
520
|
+
/**
|
|
521
|
+
@internal
|
|
522
|
+
*/
|
|
523
|
+
constructor(
|
|
524
|
+
/**
|
|
525
|
+
The position of the start of the line.
|
|
526
|
+
*/
|
|
527
|
+
from,
|
|
528
|
+
/**
|
|
529
|
+
The position at the end of the line (_before_ the line break,
|
|
530
|
+
or at the end of document for the last line).
|
|
531
|
+
*/
|
|
532
|
+
to,
|
|
533
|
+
/**
|
|
534
|
+
This line's line number (1-based).
|
|
535
|
+
*/
|
|
536
|
+
number,
|
|
537
|
+
/**
|
|
538
|
+
The line's content.
|
|
539
|
+
*/
|
|
540
|
+
text) {
|
|
541
|
+
this.from = from;
|
|
542
|
+
this.to = to;
|
|
543
|
+
this.number = number;
|
|
544
|
+
this.text = text;
|
|
545
|
+
}
|
|
546
|
+
/**
|
|
547
|
+
The length of the line (not including any line break after it).
|
|
548
|
+
*/
|
|
549
|
+
get length() { return this.to - this.from; }
|
|
550
|
+
}
|
|
551
|
+
|
|
552
|
+
// Compressed representation of the Grapheme_Cluster_Break=Extend
|
|
553
|
+
// information from
|
|
554
|
+
// http://www.unicode.org/Public/13.0.0/ucd/auxiliary/GraphemeBreakProperty.txt.
|
|
555
|
+
// Each pair of elements represents a range, as an offet from the
|
|
556
|
+
// previous range and a length. Numbers are in base-36, with the empty
|
|
557
|
+
// string being a shorthand for 1.
|
|
558
|
+
let extend = "lc,34,7n,7,7b,19,,,,2,,2,,,20,b,1c,l,g,,2t,7,2,6,2,2,,4,z,,u,r,2j,b,1m,9,9,,o,4,,9,,3,,5,17,3,3b,f,,w,1j,,,,4,8,4,,3,7,a,2,t,,1m,,,,2,4,8,,9,,a,2,q,,2,2,1l,,4,2,4,2,2,3,3,,u,2,3,,b,2,1l,,4,5,,2,4,,k,2,m,6,,,1m,,,2,,4,8,,7,3,a,2,u,,1n,,,,c,,9,,14,,3,,1l,3,5,3,,4,7,2,b,2,t,,1m,,2,,2,,3,,5,2,7,2,b,2,s,2,1l,2,,,2,4,8,,9,,a,2,t,,20,,4,,2,3,,,8,,29,,2,7,c,8,2q,,2,9,b,6,22,2,r,,,,,,1j,e,,5,,2,5,b,,10,9,,2u,4,,6,,2,2,2,p,2,4,3,g,4,d,,2,2,6,,f,,jj,3,qa,3,t,3,t,2,u,2,1s,2,,7,8,,2,b,9,,19,3,3b,2,y,,3a,3,4,2,9,,6,3,63,2,2,,1m,,,7,,,,,2,8,6,a,2,,1c,h,1r,4,1c,7,,,5,,14,9,c,2,w,4,2,2,,3,1k,,,2,3,,,3,1m,8,2,2,48,3,,d,,7,4,,6,,3,2,5i,1m,,5,ek,,5f,x,2da,3,3x,,2o,w,fe,6,2x,2,n9w,4,,a,w,2,28,2,7k,,3,,4,,p,2,5,,47,2,q,i,d,,12,8,p,b,1a,3,1c,,2,4,2,2,13,,1v,6,2,2,2,2,c,,8,,1b,,1f,,,3,2,2,5,2,,,16,2,8,,6m,,2,,4,,fn4,,kh,g,g,g,a6,2,gt,,6a,,45,5,1ae,3,,2,5,4,14,3,4,,4l,2,fx,4,ar,2,49,b,4w,,1i,f,1k,3,1d,4,2,2,1x,3,10,5,,8,1q,,c,2,1g,9,a,4,2,,2n,3,2,,,2,6,,4g,,3,8,l,2,1l,2,,,,,m,,e,7,3,5,5f,8,2,3,,,n,,29,,2,6,,,2,,,2,,2,6j,,2,4,6,2,,2,r,2,2d,8,2,,,2,2y,,,,2,6,,,2t,3,2,4,,5,77,9,,2,6t,,a,2,,,4,,40,4,2,2,4,,w,a,14,6,2,4,8,,9,6,2,3,1a,d,,2,ba,7,,6,,,2a,m,2,7,,2,,2,3e,6,3,,,2,,7,,,20,2,3,,,,9n,2,f0b,5,1n,7,t4,,1r,4,29,,f5k,2,43q,,,3,4,5,8,8,2,7,u,4,44,3,1iz,1j,4,1e,8,,e,,m,5,,f,11s,7,,h,2,7,,2,,5,79,7,c5,4,15s,7,31,7,240,5,gx7k,2o,3k,6o".split(",").map(s => s ? parseInt(s, 36) : 1);
|
|
559
|
+
// Convert offsets into absolute values
|
|
560
|
+
for (let i = 1; i < extend.length; i++)
|
|
561
|
+
extend[i] += extend[i - 1];
|
|
562
|
+
function isExtendingChar(code) {
|
|
563
|
+
for (let i = 1; i < extend.length; i += 2)
|
|
564
|
+
if (extend[i] > code)
|
|
565
|
+
return extend[i - 1] <= code;
|
|
566
|
+
return false;
|
|
567
|
+
}
|
|
568
|
+
function isRegionalIndicator(code) {
|
|
569
|
+
return code >= 0x1F1E6 && code <= 0x1F1FF;
|
|
570
|
+
}
|
|
571
|
+
const ZWJ = 0x200d;
|
|
572
|
+
/**
|
|
573
|
+
Returns a next grapheme cluster break _after_ (not equal to)
|
|
574
|
+
`pos`, if `forward` is true, or before otherwise. Returns `pos`
|
|
575
|
+
itself if no further cluster break is available in the string.
|
|
576
|
+
Moves across surrogate pairs, extending characters (when
|
|
577
|
+
`includeExtending` is true), characters joined with zero-width
|
|
578
|
+
joiners, and flag emoji.
|
|
579
|
+
*/
|
|
580
|
+
function findClusterBreak(str, pos, forward = true, includeExtending = true) {
|
|
581
|
+
return (forward ? nextClusterBreak : prevClusterBreak)(str, pos, includeExtending);
|
|
582
|
+
}
|
|
583
|
+
function nextClusterBreak(str, pos, includeExtending) {
|
|
584
|
+
if (pos == str.length)
|
|
585
|
+
return pos;
|
|
586
|
+
// If pos is in the middle of a surrogate pair, move to its start
|
|
587
|
+
if (pos && surrogateLow(str.charCodeAt(pos)) && surrogateHigh(str.charCodeAt(pos - 1)))
|
|
588
|
+
pos--;
|
|
589
|
+
let prev = codePointAt(str, pos);
|
|
590
|
+
pos += codePointSize(prev);
|
|
591
|
+
while (pos < str.length) {
|
|
592
|
+
let next = codePointAt(str, pos);
|
|
593
|
+
if (prev == ZWJ || next == ZWJ || includeExtending && isExtendingChar(next)) {
|
|
594
|
+
pos += codePointSize(next);
|
|
595
|
+
prev = next;
|
|
596
|
+
}
|
|
597
|
+
else if (isRegionalIndicator(next)) {
|
|
598
|
+
let countBefore = 0, i = pos - 2;
|
|
599
|
+
while (i >= 0 && isRegionalIndicator(codePointAt(str, i))) {
|
|
600
|
+
countBefore++;
|
|
601
|
+
i -= 2;
|
|
602
|
+
}
|
|
603
|
+
if (countBefore % 2 == 0)
|
|
604
|
+
break;
|
|
605
|
+
else
|
|
606
|
+
pos += 2;
|
|
607
|
+
}
|
|
608
|
+
else {
|
|
609
|
+
break;
|
|
610
|
+
}
|
|
611
|
+
}
|
|
612
|
+
return pos;
|
|
613
|
+
}
|
|
614
|
+
function prevClusterBreak(str, pos, includeExtending) {
|
|
615
|
+
while (pos > 0) {
|
|
616
|
+
let found = nextClusterBreak(str, pos - 2, includeExtending);
|
|
617
|
+
if (found < pos)
|
|
618
|
+
return found;
|
|
619
|
+
pos--;
|
|
620
|
+
}
|
|
621
|
+
return 0;
|
|
622
|
+
}
|
|
623
|
+
function surrogateLow(ch) { return ch >= 0xDC00 && ch < 0xE000; }
|
|
624
|
+
function surrogateHigh(ch) { return ch >= 0xD800 && ch < 0xDC00; }
|
|
625
|
+
/**
|
|
626
|
+
Find the code point at the given position in a string (like the
|
|
627
|
+
[`codePointAt`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/codePointAt)
|
|
628
|
+
string method).
|
|
629
|
+
*/
|
|
630
|
+
function codePointAt(str, pos) {
|
|
631
|
+
let code0 = str.charCodeAt(pos);
|
|
632
|
+
if (!surrogateHigh(code0) || pos + 1 == str.length)
|
|
633
|
+
return code0;
|
|
634
|
+
let code1 = str.charCodeAt(pos + 1);
|
|
635
|
+
if (!surrogateLow(code1))
|
|
636
|
+
return code0;
|
|
637
|
+
return ((code0 - 0xd800) << 10) + (code1 - 0xdc00) + 0x10000;
|
|
638
|
+
}
|
|
639
|
+
/**
|
|
640
|
+
Given a Unicode codepoint, return the JavaScript string that
|
|
641
|
+
respresents it (like
|
|
642
|
+
[`String.fromCodePoint`](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/fromCodePoint)).
|
|
643
|
+
*/
|
|
644
|
+
function fromCodePoint(code) {
|
|
645
|
+
if (code <= 0xffff)
|
|
646
|
+
return String.fromCharCode(code);
|
|
647
|
+
code -= 0x10000;
|
|
648
|
+
return String.fromCharCode((code >> 10) + 0xd800, (code & 1023) + 0xdc00);
|
|
649
|
+
}
|
|
650
|
+
/**
|
|
651
|
+
The first character that takes up two positions in a JavaScript
|
|
652
|
+
string. It is often useful to compare with this after calling
|
|
653
|
+
`codePointAt`, to figure out whether your character takes up 1 or
|
|
654
|
+
2 index positions.
|
|
655
|
+
*/
|
|
656
|
+
function codePointSize(code) { return code < 0x10000 ? 1 : 2; }
|
|
6
657
|
|
|
7
658
|
const DefaultSplit = /\r\n?|\n/;
|
|
8
659
|
/**
|
|
@@ -39,9 +690,6 @@ class ChangeDesc {
|
|
|
39
690
|
// unaffected sections, and the length of the replacement content
|
|
40
691
|
// otherwise. So an insertion would be (0, n>0), a deletion (n>0,
|
|
41
692
|
// 0), and a replacement two positive numbers.
|
|
42
|
-
/**
|
|
43
|
-
@internal
|
|
44
|
-
*/
|
|
45
693
|
constructor(
|
|
46
694
|
/**
|
|
47
695
|
@internal
|
|
@@ -74,7 +722,9 @@ class ChangeDesc {
|
|
|
74
722
|
*/
|
|
75
723
|
get empty() { return this.sections.length == 0 || this.sections.length == 2 && this.sections[1] < 0; }
|
|
76
724
|
/**
|
|
77
|
-
Iterate over the unchanged parts left by these changes.
|
|
725
|
+
Iterate over the unchanged parts left by these changes. `posA`
|
|
726
|
+
provides the position of the range in the old document, `posB`
|
|
727
|
+
the new position in the changed document.
|
|
78
728
|
*/
|
|
79
729
|
iterGaps(f) {
|
|
80
730
|
for (let i = 0, posA = 0, posB = 0; i < this.sections.length;) {
|
|
@@ -93,6 +743,9 @@ class ChangeDesc {
|
|
|
93
743
|
Iterate over the ranges changed by these changes. (See
|
|
94
744
|
[`ChangeSet.iterChanges`](https://codemirror.net/6/docs/ref/#state.ChangeSet.iterChanges) for a
|
|
95
745
|
variant that also provides you with the inserted text.)
|
|
746
|
+
`fromA`/`toA` provides the extent of the change in the starting
|
|
747
|
+
document, `fromB`/`toB` the extent of the replacement in the
|
|
748
|
+
changed document.
|
|
96
749
|
|
|
97
750
|
When `individual` is true, adjacent changes (which are kept
|
|
98
751
|
separate for [position mapping](https://codemirror.net/6/docs/ref/#state.ChangeDesc.mapPos)) are
|
|
@@ -191,6 +844,10 @@ class ChangeDesc {
|
|
|
191
844
|
throw new RangeError("Invalid JSON representation of ChangeDesc");
|
|
192
845
|
return new ChangeDesc(json);
|
|
193
846
|
}
|
|
847
|
+
/**
|
|
848
|
+
@internal
|
|
849
|
+
*/
|
|
850
|
+
static create(sections) { return new ChangeDesc(sections); }
|
|
194
851
|
}
|
|
195
852
|
/**
|
|
196
853
|
A change set represents a group of modifications to a document. It
|
|
@@ -198,9 +855,6 @@ stores the document length, and can only be applied to documents
|
|
|
198
855
|
with exactly that length.
|
|
199
856
|
*/
|
|
200
857
|
class ChangeSet extends ChangeDesc {
|
|
201
|
-
/**
|
|
202
|
-
@internal
|
|
203
|
-
*/
|
|
204
858
|
constructor(sections,
|
|
205
859
|
/**
|
|
206
860
|
@internal
|
|
@@ -235,8 +889,8 @@ class ChangeSet extends ChangeDesc {
|
|
|
235
889
|
sections[i + 1] = len;
|
|
236
890
|
let index = i >> 1;
|
|
237
891
|
while (inserted.length < index)
|
|
238
|
-
inserted.push(
|
|
239
|
-
inserted.push(len ? doc.slice(pos, pos + len) :
|
|
892
|
+
inserted.push(Text.empty);
|
|
893
|
+
inserted.push(len ? doc.slice(pos, pos + len) : Text.empty);
|
|
240
894
|
}
|
|
241
895
|
pos += len;
|
|
242
896
|
}
|
|
@@ -279,7 +933,7 @@ class ChangeSet extends ChangeDesc {
|
|
|
279
933
|
Get a [change description](https://codemirror.net/6/docs/ref/#state.ChangeDesc) for this change
|
|
280
934
|
set.
|
|
281
935
|
*/
|
|
282
|
-
get desc() { return
|
|
936
|
+
get desc() { return ChangeDesc.create(this.sections); }
|
|
283
937
|
/**
|
|
284
938
|
@internal
|
|
285
939
|
*/
|
|
@@ -312,7 +966,7 @@ class ChangeSet extends ChangeDesc {
|
|
|
312
966
|
}
|
|
313
967
|
}
|
|
314
968
|
return { changes: new ChangeSet(resultSections, resultInserted),
|
|
315
|
-
filtered:
|
|
969
|
+
filtered: ChangeDesc.create(filteredSections) };
|
|
316
970
|
}
|
|
317
971
|
/**
|
|
318
972
|
Serialize this change set to a JSON-representable value.
|
|
@@ -363,7 +1017,7 @@ class ChangeSet extends ChangeDesc {
|
|
|
363
1017
|
let { from, to = from, insert } = spec;
|
|
364
1018
|
if (from > to || from < 0 || to > length)
|
|
365
1019
|
throw new RangeError(`Invalid change range ${from} to ${to} (in doc of length ${length})`);
|
|
366
|
-
let insText = !insert ?
|
|
1020
|
+
let insText = !insert ? Text.empty : typeof insert == "string" ? Text.of(insert.split(lineSep || DefaultSplit)) : insert;
|
|
367
1021
|
let insLen = insText.length;
|
|
368
1022
|
if (from == to && insLen == 0)
|
|
369
1023
|
return;
|
|
@@ -407,13 +1061,19 @@ class ChangeSet extends ChangeDesc {
|
|
|
407
1061
|
}
|
|
408
1062
|
else {
|
|
409
1063
|
while (inserted.length < i)
|
|
410
|
-
inserted.push(
|
|
411
|
-
inserted[i] =
|
|
1064
|
+
inserted.push(Text.empty);
|
|
1065
|
+
inserted[i] = Text.of(part.slice(1));
|
|
412
1066
|
sections.push(part[0], inserted[i].length);
|
|
413
1067
|
}
|
|
414
1068
|
}
|
|
415
1069
|
return new ChangeSet(sections, inserted);
|
|
416
1070
|
}
|
|
1071
|
+
/**
|
|
1072
|
+
@internal
|
|
1073
|
+
*/
|
|
1074
|
+
static createSet(sections, inserted) {
|
|
1075
|
+
return new ChangeSet(sections, inserted);
|
|
1076
|
+
}
|
|
417
1077
|
}
|
|
418
1078
|
function addSection(sections, len, ins, forceJoin = false) {
|
|
419
1079
|
if (len == 0 && ins <= 0)
|
|
@@ -439,7 +1099,7 @@ function addInsert(values, sections, value) {
|
|
|
439
1099
|
}
|
|
440
1100
|
else {
|
|
441
1101
|
while (values.length < index)
|
|
442
|
-
values.push(
|
|
1102
|
+
values.push(Text.empty);
|
|
443
1103
|
values.push(value);
|
|
444
1104
|
}
|
|
445
1105
|
}
|
|
@@ -452,18 +1112,18 @@ function iterChanges(desc, f, individual) {
|
|
|
452
1112
|
posB += len;
|
|
453
1113
|
}
|
|
454
1114
|
else {
|
|
455
|
-
let endA = posA, endB = posB, text
|
|
1115
|
+
let endA = posA, endB = posB, text = Text.empty;
|
|
456
1116
|
for (;;) {
|
|
457
1117
|
endA += len;
|
|
458
1118
|
endB += ins;
|
|
459
1119
|
if (ins && inserted)
|
|
460
|
-
text
|
|
1120
|
+
text = text.append(inserted[(i - 2) >> 1]);
|
|
461
1121
|
if (individual || i == desc.sections.length || desc.sections[i + 1] < 0)
|
|
462
1122
|
break;
|
|
463
1123
|
len = desc.sections[i++];
|
|
464
1124
|
ins = desc.sections[i++];
|
|
465
1125
|
}
|
|
466
|
-
f(posA, endA, posB, endB, text
|
|
1126
|
+
f(posA, endA, posB, endB, text);
|
|
467
1127
|
posA = endA;
|
|
468
1128
|
posB = endB;
|
|
469
1129
|
}
|
|
@@ -517,7 +1177,7 @@ function mapSet(setA, setB, before, mkSet = false) {
|
|
|
517
1177
|
a.next();
|
|
518
1178
|
}
|
|
519
1179
|
else if (a.done && b.done) {
|
|
520
|
-
return insert ?
|
|
1180
|
+
return insert ? ChangeSet.createSet(sections, insert) : ChangeDesc.create(sections);
|
|
521
1181
|
}
|
|
522
1182
|
else {
|
|
523
1183
|
throw new Error("Mismatched change set lengths");
|
|
@@ -530,7 +1190,7 @@ function composeSets(setA, setB, mkSet = false) {
|
|
|
530
1190
|
let a = new SectionIter(setA), b = new SectionIter(setB);
|
|
531
1191
|
for (let open = false;;) {
|
|
532
1192
|
if (a.done && b.done) {
|
|
533
|
-
return insert ?
|
|
1193
|
+
return insert ? ChangeSet.createSet(sections, insert) : ChangeDesc.create(sections);
|
|
534
1194
|
}
|
|
535
1195
|
else if (a.ins == 0) { // Deletion in A
|
|
536
1196
|
addSection(sections, a.len, 0, open);
|
|
@@ -591,11 +1251,11 @@ class SectionIter {
|
|
|
591
1251
|
get len2() { return this.ins < 0 ? this.len : this.ins; }
|
|
592
1252
|
get text() {
|
|
593
1253
|
let { inserted } = this.set, index = (this.i - 2) >> 1;
|
|
594
|
-
return index >= inserted.length ?
|
|
1254
|
+
return index >= inserted.length ? Text.empty : inserted[index];
|
|
595
1255
|
}
|
|
596
1256
|
textBit(len) {
|
|
597
1257
|
let { inserted } = this.set, index = (this.i - 2) >> 1;
|
|
598
|
-
return index >= inserted.length && !len ?
|
|
1258
|
+
return index >= inserted.length && !len ? Text.empty
|
|
599
1259
|
: inserted[index].slice(this.off, len == null ? undefined : this.off + len);
|
|
600
1260
|
}
|
|
601
1261
|
forward(len) {
|
|
@@ -625,9 +1285,6 @@ is enabled, a [selection](https://codemirror.net/6/docs/ref/#state.EditorSelecti
|
|
|
625
1285
|
multiple ranges. By default, selections hold exactly one range.
|
|
626
1286
|
*/
|
|
627
1287
|
class SelectionRange {
|
|
628
|
-
/**
|
|
629
|
-
@internal
|
|
630
|
-
*/
|
|
631
1288
|
constructor(
|
|
632
1289
|
/**
|
|
633
1290
|
The lower boundary of the range.
|
|
@@ -685,7 +1342,14 @@ class SelectionRange {
|
|
|
685
1342
|
updated document.
|
|
686
1343
|
*/
|
|
687
1344
|
map(change, assoc = -1) {
|
|
688
|
-
let from
|
|
1345
|
+
let from, to;
|
|
1346
|
+
if (this.empty) {
|
|
1347
|
+
from = to = change.mapPos(this.from, assoc);
|
|
1348
|
+
}
|
|
1349
|
+
else {
|
|
1350
|
+
from = change.mapPos(this.from, 1);
|
|
1351
|
+
to = change.mapPos(this.to, -1);
|
|
1352
|
+
}
|
|
689
1353
|
return from == this.from && to == this.to ? this : new SelectionRange(from, to, this.flags);
|
|
690
1354
|
}
|
|
691
1355
|
/**
|
|
@@ -716,14 +1380,17 @@ class SelectionRange {
|
|
|
716
1380
|
throw new RangeError("Invalid JSON representation for SelectionRange");
|
|
717
1381
|
return EditorSelection.range(json.anchor, json.head);
|
|
718
1382
|
}
|
|
1383
|
+
/**
|
|
1384
|
+
@internal
|
|
1385
|
+
*/
|
|
1386
|
+
static create(from, to, flags) {
|
|
1387
|
+
return new SelectionRange(from, to, flags);
|
|
1388
|
+
}
|
|
719
1389
|
}
|
|
720
1390
|
/**
|
|
721
1391
|
An editor selection holds one or more selection ranges.
|
|
722
1392
|
*/
|
|
723
1393
|
class EditorSelection {
|
|
724
|
-
/**
|
|
725
|
-
@internal
|
|
726
|
-
*/
|
|
727
1394
|
constructor(
|
|
728
1395
|
/**
|
|
729
1396
|
The ranges in the selection, sorted by position. Ranges cannot
|
|
@@ -734,7 +1401,7 @@ class EditorSelection {
|
|
|
734
1401
|
The index of the _main_ range in the selection (which is
|
|
735
1402
|
usually the range that was added last).
|
|
736
1403
|
*/
|
|
737
|
-
mainIndex
|
|
1404
|
+
mainIndex) {
|
|
738
1405
|
this.ranges = ranges;
|
|
739
1406
|
this.mainIndex = mainIndex;
|
|
740
1407
|
}
|
|
@@ -770,7 +1437,7 @@ class EditorSelection {
|
|
|
770
1437
|
holding only the main range from this selection.
|
|
771
1438
|
*/
|
|
772
1439
|
asSingle() {
|
|
773
|
-
return this.ranges.length == 1 ? this : new EditorSelection([this.main]);
|
|
1440
|
+
return this.ranges.length == 1 ? this : new EditorSelection([this.main], 0);
|
|
774
1441
|
}
|
|
775
1442
|
/**
|
|
776
1443
|
Extend this selection with an extra range.
|
|
@@ -818,7 +1485,7 @@ class EditorSelection {
|
|
|
818
1485
|
for (let pos = 0, i = 0; i < ranges.length; i++) {
|
|
819
1486
|
let range = ranges[i];
|
|
820
1487
|
if (range.empty ? range.from <= pos : range.from < pos)
|
|
821
|
-
return normalized(ranges.slice(), mainIndex);
|
|
1488
|
+
return EditorSelection.normalized(ranges.slice(), mainIndex);
|
|
822
1489
|
pos = range.to;
|
|
823
1490
|
}
|
|
824
1491
|
return new EditorSelection(ranges, mainIndex);
|
|
@@ -828,7 +1495,7 @@ class EditorSelection {
|
|
|
828
1495
|
safely ignore the optional arguments in most situations.
|
|
829
1496
|
*/
|
|
830
1497
|
static cursor(pos, assoc = 0, bidiLevel, goalColumn) {
|
|
831
|
-
return
|
|
1498
|
+
return SelectionRange.create(pos, pos, (assoc == 0 ? 0 : assoc < 0 ? 4 /* AssocBefore */ : 8 /* AssocAfter */) |
|
|
832
1499
|
(bidiLevel == null ? 3 : Math.min(2, bidiLevel)) |
|
|
833
1500
|
((goalColumn !== null && goalColumn !== void 0 ? goalColumn : 33554431 /* NoGoalColumn */) << 5 /* GoalColumnOffset */));
|
|
834
1501
|
}
|
|
@@ -837,24 +1504,27 @@ class EditorSelection {
|
|
|
837
1504
|
*/
|
|
838
1505
|
static range(anchor, head, goalColumn) {
|
|
839
1506
|
let goal = (goalColumn !== null && goalColumn !== void 0 ? goalColumn : 33554431 /* NoGoalColumn */) << 5 /* GoalColumnOffset */;
|
|
840
|
-
return head < anchor ?
|
|
841
|
-
:
|
|
1507
|
+
return head < anchor ? SelectionRange.create(head, anchor, 16 /* Inverted */ | goal | 8 /* AssocAfter */)
|
|
1508
|
+
: SelectionRange.create(anchor, head, goal | (head > anchor ? 4 /* AssocBefore */ : 0));
|
|
842
1509
|
}
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
ranges
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
let
|
|
852
|
-
if (
|
|
853
|
-
|
|
854
|
-
|
|
1510
|
+
/**
|
|
1511
|
+
@internal
|
|
1512
|
+
*/
|
|
1513
|
+
static normalized(ranges, mainIndex = 0) {
|
|
1514
|
+
let main = ranges[mainIndex];
|
|
1515
|
+
ranges.sort((a, b) => a.from - b.from);
|
|
1516
|
+
mainIndex = ranges.indexOf(main);
|
|
1517
|
+
for (let i = 1; i < ranges.length; i++) {
|
|
1518
|
+
let range = ranges[i], prev = ranges[i - 1];
|
|
1519
|
+
if (range.empty ? range.from <= prev.to : range.from < prev.to) {
|
|
1520
|
+
let from = prev.from, to = Math.max(range.to, prev.to);
|
|
1521
|
+
if (i <= mainIndex)
|
|
1522
|
+
mainIndex--;
|
|
1523
|
+
ranges.splice(--i, 2, range.anchor > range.head ? EditorSelection.range(to, from) : EditorSelection.range(from, to));
|
|
1524
|
+
}
|
|
855
1525
|
}
|
|
1526
|
+
return new EditorSelection(ranges, mainIndex);
|
|
856
1527
|
}
|
|
857
|
-
return new EditorSelection(ranges, mainIndex);
|
|
858
1528
|
}
|
|
859
1529
|
function checkSelection(selection, docLength) {
|
|
860
1530
|
for (let range of selection.ranges)
|
|
@@ -868,10 +1538,10 @@ A facet is a labeled value that is associated with an editor
|
|
|
868
1538
|
state. It takes inputs from any number of extensions, and combines
|
|
869
1539
|
those into a single output value.
|
|
870
1540
|
|
|
871
|
-
Examples of facets are the [
|
|
872
|
-
|
|
873
|
-
|
|
874
|
-
|
|
1541
|
+
Examples of uses of facets are the [tab
|
|
1542
|
+
size](https://codemirror.net/6/docs/ref/#state.EditorState^tabSize), [editor
|
|
1543
|
+
attributes](https://codemirror.net/6/docs/ref/#view.EditorView^editorAttributes), and [update
|
|
1544
|
+
listeners](https://codemirror.net/6/docs/ref/#view.EditorView^updateListener).
|
|
875
1545
|
*/
|
|
876
1546
|
class Facet {
|
|
877
1547
|
constructor(
|
|
@@ -909,7 +1579,7 @@ class Facet {
|
|
|
909
1579
|
return new Facet(config.combine || ((a) => a), config.compareInput || ((a, b) => a === b), config.compare || (!config.combine ? sameArray : (a, b) => a === b), !!config.static, config.enables);
|
|
910
1580
|
}
|
|
911
1581
|
/**
|
|
912
|
-
Returns an extension that adds the given value
|
|
1582
|
+
Returns an extension that adds the given value to this facet.
|
|
913
1583
|
*/
|
|
914
1584
|
of(value) {
|
|
915
1585
|
return new FacetProvider([], this, 0 /* Static */, value);
|
|
@@ -920,9 +1590,8 @@ class Facet {
|
|
|
920
1590
|
this value depends on, since your function is only called again
|
|
921
1591
|
for a new state when one of those parts changed.
|
|
922
1592
|
|
|
923
|
-
In
|
|
924
|
-
[`
|
|
925
|
-
defining a field instead.
|
|
1593
|
+
In cases where your value depends only on a single field, you'll
|
|
1594
|
+
want to use the [`from`](https://codemirror.net/6/docs/ref/#state.Facet.from) method instead.
|
|
926
1595
|
*/
|
|
927
1596
|
compute(deps, get) {
|
|
928
1597
|
if (this.isStatic)
|
|
@@ -975,8 +1644,7 @@ class FacetProvider {
|
|
|
975
1644
|
return 1 /* Changed */;
|
|
976
1645
|
},
|
|
977
1646
|
update(state, tr) {
|
|
978
|
-
if ((depDoc && tr.docChanged) || (depSel && (tr.docChanged || tr.selection)) ||
|
|
979
|
-
depAddrs.some(addr => (ensureAddr(state, addr) & 1 /* Changed */) > 0)) {
|
|
1647
|
+
if ((depDoc && tr.docChanged) || (depSel && (tr.docChanged || tr.selection)) || ensureAll(state, depAddrs)) {
|
|
980
1648
|
let newVal = getter(state);
|
|
981
1649
|
if (multi ? !compareArray(newVal, state.values[idx], compare) : !compare(newVal, state.values[idx])) {
|
|
982
1650
|
state.values[idx] = newVal;
|
|
@@ -985,12 +1653,15 @@ class FacetProvider {
|
|
|
985
1653
|
}
|
|
986
1654
|
return 0;
|
|
987
1655
|
},
|
|
988
|
-
reconfigure(state, oldState) {
|
|
1656
|
+
reconfigure: (state, oldState) => {
|
|
989
1657
|
let newVal = getter(state);
|
|
990
1658
|
let oldAddr = oldState.config.address[id];
|
|
991
1659
|
if (oldAddr != null) {
|
|
992
1660
|
let oldVal = getAddr(oldState, oldAddr);
|
|
993
|
-
if (
|
|
1661
|
+
if (this.dependencies.every(dep => {
|
|
1662
|
+
return dep instanceof Facet ? oldState.facet(dep) === state.facet(dep) :
|
|
1663
|
+
dep instanceof StateField ? oldState.field(dep, false) == state.field(dep, false) : true;
|
|
1664
|
+
}) || (multi ? compareArray(newVal, oldVal, compare) : compare(newVal, oldVal))) {
|
|
994
1665
|
state.values[idx] = oldVal;
|
|
995
1666
|
return 0;
|
|
996
1667
|
}
|
|
@@ -1009,6 +1680,13 @@ function compareArray(a, b, compare) {
|
|
|
1009
1680
|
return false;
|
|
1010
1681
|
return true;
|
|
1011
1682
|
}
|
|
1683
|
+
function ensureAll(state, addrs) {
|
|
1684
|
+
let changed = false;
|
|
1685
|
+
for (let addr of addrs)
|
|
1686
|
+
if (ensureAddr(state, addr) & 1 /* Changed */)
|
|
1687
|
+
changed = true;
|
|
1688
|
+
return changed;
|
|
1689
|
+
}
|
|
1012
1690
|
function dynamicFacetSlot(addresses, facet, providers) {
|
|
1013
1691
|
let providerAddrs = providers.map(p => addresses[p.id]);
|
|
1014
1692
|
let providerTypes = providers.map(p => p.type);
|
|
@@ -1034,7 +1712,7 @@ function dynamicFacetSlot(addresses, facet, providers) {
|
|
|
1034
1712
|
return 1 /* Changed */;
|
|
1035
1713
|
},
|
|
1036
1714
|
update(state, tr) {
|
|
1037
|
-
if (!
|
|
1715
|
+
if (!ensureAll(state, dynamic))
|
|
1038
1716
|
return 0;
|
|
1039
1717
|
let value = get(state);
|
|
1040
1718
|
if (facet.compare(value, state.values[idx]))
|
|
@@ -1043,7 +1721,7 @@ function dynamicFacetSlot(addresses, facet, providers) {
|
|
|
1043
1721
|
return 1 /* Changed */;
|
|
1044
1722
|
},
|
|
1045
1723
|
reconfigure(state, oldState) {
|
|
1046
|
-
let depChanged =
|
|
1724
|
+
let depChanged = ensureAll(state, providerAddrs);
|
|
1047
1725
|
let oldProviders = oldState.config.facets[facet.id], oldValue = oldState.facet(facet);
|
|
1048
1726
|
if (oldProviders && !depChanged && sameArray(providers, oldProviders)) {
|
|
1049
1727
|
state.values[idx] = oldValue;
|
|
@@ -1156,42 +1834,29 @@ precedence and then by order within each precedence.
|
|
|
1156
1834
|
*/
|
|
1157
1835
|
const Prec = {
|
|
1158
1836
|
/**
|
|
1159
|
-
The
|
|
1160
|
-
near the
|
|
1161
|
-
*/
|
|
1162
|
-
lowest: prec(Prec_.lowest),
|
|
1163
|
-
/**
|
|
1164
|
-
A lower-than-default precedence, for extensions.
|
|
1165
|
-
*/
|
|
1166
|
-
low: prec(Prec_.low),
|
|
1167
|
-
/**
|
|
1168
|
-
The default precedence, which is also used for extensions
|
|
1169
|
-
without an explicit precedence.
|
|
1837
|
+
The highest precedence level, for extensions that should end up
|
|
1838
|
+
near the start of the precedence ordering.
|
|
1170
1839
|
*/
|
|
1171
|
-
|
|
1840
|
+
highest: prec(Prec_.highest),
|
|
1172
1841
|
/**
|
|
1173
1842
|
A higher-than-default precedence, for extensions that should
|
|
1174
1843
|
come before those with default precedence.
|
|
1175
1844
|
*/
|
|
1176
1845
|
high: prec(Prec_.high),
|
|
1177
1846
|
/**
|
|
1178
|
-
The
|
|
1179
|
-
|
|
1180
|
-
*/
|
|
1181
|
-
highest: prec(Prec_.highest),
|
|
1182
|
-
// FIXME Drop these in some future breaking version
|
|
1183
|
-
/**
|
|
1184
|
-
Backwards-compatible synonym for `Prec.lowest`.
|
|
1847
|
+
The default precedence, which is also used for extensions
|
|
1848
|
+
without an explicit precedence.
|
|
1185
1849
|
*/
|
|
1186
|
-
|
|
1850
|
+
default: prec(Prec_.default),
|
|
1187
1851
|
/**
|
|
1188
|
-
|
|
1852
|
+
A lower-than-default precedence.
|
|
1189
1853
|
*/
|
|
1190
|
-
|
|
1854
|
+
low: prec(Prec_.low),
|
|
1191
1855
|
/**
|
|
1192
|
-
|
|
1856
|
+
The lowest precedence level. Meant for things that should end up
|
|
1857
|
+
near the end of the extension order.
|
|
1193
1858
|
*/
|
|
1194
|
-
|
|
1859
|
+
lowest: prec(Prec_.lowest)
|
|
1195
1860
|
};
|
|
1196
1861
|
class PrecExtension {
|
|
1197
1862
|
constructor(inner, prec) {
|
|
@@ -1305,7 +1970,7 @@ function flatten(extension, compartments, newCompartments) {
|
|
|
1305
1970
|
function inner(ext, prec) {
|
|
1306
1971
|
let known = seen.get(ext);
|
|
1307
1972
|
if (known != null) {
|
|
1308
|
-
if (known
|
|
1973
|
+
if (known <= prec)
|
|
1309
1974
|
return;
|
|
1310
1975
|
let found = result[known].indexOf(ext);
|
|
1311
1976
|
if (found > -1)
|
|
@@ -1520,12 +2185,11 @@ Changes to the editor state are grouped into transactions.
|
|
|
1520
2185
|
Typically, a user action creates a single transaction, which may
|
|
1521
2186
|
contain any number of document changes, may change the selection,
|
|
1522
2187
|
or have other effects. Create a transaction by calling
|
|
1523
|
-
[`EditorState.update`](https://codemirror.net/6/docs/ref/#state.EditorState.update)
|
|
2188
|
+
[`EditorState.update`](https://codemirror.net/6/docs/ref/#state.EditorState.update), or immediately
|
|
2189
|
+
dispatch one by calling
|
|
2190
|
+
[`EditorView.dispatch`](https://codemirror.net/6/docs/ref/#view.EditorView.dispatch).
|
|
1524
2191
|
*/
|
|
1525
2192
|
class Transaction {
|
|
1526
|
-
/**
|
|
1527
|
-
@internal
|
|
1528
|
-
*/
|
|
1529
2193
|
constructor(
|
|
1530
2194
|
/**
|
|
1531
2195
|
The state from which the transaction starts.
|
|
@@ -1573,6 +2237,12 @@ class Transaction {
|
|
|
1573
2237
|
this.annotations = annotations.concat(Transaction.time.of(Date.now()));
|
|
1574
2238
|
}
|
|
1575
2239
|
/**
|
|
2240
|
+
@internal
|
|
2241
|
+
*/
|
|
2242
|
+
static create(startState, changes, selection, effects, annotations, scrollIntoView) {
|
|
2243
|
+
return new Transaction(startState, changes, selection, effects, annotations, scrollIntoView);
|
|
2244
|
+
}
|
|
2245
|
+
/**
|
|
1576
2246
|
The new document produced by the transaction. Contrary to
|
|
1577
2247
|
[`.state`](https://codemirror.net/6/docs/ref/#state.Transaction.state)`.doc`, accessing this won't
|
|
1578
2248
|
force the entire new state to be computed right away, so it is
|
|
@@ -1594,7 +2264,7 @@ class Transaction {
|
|
|
1594
2264
|
}
|
|
1595
2265
|
/**
|
|
1596
2266
|
The new state created by the transaction. Computed on demand
|
|
1597
|
-
(but retained for subsequent access), so
|
|
2267
|
+
(but retained for subsequent access), so it is recommended not to
|
|
1598
2268
|
access it in [transaction
|
|
1599
2269
|
filters](https://codemirror.net/6/docs/ref/#state.EditorState^transactionFilter) when possible.
|
|
1600
2270
|
*/
|
|
@@ -1636,7 +2306,8 @@ class Transaction {
|
|
|
1636
2306
|
}
|
|
1637
2307
|
}
|
|
1638
2308
|
/**
|
|
1639
|
-
Annotation used to store transaction timestamps.
|
|
2309
|
+
Annotation used to store transaction timestamps. Automatically
|
|
2310
|
+
added to every transaction, holding `Date.now()`.
|
|
1640
2311
|
*/
|
|
1641
2312
|
Transaction.time = Annotation.define();
|
|
1642
2313
|
/**
|
|
@@ -1742,7 +2413,7 @@ function resolveTransaction(state, specs, filter) {
|
|
|
1742
2413
|
let seq = !!specs[i].sequential;
|
|
1743
2414
|
s = mergeTransaction(s, resolveTransactionInner(state, specs[i], seq ? s.changes.newLength : state.doc.length), seq);
|
|
1744
2415
|
}
|
|
1745
|
-
let tr =
|
|
2416
|
+
let tr = Transaction.create(state, s.changes, s.selection, s.effects, s.annotations, s.scrollIntoView);
|
|
1746
2417
|
return extendTransaction(filter ? filterTransaction(tr) : tr);
|
|
1747
2418
|
}
|
|
1748
2419
|
// Finish a transaction by applying filters if necessary.
|
|
@@ -1770,7 +2441,7 @@ function filterTransaction(tr) {
|
|
|
1770
2441
|
changes = filtered.changes;
|
|
1771
2442
|
back = filtered.filtered.invertedDesc;
|
|
1772
2443
|
}
|
|
1773
|
-
tr =
|
|
2444
|
+
tr = Transaction.create(state, changes, tr.selection && tr.selection.map(back), StateEffect.mapEffects(tr.effects, back), tr.annotations, tr.scrollIntoView);
|
|
1774
2445
|
}
|
|
1775
2446
|
// Transaction filters
|
|
1776
2447
|
let filters = state.facet(transactionFilter);
|
|
@@ -1792,7 +2463,7 @@ function extendTransaction(tr) {
|
|
|
1792
2463
|
if (extension && Object.keys(extension).length)
|
|
1793
2464
|
spec = mergeTransaction(tr, resolveTransactionInner(state, extension, tr.changes.newLength), true);
|
|
1794
2465
|
}
|
|
1795
|
-
return spec == tr ? tr :
|
|
2466
|
+
return spec == tr ? tr : Transaction.create(state, tr.changes, tr.selection, spec.effects, spec.annotations, spec.scrollIntoView);
|
|
1796
2467
|
}
|
|
1797
2468
|
const none = [];
|
|
1798
2469
|
function asArray(value) {
|
|
@@ -1858,9 +2529,6 @@ As such, _never_ mutate properties of a state directly. That'll
|
|
|
1858
2529
|
just break things.
|
|
1859
2530
|
*/
|
|
1860
2531
|
class EditorState {
|
|
1861
|
-
/**
|
|
1862
|
-
@internal
|
|
1863
|
-
*/
|
|
1864
2532
|
constructor(
|
|
1865
2533
|
/**
|
|
1866
2534
|
@internal
|
|
@@ -2009,10 +2677,10 @@ class EditorState {
|
|
|
2009
2677
|
/**
|
|
2010
2678
|
Using the state's [line
|
|
2011
2679
|
separator](https://codemirror.net/6/docs/ref/#state.EditorState^lineSeparator), create a
|
|
2012
|
-
[`Text`](https://codemirror.net/6/docs/ref/#
|
|
2680
|
+
[`Text`](https://codemirror.net/6/docs/ref/#state.Text) instance from the given string.
|
|
2013
2681
|
*/
|
|
2014
2682
|
toText(string) {
|
|
2015
|
-
return
|
|
2683
|
+
return Text.of(string.split(this.facet(EditorState.lineSeparator) || DefaultSplit));
|
|
2016
2684
|
}
|
|
2017
2685
|
/**
|
|
2018
2686
|
Return the given range of the document as a string.
|
|
@@ -2077,8 +2745,8 @@ class EditorState {
|
|
|
2077
2745
|
*/
|
|
2078
2746
|
static create(config = {}) {
|
|
2079
2747
|
let configuration = Configuration.resolve(config.extensions || [], new Map);
|
|
2080
|
-
let doc = config.doc instanceof
|
|
2081
|
-
:
|
|
2748
|
+
let doc = config.doc instanceof Text ? config.doc
|
|
2749
|
+
: Text.of((config.doc || "").split(configuration.staticFacet(EditorState.lineSeparator) || DefaultSplit));
|
|
2082
2750
|
let selection = !config.selection ? EditorSelection.single(0)
|
|
2083
2751
|
: config.selection instanceof EditorSelection ? config.selection
|
|
2084
2752
|
: EditorSelection.single(config.selection.anchor, config.selection.head);
|
|
@@ -2106,11 +2774,25 @@ class EditorState {
|
|
|
2106
2774
|
Look up a translation for the given phrase (via the
|
|
2107
2775
|
[`phrases`](https://codemirror.net/6/docs/ref/#state.EditorState^phrases) facet), or return the
|
|
2108
2776
|
original string if no translation is found.
|
|
2777
|
+
|
|
2778
|
+
If additional arguments are passed, they will be inserted in
|
|
2779
|
+
place of markers like `$1` (for the first value) and `$2`, etc.
|
|
2780
|
+
A single `$` is equivalent to `$1`, and `$$` will produce a
|
|
2781
|
+
literal dollar sign.
|
|
2109
2782
|
*/
|
|
2110
|
-
phrase(phrase) {
|
|
2783
|
+
phrase(phrase, ...insert) {
|
|
2111
2784
|
for (let map of this.facet(EditorState.phrases))
|
|
2112
|
-
if (Object.prototype.hasOwnProperty.call(map, phrase))
|
|
2113
|
-
|
|
2785
|
+
if (Object.prototype.hasOwnProperty.call(map, phrase)) {
|
|
2786
|
+
phrase = map[phrase];
|
|
2787
|
+
break;
|
|
2788
|
+
}
|
|
2789
|
+
if (insert.length)
|
|
2790
|
+
phrase = phrase.replace(/\$(\$|\d*)/g, (m, i) => {
|
|
2791
|
+
if (i == "$")
|
|
2792
|
+
return "$";
|
|
2793
|
+
let n = +(i || 1);
|
|
2794
|
+
return n > insert.length ? m : insert[n - 1];
|
|
2795
|
+
});
|
|
2114
2796
|
return phrase;
|
|
2115
2797
|
}
|
|
2116
2798
|
/**
|
|
@@ -2129,7 +2811,7 @@ class EditorState {
|
|
|
2129
2811
|
}
|
|
2130
2812
|
/**
|
|
2131
2813
|
Return a function that can categorize strings (expected to
|
|
2132
|
-
represent a single [grapheme cluster](https://codemirror.net/6/docs/ref/#
|
|
2814
|
+
represent a single [grapheme cluster](https://codemirror.net/6/docs/ref/#state.findClusterBreak))
|
|
2133
2815
|
into one of:
|
|
2134
2816
|
|
|
2135
2817
|
- Word (contains an alphanumeric character or a character
|
|
@@ -2148,18 +2830,18 @@ class EditorState {
|
|
|
2148
2830
|
this returns null.
|
|
2149
2831
|
*/
|
|
2150
2832
|
wordAt(pos) {
|
|
2151
|
-
let { text
|
|
2833
|
+
let { text, from, length } = this.doc.lineAt(pos);
|
|
2152
2834
|
let cat = this.charCategorizer(pos);
|
|
2153
2835
|
let start = pos - from, end = pos - from;
|
|
2154
2836
|
while (start > 0) {
|
|
2155
|
-
let prev =
|
|
2156
|
-
if (cat(text
|
|
2837
|
+
let prev = findClusterBreak(text, start, false);
|
|
2838
|
+
if (cat(text.slice(prev, start)) != exports.CharCategory.Word)
|
|
2157
2839
|
break;
|
|
2158
2840
|
start = prev;
|
|
2159
2841
|
}
|
|
2160
2842
|
while (end < length) {
|
|
2161
|
-
let next =
|
|
2162
|
-
if (cat(text
|
|
2843
|
+
let next = findClusterBreak(text, end);
|
|
2844
|
+
if (cat(text.slice(end, next)) != exports.CharCategory.Word)
|
|
2163
2845
|
break;
|
|
2164
2846
|
end = next;
|
|
2165
2847
|
}
|
|
@@ -2213,8 +2895,13 @@ Registers translation phrases. The
|
|
|
2213
2895
|
all objects registered with this facet to find translations for
|
|
2214
2896
|
its argument.
|
|
2215
2897
|
*/
|
|
2216
|
-
EditorState.phrases = Facet.define(
|
|
2217
|
-
|
|
2898
|
+
EditorState.phrases = Facet.define({
|
|
2899
|
+
compare(a, b) {
|
|
2900
|
+
let kA = Object.keys(a), kB = Object.keys(b);
|
|
2901
|
+
return kA.length == kB.length && kA.every(k => a[k] == b[k]);
|
|
2902
|
+
}
|
|
2903
|
+
});
|
|
2904
|
+
/**
|
|
2218
2905
|
A facet used to register [language
|
|
2219
2906
|
data](https://codemirror.net/6/docs/ref/#state.EditorState.languageDataAt) providers.
|
|
2220
2907
|
*/
|
|
@@ -2229,7 +2916,7 @@ Such a function can return `true` to indicate that it doesn't
|
|
|
2229
2916
|
want to do anything, `false` to completely stop the changes in
|
|
2230
2917
|
the transaction, or a set of ranges in which changes should be
|
|
2231
2918
|
suppressed. Such ranges are represented as an array of numbers,
|
|
2232
|
-
with each pair of two
|
|
2919
|
+
with each pair of two numbers indicating the start and end of a
|
|
2233
2920
|
range. So for example `[10, 20, 100, 110]` suppresses changes
|
|
2234
2921
|
between 10 and 20, and between 100 and 110.
|
|
2235
2922
|
*/
|
|
@@ -2260,19 +2947,22 @@ This is a more limited form of
|
|
|
2260
2947
|
which can only add
|
|
2261
2948
|
[annotations](https://codemirror.net/6/docs/ref/#state.TransactionSpec.annotations) and
|
|
2262
2949
|
[effects](https://codemirror.net/6/docs/ref/#state.TransactionSpec.effects). _But_, this type
|
|
2263
|
-
of filter runs even the transaction has disabled regular
|
|
2950
|
+
of filter runs even if the transaction has disabled regular
|
|
2264
2951
|
[filtering](https://codemirror.net/6/docs/ref/#state.TransactionSpec.filter), making it suitable
|
|
2265
2952
|
for effects that don't need to touch the changes or selection,
|
|
2266
2953
|
but do want to process every transaction.
|
|
2267
2954
|
|
|
2268
|
-
Extenders run _after_ filters, when both are
|
|
2955
|
+
Extenders run _after_ filters, when both are present.
|
|
2269
2956
|
*/
|
|
2270
2957
|
EditorState.transactionExtender = transactionExtender;
|
|
2271
2958
|
Compartment.reconfigure = StateEffect.define();
|
|
2272
2959
|
|
|
2273
2960
|
/**
|
|
2274
2961
|
Utility function for combining behaviors to fill in a config
|
|
2275
|
-
object from an array of provided configs.
|
|
2962
|
+
object from an array of provided configs. `defaults` should hold
|
|
2963
|
+
default values for all optional fields in `Config`.
|
|
2964
|
+
|
|
2965
|
+
The function will, by default, error
|
|
2276
2966
|
when a field gets two values that aren't `===`-equal, but you can
|
|
2277
2967
|
provide combine functions per field to do something else.
|
|
2278
2968
|
*/
|
|
@@ -2296,10 +2986,879 @@ combine = {}) {
|
|
|
2296
2986
|
return result;
|
|
2297
2987
|
}
|
|
2298
2988
|
|
|
2299
|
-
|
|
2300
|
-
|
|
2301
|
-
|
|
2302
|
-
|
|
2989
|
+
/**
|
|
2990
|
+
Each range is associated with a value, which must inherit from
|
|
2991
|
+
this class.
|
|
2992
|
+
*/
|
|
2993
|
+
class RangeValue {
|
|
2994
|
+
/**
|
|
2995
|
+
Compare this value with another value. Used when comparing
|
|
2996
|
+
rangesets. The default implementation compares by identity.
|
|
2997
|
+
Unless you are only creating a fixed number of unique instances
|
|
2998
|
+
of your value type, it is a good idea to implement this
|
|
2999
|
+
properly.
|
|
3000
|
+
*/
|
|
3001
|
+
eq(other) { return this == other; }
|
|
3002
|
+
/**
|
|
3003
|
+
Create a [range](https://codemirror.net/6/docs/ref/#state.Range) with this value.
|
|
3004
|
+
*/
|
|
3005
|
+
range(from, to = from) { return Range.create(from, to, this); }
|
|
3006
|
+
}
|
|
3007
|
+
RangeValue.prototype.startSide = RangeValue.prototype.endSide = 0;
|
|
3008
|
+
RangeValue.prototype.point = false;
|
|
3009
|
+
RangeValue.prototype.mapMode = exports.MapMode.TrackDel;
|
|
3010
|
+
/**
|
|
3011
|
+
A range associates a value with a range of positions.
|
|
3012
|
+
*/
|
|
3013
|
+
class Range {
|
|
3014
|
+
constructor(
|
|
3015
|
+
/**
|
|
3016
|
+
The range's start position.
|
|
3017
|
+
*/
|
|
3018
|
+
from,
|
|
3019
|
+
/**
|
|
3020
|
+
Its end position.
|
|
3021
|
+
*/
|
|
3022
|
+
to,
|
|
3023
|
+
/**
|
|
3024
|
+
The value associated with this range.
|
|
3025
|
+
*/
|
|
3026
|
+
value) {
|
|
3027
|
+
this.from = from;
|
|
3028
|
+
this.to = to;
|
|
3029
|
+
this.value = value;
|
|
3030
|
+
}
|
|
3031
|
+
/**
|
|
3032
|
+
@internal
|
|
3033
|
+
*/
|
|
3034
|
+
static create(from, to, value) {
|
|
3035
|
+
return new Range(from, to, value);
|
|
3036
|
+
}
|
|
3037
|
+
}
|
|
3038
|
+
function cmpRange(a, b) {
|
|
3039
|
+
return a.from - b.from || a.value.startSide - b.value.startSide;
|
|
3040
|
+
}
|
|
3041
|
+
class Chunk {
|
|
3042
|
+
constructor(from, to, value,
|
|
3043
|
+
// Chunks are marked with the largest point that occurs
|
|
3044
|
+
// in them (or -1 for no points), so that scans that are
|
|
3045
|
+
// only interested in points (such as the
|
|
3046
|
+
// heightmap-related logic) can skip range-only chunks.
|
|
3047
|
+
maxPoint) {
|
|
3048
|
+
this.from = from;
|
|
3049
|
+
this.to = to;
|
|
3050
|
+
this.value = value;
|
|
3051
|
+
this.maxPoint = maxPoint;
|
|
3052
|
+
}
|
|
3053
|
+
get length() { return this.to[this.to.length - 1]; }
|
|
3054
|
+
// Find the index of the given position and side. Use the ranges'
|
|
3055
|
+
// `from` pos when `end == false`, `to` when `end == true`.
|
|
3056
|
+
findIndex(pos, side, end, startAt = 0) {
|
|
3057
|
+
let arr = end ? this.to : this.from;
|
|
3058
|
+
for (let lo = startAt, hi = arr.length;;) {
|
|
3059
|
+
if (lo == hi)
|
|
3060
|
+
return lo;
|
|
3061
|
+
let mid = (lo + hi) >> 1;
|
|
3062
|
+
let diff = arr[mid] - pos || (end ? this.value[mid].endSide : this.value[mid].startSide) - side;
|
|
3063
|
+
if (mid == lo)
|
|
3064
|
+
return diff >= 0 ? lo : hi;
|
|
3065
|
+
if (diff >= 0)
|
|
3066
|
+
hi = mid;
|
|
3067
|
+
else
|
|
3068
|
+
lo = mid + 1;
|
|
3069
|
+
}
|
|
3070
|
+
}
|
|
3071
|
+
between(offset, from, to, f) {
|
|
3072
|
+
for (let i = this.findIndex(from, -1000000000 /* Far */, true), e = this.findIndex(to, 1000000000 /* Far */, false, i); i < e; i++)
|
|
3073
|
+
if (f(this.from[i] + offset, this.to[i] + offset, this.value[i]) === false)
|
|
3074
|
+
return false;
|
|
3075
|
+
}
|
|
3076
|
+
map(offset, changes) {
|
|
3077
|
+
let value = [], from = [], to = [], newPos = -1, maxPoint = -1;
|
|
3078
|
+
for (let i = 0; i < this.value.length; i++) {
|
|
3079
|
+
let val = this.value[i], curFrom = this.from[i] + offset, curTo = this.to[i] + offset, newFrom, newTo;
|
|
3080
|
+
if (curFrom == curTo) {
|
|
3081
|
+
let mapped = changes.mapPos(curFrom, val.startSide, val.mapMode);
|
|
3082
|
+
if (mapped == null)
|
|
3083
|
+
continue;
|
|
3084
|
+
newFrom = newTo = mapped;
|
|
3085
|
+
if (val.startSide != val.endSide) {
|
|
3086
|
+
newTo = changes.mapPos(curFrom, val.endSide);
|
|
3087
|
+
if (newTo < newFrom)
|
|
3088
|
+
continue;
|
|
3089
|
+
}
|
|
3090
|
+
}
|
|
3091
|
+
else {
|
|
3092
|
+
newFrom = changes.mapPos(curFrom, val.startSide);
|
|
3093
|
+
newTo = changes.mapPos(curTo, val.endSide);
|
|
3094
|
+
if (newFrom > newTo || newFrom == newTo && val.startSide > 0 && val.endSide <= 0)
|
|
3095
|
+
continue;
|
|
3096
|
+
}
|
|
3097
|
+
if ((newTo - newFrom || val.endSide - val.startSide) < 0)
|
|
3098
|
+
continue;
|
|
3099
|
+
if (newPos < 0)
|
|
3100
|
+
newPos = newFrom;
|
|
3101
|
+
if (val.point)
|
|
3102
|
+
maxPoint = Math.max(maxPoint, newTo - newFrom);
|
|
3103
|
+
value.push(val);
|
|
3104
|
+
from.push(newFrom - newPos);
|
|
3105
|
+
to.push(newTo - newPos);
|
|
3106
|
+
}
|
|
3107
|
+
return { mapped: value.length ? new Chunk(from, to, value, maxPoint) : null, pos: newPos };
|
|
3108
|
+
}
|
|
3109
|
+
}
|
|
3110
|
+
/**
|
|
3111
|
+
A range set stores a collection of [ranges](https://codemirror.net/6/docs/ref/#state.Range) in a
|
|
3112
|
+
way that makes them efficient to [map](https://codemirror.net/6/docs/ref/#state.RangeSet.map) and
|
|
3113
|
+
[update](https://codemirror.net/6/docs/ref/#state.RangeSet.update). This is an immutable data
|
|
3114
|
+
structure.
|
|
3115
|
+
*/
|
|
3116
|
+
class RangeSet {
|
|
3117
|
+
constructor(
|
|
3118
|
+
/**
|
|
3119
|
+
@internal
|
|
3120
|
+
*/
|
|
3121
|
+
chunkPos,
|
|
3122
|
+
/**
|
|
3123
|
+
@internal
|
|
3124
|
+
*/
|
|
3125
|
+
chunk,
|
|
3126
|
+
/**
|
|
3127
|
+
@internal
|
|
3128
|
+
*/
|
|
3129
|
+
nextLayer,
|
|
3130
|
+
/**
|
|
3131
|
+
@internal
|
|
3132
|
+
*/
|
|
3133
|
+
maxPoint) {
|
|
3134
|
+
this.chunkPos = chunkPos;
|
|
3135
|
+
this.chunk = chunk;
|
|
3136
|
+
this.nextLayer = nextLayer;
|
|
3137
|
+
this.maxPoint = maxPoint;
|
|
3138
|
+
}
|
|
3139
|
+
/**
|
|
3140
|
+
@internal
|
|
3141
|
+
*/
|
|
3142
|
+
static create(chunkPos, chunk, nextLayer, maxPoint) {
|
|
3143
|
+
return new RangeSet(chunkPos, chunk, nextLayer, maxPoint);
|
|
3144
|
+
}
|
|
3145
|
+
/**
|
|
3146
|
+
@internal
|
|
3147
|
+
*/
|
|
3148
|
+
get length() {
|
|
3149
|
+
let last = this.chunk.length - 1;
|
|
3150
|
+
return last < 0 ? 0 : Math.max(this.chunkEnd(last), this.nextLayer.length);
|
|
3151
|
+
}
|
|
3152
|
+
/**
|
|
3153
|
+
The number of ranges in the set.
|
|
3154
|
+
*/
|
|
3155
|
+
get size() {
|
|
3156
|
+
if (this.isEmpty)
|
|
3157
|
+
return 0;
|
|
3158
|
+
let size = this.nextLayer.size;
|
|
3159
|
+
for (let chunk of this.chunk)
|
|
3160
|
+
size += chunk.value.length;
|
|
3161
|
+
return size;
|
|
3162
|
+
}
|
|
3163
|
+
/**
|
|
3164
|
+
@internal
|
|
3165
|
+
*/
|
|
3166
|
+
chunkEnd(index) {
|
|
3167
|
+
return this.chunkPos[index] + this.chunk[index].length;
|
|
3168
|
+
}
|
|
3169
|
+
/**
|
|
3170
|
+
Update the range set, optionally adding new ranges or filtering
|
|
3171
|
+
out existing ones.
|
|
3172
|
+
|
|
3173
|
+
(Note: The type parameter is just there as a kludge to work
|
|
3174
|
+
around TypeScript variance issues that prevented `RangeSet<X>`
|
|
3175
|
+
from being a subtype of `RangeSet<Y>` when `X` is a subtype of
|
|
3176
|
+
`Y`.)
|
|
3177
|
+
*/
|
|
3178
|
+
update(updateSpec) {
|
|
3179
|
+
let { add = [], sort = false, filterFrom = 0, filterTo = this.length } = updateSpec;
|
|
3180
|
+
let filter = updateSpec.filter;
|
|
3181
|
+
if (add.length == 0 && !filter)
|
|
3182
|
+
return this;
|
|
3183
|
+
if (sort)
|
|
3184
|
+
add = add.slice().sort(cmpRange);
|
|
3185
|
+
if (this.isEmpty)
|
|
3186
|
+
return add.length ? RangeSet.of(add) : this;
|
|
3187
|
+
let cur = new LayerCursor(this, null, -1).goto(0), i = 0, spill = [];
|
|
3188
|
+
let builder = new RangeSetBuilder();
|
|
3189
|
+
while (cur.value || i < add.length) {
|
|
3190
|
+
if (i < add.length && (cur.from - add[i].from || cur.startSide - add[i].value.startSide) >= 0) {
|
|
3191
|
+
let range = add[i++];
|
|
3192
|
+
if (!builder.addInner(range.from, range.to, range.value))
|
|
3193
|
+
spill.push(range);
|
|
3194
|
+
}
|
|
3195
|
+
else if (cur.rangeIndex == 1 && cur.chunkIndex < this.chunk.length &&
|
|
3196
|
+
(i == add.length || this.chunkEnd(cur.chunkIndex) < add[i].from) &&
|
|
3197
|
+
(!filter || filterFrom > this.chunkEnd(cur.chunkIndex) || filterTo < this.chunkPos[cur.chunkIndex]) &&
|
|
3198
|
+
builder.addChunk(this.chunkPos[cur.chunkIndex], this.chunk[cur.chunkIndex])) {
|
|
3199
|
+
cur.nextChunk();
|
|
3200
|
+
}
|
|
3201
|
+
else {
|
|
3202
|
+
if (!filter || filterFrom > cur.to || filterTo < cur.from || filter(cur.from, cur.to, cur.value)) {
|
|
3203
|
+
if (!builder.addInner(cur.from, cur.to, cur.value))
|
|
3204
|
+
spill.push(Range.create(cur.from, cur.to, cur.value));
|
|
3205
|
+
}
|
|
3206
|
+
cur.next();
|
|
3207
|
+
}
|
|
3208
|
+
}
|
|
3209
|
+
return builder.finishInner(this.nextLayer.isEmpty && !spill.length ? RangeSet.empty
|
|
3210
|
+
: this.nextLayer.update({ add: spill, filter, filterFrom, filterTo }));
|
|
3211
|
+
}
|
|
3212
|
+
/**
|
|
3213
|
+
Map this range set through a set of changes, return the new set.
|
|
3214
|
+
*/
|
|
3215
|
+
map(changes) {
|
|
3216
|
+
if (changes.empty || this.isEmpty)
|
|
3217
|
+
return this;
|
|
3218
|
+
let chunks = [], chunkPos = [], maxPoint = -1;
|
|
3219
|
+
for (let i = 0; i < this.chunk.length; i++) {
|
|
3220
|
+
let start = this.chunkPos[i], chunk = this.chunk[i];
|
|
3221
|
+
let touch = changes.touchesRange(start, start + chunk.length);
|
|
3222
|
+
if (touch === false) {
|
|
3223
|
+
maxPoint = Math.max(maxPoint, chunk.maxPoint);
|
|
3224
|
+
chunks.push(chunk);
|
|
3225
|
+
chunkPos.push(changes.mapPos(start));
|
|
3226
|
+
}
|
|
3227
|
+
else if (touch === true) {
|
|
3228
|
+
let { mapped, pos } = chunk.map(start, changes);
|
|
3229
|
+
if (mapped) {
|
|
3230
|
+
maxPoint = Math.max(maxPoint, mapped.maxPoint);
|
|
3231
|
+
chunks.push(mapped);
|
|
3232
|
+
chunkPos.push(pos);
|
|
3233
|
+
}
|
|
3234
|
+
}
|
|
3235
|
+
}
|
|
3236
|
+
let next = this.nextLayer.map(changes);
|
|
3237
|
+
return chunks.length == 0 ? next : new RangeSet(chunkPos, chunks, next || RangeSet.empty, maxPoint);
|
|
3238
|
+
}
|
|
3239
|
+
/**
|
|
3240
|
+
Iterate over the ranges that touch the region `from` to `to`,
|
|
3241
|
+
calling `f` for each. There is no guarantee that the ranges will
|
|
3242
|
+
be reported in any specific order. When the callback returns
|
|
3243
|
+
`false`, iteration stops.
|
|
3244
|
+
*/
|
|
3245
|
+
between(from, to, f) {
|
|
3246
|
+
if (this.isEmpty)
|
|
3247
|
+
return;
|
|
3248
|
+
for (let i = 0; i < this.chunk.length; i++) {
|
|
3249
|
+
let start = this.chunkPos[i], chunk = this.chunk[i];
|
|
3250
|
+
if (to >= start && from <= start + chunk.length &&
|
|
3251
|
+
chunk.between(start, from - start, to - start, f) === false)
|
|
3252
|
+
return;
|
|
3253
|
+
}
|
|
3254
|
+
this.nextLayer.between(from, to, f);
|
|
3255
|
+
}
|
|
3256
|
+
/**
|
|
3257
|
+
Iterate over the ranges in this set, in order, including all
|
|
3258
|
+
ranges that end at or after `from`.
|
|
3259
|
+
*/
|
|
3260
|
+
iter(from = 0) {
|
|
3261
|
+
return HeapCursor.from([this]).goto(from);
|
|
3262
|
+
}
|
|
3263
|
+
/**
|
|
3264
|
+
@internal
|
|
3265
|
+
*/
|
|
3266
|
+
get isEmpty() { return this.nextLayer == this; }
|
|
3267
|
+
/**
|
|
3268
|
+
Iterate over the ranges in a collection of sets, in order,
|
|
3269
|
+
starting from `from`.
|
|
3270
|
+
*/
|
|
3271
|
+
static iter(sets, from = 0) {
|
|
3272
|
+
return HeapCursor.from(sets).goto(from);
|
|
3273
|
+
}
|
|
3274
|
+
/**
|
|
3275
|
+
Iterate over two groups of sets, calling methods on `comparator`
|
|
3276
|
+
to notify it of possible differences.
|
|
3277
|
+
*/
|
|
3278
|
+
static compare(oldSets, newSets,
|
|
3279
|
+
/**
|
|
3280
|
+
This indicates how the underlying data changed between these
|
|
3281
|
+
ranges, and is needed to synchronize the iteration. `from` and
|
|
3282
|
+
`to` are coordinates in the _new_ space, after these changes.
|
|
3283
|
+
*/
|
|
3284
|
+
textDiff, comparator,
|
|
3285
|
+
/**
|
|
3286
|
+
Can be used to ignore all non-point ranges, and points below
|
|
3287
|
+
the given size. When -1, all ranges are compared.
|
|
3288
|
+
*/
|
|
3289
|
+
minPointSize = -1) {
|
|
3290
|
+
let a = oldSets.filter(set => set.maxPoint > 0 || !set.isEmpty && set.maxPoint >= minPointSize);
|
|
3291
|
+
let b = newSets.filter(set => set.maxPoint > 0 || !set.isEmpty && set.maxPoint >= minPointSize);
|
|
3292
|
+
let sharedChunks = findSharedChunks(a, b, textDiff);
|
|
3293
|
+
let sideA = new SpanCursor(a, sharedChunks, minPointSize);
|
|
3294
|
+
let sideB = new SpanCursor(b, sharedChunks, minPointSize);
|
|
3295
|
+
textDiff.iterGaps((fromA, fromB, length) => compare(sideA, fromA, sideB, fromB, length, comparator));
|
|
3296
|
+
if (textDiff.empty && textDiff.length == 0)
|
|
3297
|
+
compare(sideA, 0, sideB, 0, 0, comparator);
|
|
3298
|
+
}
|
|
3299
|
+
/**
|
|
3300
|
+
Compare the contents of two groups of range sets, returning true
|
|
3301
|
+
if they are equivalent in the given range.
|
|
3302
|
+
*/
|
|
3303
|
+
static eq(oldSets, newSets, from = 0, to) {
|
|
3304
|
+
if (to == null)
|
|
3305
|
+
to = 1000000000 /* Far */;
|
|
3306
|
+
let a = oldSets.filter(set => !set.isEmpty && newSets.indexOf(set) < 0);
|
|
3307
|
+
let b = newSets.filter(set => !set.isEmpty && oldSets.indexOf(set) < 0);
|
|
3308
|
+
if (a.length != b.length)
|
|
3309
|
+
return false;
|
|
3310
|
+
if (!a.length)
|
|
3311
|
+
return true;
|
|
3312
|
+
let sharedChunks = findSharedChunks(a, b);
|
|
3313
|
+
let sideA = new SpanCursor(a, sharedChunks, 0).goto(from), sideB = new SpanCursor(b, sharedChunks, 0).goto(from);
|
|
3314
|
+
for (;;) {
|
|
3315
|
+
if (sideA.to != sideB.to ||
|
|
3316
|
+
!sameValues(sideA.active, sideB.active) ||
|
|
3317
|
+
sideA.point && (!sideB.point || !sideA.point.eq(sideB.point)))
|
|
3318
|
+
return false;
|
|
3319
|
+
if (sideA.to > to)
|
|
3320
|
+
return true;
|
|
3321
|
+
sideA.next();
|
|
3322
|
+
sideB.next();
|
|
3323
|
+
}
|
|
3324
|
+
}
|
|
3325
|
+
/**
|
|
3326
|
+
Iterate over a group of range sets at the same time, notifying
|
|
3327
|
+
the iterator about the ranges covering every given piece of
|
|
3328
|
+
content. Returns the open count (see
|
|
3329
|
+
[`SpanIterator.span`](https://codemirror.net/6/docs/ref/#state.SpanIterator.span)) at the end
|
|
3330
|
+
of the iteration.
|
|
3331
|
+
*/
|
|
3332
|
+
static spans(sets, from, to, iterator,
|
|
3333
|
+
/**
|
|
3334
|
+
When given and greater than -1, only points of at least this
|
|
3335
|
+
size are taken into account.
|
|
3336
|
+
*/
|
|
3337
|
+
minPointSize = -1) {
|
|
3338
|
+
let cursor = new SpanCursor(sets, null, minPointSize).goto(from), pos = from;
|
|
3339
|
+
let open = cursor.openStart;
|
|
3340
|
+
for (;;) {
|
|
3341
|
+
let curTo = Math.min(cursor.to, to);
|
|
3342
|
+
if (cursor.point) {
|
|
3343
|
+
iterator.point(pos, curTo, cursor.point, cursor.activeForPoint(cursor.to), open, cursor.pointRank);
|
|
3344
|
+
open = cursor.openEnd(curTo) + (cursor.to > curTo ? 1 : 0);
|
|
3345
|
+
}
|
|
3346
|
+
else if (curTo > pos) {
|
|
3347
|
+
iterator.span(pos, curTo, cursor.active, open);
|
|
3348
|
+
open = cursor.openEnd(curTo);
|
|
3349
|
+
}
|
|
3350
|
+
if (cursor.to > to)
|
|
3351
|
+
break;
|
|
3352
|
+
pos = cursor.to;
|
|
3353
|
+
cursor.next();
|
|
3354
|
+
}
|
|
3355
|
+
return open;
|
|
3356
|
+
}
|
|
3357
|
+
/**
|
|
3358
|
+
Create a range set for the given range or array of ranges. By
|
|
3359
|
+
default, this expects the ranges to be _sorted_ (by start
|
|
3360
|
+
position and, if two start at the same position,
|
|
3361
|
+
`value.startSide`). You can pass `true` as second argument to
|
|
3362
|
+
cause the method to sort them.
|
|
3363
|
+
*/
|
|
3364
|
+
static of(ranges, sort = false) {
|
|
3365
|
+
let build = new RangeSetBuilder();
|
|
3366
|
+
for (let range of ranges instanceof Range ? [ranges] : sort ? lazySort(ranges) : ranges)
|
|
3367
|
+
build.add(range.from, range.to, range.value);
|
|
3368
|
+
return build.finish();
|
|
3369
|
+
}
|
|
3370
|
+
}
|
|
3371
|
+
/**
|
|
3372
|
+
The empty set of ranges.
|
|
3373
|
+
*/
|
|
3374
|
+
RangeSet.empty = new RangeSet([], [], null, -1);
|
|
3375
|
+
function lazySort(ranges) {
|
|
3376
|
+
if (ranges.length > 1)
|
|
3377
|
+
for (let prev = ranges[0], i = 1; i < ranges.length; i++) {
|
|
3378
|
+
let cur = ranges[i];
|
|
3379
|
+
if (cmpRange(prev, cur) > 0)
|
|
3380
|
+
return ranges.slice().sort(cmpRange);
|
|
3381
|
+
prev = cur;
|
|
3382
|
+
}
|
|
3383
|
+
return ranges;
|
|
3384
|
+
}
|
|
3385
|
+
RangeSet.empty.nextLayer = RangeSet.empty;
|
|
3386
|
+
/**
|
|
3387
|
+
A range set builder is a data structure that helps build up a
|
|
3388
|
+
[range set](https://codemirror.net/6/docs/ref/#state.RangeSet) directly, without first allocating
|
|
3389
|
+
an array of [`Range`](https://codemirror.net/6/docs/ref/#state.Range) objects.
|
|
3390
|
+
*/
|
|
3391
|
+
class RangeSetBuilder {
|
|
3392
|
+
/**
|
|
3393
|
+
Create an empty builder.
|
|
3394
|
+
*/
|
|
3395
|
+
constructor() {
|
|
3396
|
+
this.chunks = [];
|
|
3397
|
+
this.chunkPos = [];
|
|
3398
|
+
this.chunkStart = -1;
|
|
3399
|
+
this.last = null;
|
|
3400
|
+
this.lastFrom = -1000000000 /* Far */;
|
|
3401
|
+
this.lastTo = -1000000000 /* Far */;
|
|
3402
|
+
this.from = [];
|
|
3403
|
+
this.to = [];
|
|
3404
|
+
this.value = [];
|
|
3405
|
+
this.maxPoint = -1;
|
|
3406
|
+
this.setMaxPoint = -1;
|
|
3407
|
+
this.nextLayer = null;
|
|
3408
|
+
}
|
|
3409
|
+
finishChunk(newArrays) {
|
|
3410
|
+
this.chunks.push(new Chunk(this.from, this.to, this.value, this.maxPoint));
|
|
3411
|
+
this.chunkPos.push(this.chunkStart);
|
|
3412
|
+
this.chunkStart = -1;
|
|
3413
|
+
this.setMaxPoint = Math.max(this.setMaxPoint, this.maxPoint);
|
|
3414
|
+
this.maxPoint = -1;
|
|
3415
|
+
if (newArrays) {
|
|
3416
|
+
this.from = [];
|
|
3417
|
+
this.to = [];
|
|
3418
|
+
this.value = [];
|
|
3419
|
+
}
|
|
3420
|
+
}
|
|
3421
|
+
/**
|
|
3422
|
+
Add a range. Ranges should be added in sorted (by `from` and
|
|
3423
|
+
`value.startSide`) order.
|
|
3424
|
+
*/
|
|
3425
|
+
add(from, to, value) {
|
|
3426
|
+
if (!this.addInner(from, to, value))
|
|
3427
|
+
(this.nextLayer || (this.nextLayer = new RangeSetBuilder)).add(from, to, value);
|
|
3428
|
+
}
|
|
3429
|
+
/**
|
|
3430
|
+
@internal
|
|
3431
|
+
*/
|
|
3432
|
+
addInner(from, to, value) {
|
|
3433
|
+
let diff = from - this.lastTo || value.startSide - this.last.endSide;
|
|
3434
|
+
if (diff <= 0 && (from - this.lastFrom || value.startSide - this.last.startSide) < 0)
|
|
3435
|
+
throw new Error("Ranges must be added sorted by `from` position and `startSide`");
|
|
3436
|
+
if (diff < 0)
|
|
3437
|
+
return false;
|
|
3438
|
+
if (this.from.length == 250 /* ChunkSize */)
|
|
3439
|
+
this.finishChunk(true);
|
|
3440
|
+
if (this.chunkStart < 0)
|
|
3441
|
+
this.chunkStart = from;
|
|
3442
|
+
this.from.push(from - this.chunkStart);
|
|
3443
|
+
this.to.push(to - this.chunkStart);
|
|
3444
|
+
this.last = value;
|
|
3445
|
+
this.lastFrom = from;
|
|
3446
|
+
this.lastTo = to;
|
|
3447
|
+
this.value.push(value);
|
|
3448
|
+
if (value.point)
|
|
3449
|
+
this.maxPoint = Math.max(this.maxPoint, to - from);
|
|
3450
|
+
return true;
|
|
3451
|
+
}
|
|
3452
|
+
/**
|
|
3453
|
+
@internal
|
|
3454
|
+
*/
|
|
3455
|
+
addChunk(from, chunk) {
|
|
3456
|
+
if ((from - this.lastTo || chunk.value[0].startSide - this.last.endSide) < 0)
|
|
3457
|
+
return false;
|
|
3458
|
+
if (this.from.length)
|
|
3459
|
+
this.finishChunk(true);
|
|
3460
|
+
this.setMaxPoint = Math.max(this.setMaxPoint, chunk.maxPoint);
|
|
3461
|
+
this.chunks.push(chunk);
|
|
3462
|
+
this.chunkPos.push(from);
|
|
3463
|
+
let last = chunk.value.length - 1;
|
|
3464
|
+
this.last = chunk.value[last];
|
|
3465
|
+
this.lastFrom = chunk.from[last] + from;
|
|
3466
|
+
this.lastTo = chunk.to[last] + from;
|
|
3467
|
+
return true;
|
|
3468
|
+
}
|
|
3469
|
+
/**
|
|
3470
|
+
Finish the range set. Returns the new set. The builder can't be
|
|
3471
|
+
used anymore after this has been called.
|
|
3472
|
+
*/
|
|
3473
|
+
finish() { return this.finishInner(RangeSet.empty); }
|
|
3474
|
+
/**
|
|
3475
|
+
@internal
|
|
3476
|
+
*/
|
|
3477
|
+
finishInner(next) {
|
|
3478
|
+
if (this.from.length)
|
|
3479
|
+
this.finishChunk(false);
|
|
3480
|
+
if (this.chunks.length == 0)
|
|
3481
|
+
return next;
|
|
3482
|
+
let result = RangeSet.create(this.chunkPos, this.chunks, this.nextLayer ? this.nextLayer.finishInner(next) : next, this.setMaxPoint);
|
|
3483
|
+
this.from = null; // Make sure further `add` calls produce errors
|
|
3484
|
+
return result;
|
|
3485
|
+
}
|
|
3486
|
+
}
|
|
3487
|
+
function findSharedChunks(a, b, textDiff) {
|
|
3488
|
+
let inA = new Map();
|
|
3489
|
+
for (let set of a)
|
|
3490
|
+
for (let i = 0; i < set.chunk.length; i++)
|
|
3491
|
+
if (set.chunk[i].maxPoint <= 0)
|
|
3492
|
+
inA.set(set.chunk[i], set.chunkPos[i]);
|
|
3493
|
+
let shared = new Set();
|
|
3494
|
+
for (let set of b)
|
|
3495
|
+
for (let i = 0; i < set.chunk.length; i++) {
|
|
3496
|
+
let known = inA.get(set.chunk[i]);
|
|
3497
|
+
if (known != null && (textDiff ? textDiff.mapPos(known) : known) == set.chunkPos[i] &&
|
|
3498
|
+
!(textDiff === null || textDiff === void 0 ? void 0 : textDiff.touchesRange(known, known + set.chunk[i].length)))
|
|
3499
|
+
shared.add(set.chunk[i]);
|
|
3500
|
+
}
|
|
3501
|
+
return shared;
|
|
3502
|
+
}
|
|
3503
|
+
class LayerCursor {
|
|
3504
|
+
constructor(layer, skip, minPoint, rank = 0) {
|
|
3505
|
+
this.layer = layer;
|
|
3506
|
+
this.skip = skip;
|
|
3507
|
+
this.minPoint = minPoint;
|
|
3508
|
+
this.rank = rank;
|
|
3509
|
+
}
|
|
3510
|
+
get startSide() { return this.value ? this.value.startSide : 0; }
|
|
3511
|
+
get endSide() { return this.value ? this.value.endSide : 0; }
|
|
3512
|
+
goto(pos, side = -1000000000 /* Far */) {
|
|
3513
|
+
this.chunkIndex = this.rangeIndex = 0;
|
|
3514
|
+
this.gotoInner(pos, side, false);
|
|
3515
|
+
return this;
|
|
3516
|
+
}
|
|
3517
|
+
gotoInner(pos, side, forward) {
|
|
3518
|
+
while (this.chunkIndex < this.layer.chunk.length) {
|
|
3519
|
+
let next = this.layer.chunk[this.chunkIndex];
|
|
3520
|
+
if (!(this.skip && this.skip.has(next) ||
|
|
3521
|
+
this.layer.chunkEnd(this.chunkIndex) < pos ||
|
|
3522
|
+
next.maxPoint < this.minPoint))
|
|
3523
|
+
break;
|
|
3524
|
+
this.chunkIndex++;
|
|
3525
|
+
forward = false;
|
|
3526
|
+
}
|
|
3527
|
+
if (this.chunkIndex < this.layer.chunk.length) {
|
|
3528
|
+
let rangeIndex = this.layer.chunk[this.chunkIndex].findIndex(pos - this.layer.chunkPos[this.chunkIndex], side, true);
|
|
3529
|
+
if (!forward || this.rangeIndex < rangeIndex)
|
|
3530
|
+
this.setRangeIndex(rangeIndex);
|
|
3531
|
+
}
|
|
3532
|
+
this.next();
|
|
3533
|
+
}
|
|
3534
|
+
forward(pos, side) {
|
|
3535
|
+
if ((this.to - pos || this.endSide - side) < 0)
|
|
3536
|
+
this.gotoInner(pos, side, true);
|
|
3537
|
+
}
|
|
3538
|
+
next() {
|
|
3539
|
+
for (;;) {
|
|
3540
|
+
if (this.chunkIndex == this.layer.chunk.length) {
|
|
3541
|
+
this.from = this.to = 1000000000 /* Far */;
|
|
3542
|
+
this.value = null;
|
|
3543
|
+
break;
|
|
3544
|
+
}
|
|
3545
|
+
else {
|
|
3546
|
+
let chunkPos = this.layer.chunkPos[this.chunkIndex], chunk = this.layer.chunk[this.chunkIndex];
|
|
3547
|
+
let from = chunkPos + chunk.from[this.rangeIndex];
|
|
3548
|
+
this.from = from;
|
|
3549
|
+
this.to = chunkPos + chunk.to[this.rangeIndex];
|
|
3550
|
+
this.value = chunk.value[this.rangeIndex];
|
|
3551
|
+
this.setRangeIndex(this.rangeIndex + 1);
|
|
3552
|
+
if (this.minPoint < 0 || this.value.point && this.to - this.from >= this.minPoint)
|
|
3553
|
+
break;
|
|
3554
|
+
}
|
|
3555
|
+
}
|
|
3556
|
+
}
|
|
3557
|
+
setRangeIndex(index) {
|
|
3558
|
+
if (index == this.layer.chunk[this.chunkIndex].value.length) {
|
|
3559
|
+
this.chunkIndex++;
|
|
3560
|
+
if (this.skip) {
|
|
3561
|
+
while (this.chunkIndex < this.layer.chunk.length && this.skip.has(this.layer.chunk[this.chunkIndex]))
|
|
3562
|
+
this.chunkIndex++;
|
|
3563
|
+
}
|
|
3564
|
+
this.rangeIndex = 0;
|
|
3565
|
+
}
|
|
3566
|
+
else {
|
|
3567
|
+
this.rangeIndex = index;
|
|
3568
|
+
}
|
|
3569
|
+
}
|
|
3570
|
+
nextChunk() {
|
|
3571
|
+
this.chunkIndex++;
|
|
3572
|
+
this.rangeIndex = 0;
|
|
3573
|
+
this.next();
|
|
3574
|
+
}
|
|
3575
|
+
compare(other) {
|
|
3576
|
+
return this.from - other.from || this.startSide - other.startSide || this.rank - other.rank ||
|
|
3577
|
+
this.to - other.to || this.endSide - other.endSide;
|
|
3578
|
+
}
|
|
3579
|
+
}
|
|
3580
|
+
class HeapCursor {
|
|
3581
|
+
constructor(heap) {
|
|
3582
|
+
this.heap = heap;
|
|
3583
|
+
}
|
|
3584
|
+
static from(sets, skip = null, minPoint = -1) {
|
|
3585
|
+
let heap = [];
|
|
3586
|
+
for (let i = 0; i < sets.length; i++) {
|
|
3587
|
+
for (let cur = sets[i]; !cur.isEmpty; cur = cur.nextLayer) {
|
|
3588
|
+
if (cur.maxPoint >= minPoint)
|
|
3589
|
+
heap.push(new LayerCursor(cur, skip, minPoint, i));
|
|
3590
|
+
}
|
|
3591
|
+
}
|
|
3592
|
+
return heap.length == 1 ? heap[0] : new HeapCursor(heap);
|
|
3593
|
+
}
|
|
3594
|
+
get startSide() { return this.value ? this.value.startSide : 0; }
|
|
3595
|
+
goto(pos, side = -1000000000 /* Far */) {
|
|
3596
|
+
for (let cur of this.heap)
|
|
3597
|
+
cur.goto(pos, side);
|
|
3598
|
+
for (let i = this.heap.length >> 1; i >= 0; i--)
|
|
3599
|
+
heapBubble(this.heap, i);
|
|
3600
|
+
this.next();
|
|
3601
|
+
return this;
|
|
3602
|
+
}
|
|
3603
|
+
forward(pos, side) {
|
|
3604
|
+
for (let cur of this.heap)
|
|
3605
|
+
cur.forward(pos, side);
|
|
3606
|
+
for (let i = this.heap.length >> 1; i >= 0; i--)
|
|
3607
|
+
heapBubble(this.heap, i);
|
|
3608
|
+
if ((this.to - pos || this.value.endSide - side) < 0)
|
|
3609
|
+
this.next();
|
|
3610
|
+
}
|
|
3611
|
+
next() {
|
|
3612
|
+
if (this.heap.length == 0) {
|
|
3613
|
+
this.from = this.to = 1000000000 /* Far */;
|
|
3614
|
+
this.value = null;
|
|
3615
|
+
this.rank = -1;
|
|
3616
|
+
}
|
|
3617
|
+
else {
|
|
3618
|
+
let top = this.heap[0];
|
|
3619
|
+
this.from = top.from;
|
|
3620
|
+
this.to = top.to;
|
|
3621
|
+
this.value = top.value;
|
|
3622
|
+
this.rank = top.rank;
|
|
3623
|
+
if (top.value)
|
|
3624
|
+
top.next();
|
|
3625
|
+
heapBubble(this.heap, 0);
|
|
3626
|
+
}
|
|
3627
|
+
}
|
|
3628
|
+
}
|
|
3629
|
+
function heapBubble(heap, index) {
|
|
3630
|
+
for (let cur = heap[index];;) {
|
|
3631
|
+
let childIndex = (index << 1) + 1;
|
|
3632
|
+
if (childIndex >= heap.length)
|
|
3633
|
+
break;
|
|
3634
|
+
let child = heap[childIndex];
|
|
3635
|
+
if (childIndex + 1 < heap.length && child.compare(heap[childIndex + 1]) >= 0) {
|
|
3636
|
+
child = heap[childIndex + 1];
|
|
3637
|
+
childIndex++;
|
|
3638
|
+
}
|
|
3639
|
+
if (cur.compare(child) < 0)
|
|
3640
|
+
break;
|
|
3641
|
+
heap[childIndex] = cur;
|
|
3642
|
+
heap[index] = child;
|
|
3643
|
+
index = childIndex;
|
|
3644
|
+
}
|
|
3645
|
+
}
|
|
3646
|
+
class SpanCursor {
|
|
3647
|
+
constructor(sets, skip, minPoint) {
|
|
3648
|
+
this.minPoint = minPoint;
|
|
3649
|
+
this.active = [];
|
|
3650
|
+
this.activeTo = [];
|
|
3651
|
+
this.activeRank = [];
|
|
3652
|
+
this.minActive = -1;
|
|
3653
|
+
// A currently active point range, if any
|
|
3654
|
+
this.point = null;
|
|
3655
|
+
this.pointFrom = 0;
|
|
3656
|
+
this.pointRank = 0;
|
|
3657
|
+
this.to = -1000000000 /* Far */;
|
|
3658
|
+
this.endSide = 0;
|
|
3659
|
+
this.openStart = -1;
|
|
3660
|
+
this.cursor = HeapCursor.from(sets, skip, minPoint);
|
|
3661
|
+
}
|
|
3662
|
+
goto(pos, side = -1000000000 /* Far */) {
|
|
3663
|
+
this.cursor.goto(pos, side);
|
|
3664
|
+
this.active.length = this.activeTo.length = this.activeRank.length = 0;
|
|
3665
|
+
this.minActive = -1;
|
|
3666
|
+
this.to = pos;
|
|
3667
|
+
this.endSide = side;
|
|
3668
|
+
this.openStart = -1;
|
|
3669
|
+
this.next();
|
|
3670
|
+
return this;
|
|
3671
|
+
}
|
|
3672
|
+
forward(pos, side) {
|
|
3673
|
+
while (this.minActive > -1 && (this.activeTo[this.minActive] - pos || this.active[this.minActive].endSide - side) < 0)
|
|
3674
|
+
this.removeActive(this.minActive);
|
|
3675
|
+
this.cursor.forward(pos, side);
|
|
3676
|
+
}
|
|
3677
|
+
removeActive(index) {
|
|
3678
|
+
remove(this.active, index);
|
|
3679
|
+
remove(this.activeTo, index);
|
|
3680
|
+
remove(this.activeRank, index);
|
|
3681
|
+
this.minActive = findMinIndex(this.active, this.activeTo);
|
|
3682
|
+
}
|
|
3683
|
+
addActive(trackOpen) {
|
|
3684
|
+
let i = 0, { value, to, rank } = this.cursor;
|
|
3685
|
+
while (i < this.activeRank.length && this.activeRank[i] <= rank)
|
|
3686
|
+
i++;
|
|
3687
|
+
insert(this.active, i, value);
|
|
3688
|
+
insert(this.activeTo, i, to);
|
|
3689
|
+
insert(this.activeRank, i, rank);
|
|
3690
|
+
if (trackOpen)
|
|
3691
|
+
insert(trackOpen, i, this.cursor.from);
|
|
3692
|
+
this.minActive = findMinIndex(this.active, this.activeTo);
|
|
3693
|
+
}
|
|
3694
|
+
// After calling this, if `this.point` != null, the next range is a
|
|
3695
|
+
// point. Otherwise, it's a regular range, covered by `this.active`.
|
|
3696
|
+
next() {
|
|
3697
|
+
let from = this.to, wasPoint = this.point;
|
|
3698
|
+
this.point = null;
|
|
3699
|
+
let trackOpen = this.openStart < 0 ? [] : null, trackExtra = 0;
|
|
3700
|
+
for (;;) {
|
|
3701
|
+
let a = this.minActive;
|
|
3702
|
+
if (a > -1 && (this.activeTo[a] - this.cursor.from || this.active[a].endSide - this.cursor.startSide) < 0) {
|
|
3703
|
+
if (this.activeTo[a] > from) {
|
|
3704
|
+
this.to = this.activeTo[a];
|
|
3705
|
+
this.endSide = this.active[a].endSide;
|
|
3706
|
+
break;
|
|
3707
|
+
}
|
|
3708
|
+
this.removeActive(a);
|
|
3709
|
+
if (trackOpen)
|
|
3710
|
+
remove(trackOpen, a);
|
|
3711
|
+
}
|
|
3712
|
+
else if (!this.cursor.value) {
|
|
3713
|
+
this.to = this.endSide = 1000000000 /* Far */;
|
|
3714
|
+
break;
|
|
3715
|
+
}
|
|
3716
|
+
else if (this.cursor.from > from) {
|
|
3717
|
+
this.to = this.cursor.from;
|
|
3718
|
+
this.endSide = this.cursor.startSide;
|
|
3719
|
+
break;
|
|
3720
|
+
}
|
|
3721
|
+
else {
|
|
3722
|
+
let nextVal = this.cursor.value;
|
|
3723
|
+
if (!nextVal.point) { // Opening a range
|
|
3724
|
+
this.addActive(trackOpen);
|
|
3725
|
+
this.cursor.next();
|
|
3726
|
+
}
|
|
3727
|
+
else if (wasPoint && this.cursor.to == this.to && this.cursor.from < this.cursor.to) {
|
|
3728
|
+
// Ignore any non-empty points that end precisely at the end of the prev point
|
|
3729
|
+
this.cursor.next();
|
|
3730
|
+
}
|
|
3731
|
+
else { // New point
|
|
3732
|
+
this.point = nextVal;
|
|
3733
|
+
this.pointFrom = this.cursor.from;
|
|
3734
|
+
this.pointRank = this.cursor.rank;
|
|
3735
|
+
this.to = this.cursor.to;
|
|
3736
|
+
this.endSide = nextVal.endSide;
|
|
3737
|
+
if (this.cursor.from < from)
|
|
3738
|
+
trackExtra = 1;
|
|
3739
|
+
this.cursor.next();
|
|
3740
|
+
this.forward(this.to, this.endSide);
|
|
3741
|
+
break;
|
|
3742
|
+
}
|
|
3743
|
+
}
|
|
3744
|
+
}
|
|
3745
|
+
if (trackOpen) {
|
|
3746
|
+
let openStart = 0;
|
|
3747
|
+
while (openStart < trackOpen.length && trackOpen[openStart] < from)
|
|
3748
|
+
openStart++;
|
|
3749
|
+
this.openStart = openStart + trackExtra;
|
|
3750
|
+
}
|
|
3751
|
+
}
|
|
3752
|
+
activeForPoint(to) {
|
|
3753
|
+
if (!this.active.length)
|
|
3754
|
+
return this.active;
|
|
3755
|
+
let active = [];
|
|
3756
|
+
for (let i = this.active.length - 1; i >= 0; i--) {
|
|
3757
|
+
if (this.activeRank[i] < this.pointRank)
|
|
3758
|
+
break;
|
|
3759
|
+
if (this.activeTo[i] > to || this.activeTo[i] == to && this.active[i].endSide >= this.point.endSide)
|
|
3760
|
+
active.push(this.active[i]);
|
|
3761
|
+
}
|
|
3762
|
+
return active.reverse();
|
|
3763
|
+
}
|
|
3764
|
+
openEnd(to) {
|
|
3765
|
+
let open = 0;
|
|
3766
|
+
for (let i = this.activeTo.length - 1; i >= 0 && this.activeTo[i] > to; i--)
|
|
3767
|
+
open++;
|
|
3768
|
+
return open;
|
|
3769
|
+
}
|
|
3770
|
+
}
|
|
3771
|
+
function compare(a, startA, b, startB, length, comparator) {
|
|
3772
|
+
a.goto(startA);
|
|
3773
|
+
b.goto(startB);
|
|
3774
|
+
let endB = startB + length;
|
|
3775
|
+
let pos = startB, dPos = startB - startA;
|
|
3776
|
+
for (;;) {
|
|
3777
|
+
let diff = (a.to + dPos) - b.to || a.endSide - b.endSide;
|
|
3778
|
+
let end = diff < 0 ? a.to + dPos : b.to, clipEnd = Math.min(end, endB);
|
|
3779
|
+
if (a.point || b.point) {
|
|
3780
|
+
if (!(a.point && b.point && (a.point == b.point || a.point.eq(b.point)) &&
|
|
3781
|
+
sameValues(a.activeForPoint(a.to + dPos), b.activeForPoint(b.to))))
|
|
3782
|
+
comparator.comparePoint(pos, clipEnd, a.point, b.point);
|
|
3783
|
+
}
|
|
3784
|
+
else {
|
|
3785
|
+
if (clipEnd > pos && !sameValues(a.active, b.active))
|
|
3786
|
+
comparator.compareRange(pos, clipEnd, a.active, b.active);
|
|
3787
|
+
}
|
|
3788
|
+
if (end > endB)
|
|
3789
|
+
break;
|
|
3790
|
+
pos = end;
|
|
3791
|
+
if (diff <= 0)
|
|
3792
|
+
a.next();
|
|
3793
|
+
if (diff >= 0)
|
|
3794
|
+
b.next();
|
|
3795
|
+
}
|
|
3796
|
+
}
|
|
3797
|
+
function sameValues(a, b) {
|
|
3798
|
+
if (a.length != b.length)
|
|
3799
|
+
return false;
|
|
3800
|
+
for (let i = 0; i < a.length; i++)
|
|
3801
|
+
if (a[i] != b[i] && !a[i].eq(b[i]))
|
|
3802
|
+
return false;
|
|
3803
|
+
return true;
|
|
3804
|
+
}
|
|
3805
|
+
function remove(array, index) {
|
|
3806
|
+
for (let i = index, e = array.length - 1; i < e; i++)
|
|
3807
|
+
array[i] = array[i + 1];
|
|
3808
|
+
array.pop();
|
|
3809
|
+
}
|
|
3810
|
+
function insert(array, index, value) {
|
|
3811
|
+
for (let i = array.length - 1; i >= index; i--)
|
|
3812
|
+
array[i + 1] = array[i];
|
|
3813
|
+
array[index] = value;
|
|
3814
|
+
}
|
|
3815
|
+
function findMinIndex(value, array) {
|
|
3816
|
+
let found = -1, foundPos = 1000000000 /* Far */;
|
|
3817
|
+
for (let i = 0; i < array.length; i++)
|
|
3818
|
+
if ((array[i] - foundPos || value[i].endSide - value[found].endSide) < 0) {
|
|
3819
|
+
found = i;
|
|
3820
|
+
foundPos = array[i];
|
|
3821
|
+
}
|
|
3822
|
+
return found;
|
|
3823
|
+
}
|
|
3824
|
+
|
|
3825
|
+
/**
|
|
3826
|
+
Count the column position at the given offset into the string,
|
|
3827
|
+
taking extending characters and tab size into account.
|
|
3828
|
+
*/
|
|
3829
|
+
function countColumn(string, tabSize, to = string.length) {
|
|
3830
|
+
let n = 0;
|
|
3831
|
+
for (let i = 0; i < to;) {
|
|
3832
|
+
if (string.charCodeAt(i) == 9) {
|
|
3833
|
+
n += tabSize - (n % tabSize);
|
|
3834
|
+
i++;
|
|
3835
|
+
}
|
|
3836
|
+
else {
|
|
3837
|
+
n++;
|
|
3838
|
+
i = findClusterBreak(string, i);
|
|
3839
|
+
}
|
|
3840
|
+
}
|
|
3841
|
+
return n;
|
|
3842
|
+
}
|
|
3843
|
+
/**
|
|
3844
|
+
Find the offset that corresponds to the given column position in a
|
|
3845
|
+
string, taking extending characters and tab size into account. By
|
|
3846
|
+
default, the string length is returned when it is too short to
|
|
3847
|
+
reach the column. Pass `strict` true to make it return -1 in that
|
|
3848
|
+
situation.
|
|
3849
|
+
*/
|
|
3850
|
+
function findColumn(string, col, tabSize, strict) {
|
|
3851
|
+
for (let i = 0, n = 0;;) {
|
|
3852
|
+
if (n >= col)
|
|
3853
|
+
return i;
|
|
3854
|
+
if (i == string.length)
|
|
3855
|
+
break;
|
|
3856
|
+
n += string.charCodeAt(i) == 9 ? tabSize - (n % tabSize) : 1;
|
|
3857
|
+
i = findClusterBreak(string, i);
|
|
3858
|
+
}
|
|
3859
|
+
return strict === true ? -1 : string.length;
|
|
3860
|
+
}
|
|
3861
|
+
|
|
2303
3862
|
exports.Annotation = Annotation;
|
|
2304
3863
|
exports.AnnotationType = AnnotationType;
|
|
2305
3864
|
exports.ChangeDesc = ChangeDesc;
|
|
@@ -2308,10 +3867,22 @@ exports.Compartment = Compartment;
|
|
|
2308
3867
|
exports.EditorSelection = EditorSelection;
|
|
2309
3868
|
exports.EditorState = EditorState;
|
|
2310
3869
|
exports.Facet = Facet;
|
|
3870
|
+
exports.Line = Line;
|
|
2311
3871
|
exports.Prec = Prec;
|
|
3872
|
+
exports.Range = Range;
|
|
3873
|
+
exports.RangeSet = RangeSet;
|
|
3874
|
+
exports.RangeSetBuilder = RangeSetBuilder;
|
|
3875
|
+
exports.RangeValue = RangeValue;
|
|
2312
3876
|
exports.SelectionRange = SelectionRange;
|
|
2313
3877
|
exports.StateEffect = StateEffect;
|
|
2314
3878
|
exports.StateEffectType = StateEffectType;
|
|
2315
3879
|
exports.StateField = StateField;
|
|
3880
|
+
exports.Text = Text;
|
|
2316
3881
|
exports.Transaction = Transaction;
|
|
3882
|
+
exports.codePointAt = codePointAt;
|
|
3883
|
+
exports.codePointSize = codePointSize;
|
|
2317
3884
|
exports.combineConfig = combineConfig;
|
|
3885
|
+
exports.countColumn = countColumn;
|
|
3886
|
+
exports.findClusterBreak = findClusterBreak;
|
|
3887
|
+
exports.findColumn = findColumn;
|
|
3888
|
+
exports.fromCodePoint = fromCodePoint;
|