|
|
|
var Text = class _Text { |
|
|
|
|
|
|
|
lineAt(pos) { |
|
if (pos < 0 || pos > this.length) |
|
throw new RangeError(`Invalid position ${pos} in document of length ${this.length}`); |
|
return this.lineInner(pos, false, 1, 0); |
|
} |
|
|
|
|
|
|
|
line(n) { |
|
if (n < 1 || n > this.lines) |
|
throw new RangeError(`Invalid line number ${n} in ${this.lines}-line document`); |
|
return this.lineInner(n, true, 1, 0); |
|
} |
|
|
|
|
|
|
|
replace(from, to, text) { |
|
[from, to] = clip(this, from, to); |
|
let parts = []; |
|
this.decompose( |
|
0, |
|
from, |
|
parts, |
|
2 |
|
|
|
); |
|
if (text.length) |
|
text.decompose( |
|
0, |
|
text.length, |
|
parts, |
|
1 | 2 |
|
|
|
); |
|
this.decompose( |
|
to, |
|
this.length, |
|
parts, |
|
1 |
|
|
|
); |
|
return TextNode.from(parts, this.length - (to - from) + text.length); |
|
} |
|
|
|
|
|
|
|
append(other) { |
|
return this.replace(this.length, this.length, other); |
|
} |
|
|
|
|
|
|
|
slice(from, to = this.length) { |
|
[from, to] = clip(this, from, to); |
|
let parts = []; |
|
this.decompose(from, to, parts, 0); |
|
return TextNode.from(parts, to - from); |
|
} |
|
|
|
|
|
|
|
eq(other) { |
|
if (other == this) |
|
return true; |
|
if (other.length != this.length || other.lines != this.lines) |
|
return false; |
|
let start = this.scanIdentical(other, 1), end = this.length - this.scanIdentical(other, -1); |
|
let a = new RawTextCursor(this), b = new RawTextCursor(other); |
|
for (let skip = start, pos = start; ; ) { |
|
a.next(skip); |
|
b.next(skip); |
|
skip = 0; |
|
if (a.lineBreak != b.lineBreak || a.done != b.done || a.value != b.value) |
|
return false; |
|
pos += a.value.length; |
|
if (a.done || pos >= end) |
|
return true; |
|
} |
|
} |
|
|
|
|
|
|
|
|
|
|
|
iter(dir = 1) { |
|
return new RawTextCursor(this, dir); |
|
} |
|
|
|
|
|
|
|
|
|
iterRange(from, to = this.length) { |
|
return new PartialTextCursor(this, from, to); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
iterLines(from, to) { |
|
let inner; |
|
if (from == null) { |
|
inner = this.iter(); |
|
} else { |
|
if (to == null) |
|
to = this.lines + 1; |
|
let start = this.line(from).from; |
|
inner = this.iterRange(start, Math.max(start, to == this.lines + 1 ? this.length : to <= 1 ? 0 : this.line(to - 1).to)); |
|
} |
|
return new LineCursor(inner); |
|
} |
|
|
|
|
|
|
|
|
|
toString() { |
|
return this.sliceString(0); |
|
} |
|
|
|
|
|
|
|
|
|
toJSON() { |
|
let lines = []; |
|
this.flatten(lines); |
|
return lines; |
|
} |
|
|
|
|
|
|
|
constructor() { |
|
} |
|
|
|
|
|
|
|
static of(text) { |
|
if (text.length == 0) |
|
throw new RangeError("A document must have at least one line"); |
|
if (text.length == 1 && !text[0]) |
|
return _Text.empty; |
|
return text.length <= 32 ? new TextLeaf(text) : TextNode.from(TextLeaf.split(text, [])); |
|
} |
|
}; |
|
var TextLeaf = class _TextLeaf extends Text { |
|
constructor(text, length = textLength(text)) { |
|
super(); |
|
this.text = text; |
|
this.length = length; |
|
} |
|
get lines() { |
|
return this.text.length; |
|
} |
|
get children() { |
|
return null; |
|
} |
|
lineInner(target, isLine, line, offset) { |
|
for (let i = 0; ; i++) { |
|
let string = this.text[i], end = offset + string.length; |
|
if ((isLine ? line : end) >= target) |
|
return new Line(offset, end, line, string); |
|
offset = end + 1; |
|
line++; |
|
} |
|
} |
|
decompose(from, to, target, open) { |
|
let text = from <= 0 && to >= this.length ? this : new _TextLeaf(sliceText(this.text, from, to), Math.min(to, this.length) - Math.max(0, from)); |
|
if (open & 1) { |
|
let prev = target.pop(); |
|
let joined = appendText(text.text, prev.text.slice(), 0, text.length); |
|
if (joined.length <= 32) { |
|
target.push(new _TextLeaf(joined, prev.length + text.length)); |
|
} else { |
|
let mid = joined.length >> 1; |
|
target.push(new _TextLeaf(joined.slice(0, mid)), new _TextLeaf(joined.slice(mid))); |
|
} |
|
} else { |
|
target.push(text); |
|
} |
|
} |
|
replace(from, to, text) { |
|
if (!(text instanceof _TextLeaf)) |
|
return super.replace(from, to, text); |
|
[from, to] = clip(this, from, to); |
|
let lines = appendText(this.text, appendText(text.text, sliceText(this.text, 0, from)), to); |
|
let newLen = this.length + text.length - (to - from); |
|
if (lines.length <= 32) |
|
return new _TextLeaf(lines, newLen); |
|
return TextNode.from(_TextLeaf.split(lines, []), newLen); |
|
} |
|
sliceString(from, to = this.length, lineSep = "\n") { |
|
[from, to] = clip(this, from, to); |
|
let result = ""; |
|
for (let pos = 0, i = 0; pos <= to && i < this.text.length; i++) { |
|
let line = this.text[i], end = pos + line.length; |
|
if (pos > from && i) |
|
result += lineSep; |
|
if (from < end && to > pos) |
|
result += line.slice(Math.max(0, from - pos), to - pos); |
|
pos = end + 1; |
|
} |
|
return result; |
|
} |
|
flatten(target) { |
|
for (let line of this.text) |
|
target.push(line); |
|
} |
|
scanIdentical() { |
|
return 0; |
|
} |
|
static split(text, target) { |
|
let part = [], len = -1; |
|
for (let line of text) { |
|
part.push(line); |
|
len += line.length + 1; |
|
if (part.length == 32) { |
|
target.push(new _TextLeaf(part, len)); |
|
part = []; |
|
len = -1; |
|
} |
|
} |
|
if (len > -1) |
|
target.push(new _TextLeaf(part, len)); |
|
return target; |
|
} |
|
}; |
|
var TextNode = class _TextNode extends Text { |
|
constructor(children, length) { |
|
super(); |
|
this.children = children; |
|
this.length = length; |
|
this.lines = 0; |
|
for (let child of children) |
|
this.lines += child.lines; |
|
} |
|
lineInner(target, isLine, line, offset) { |
|
for (let i = 0; ; i++) { |
|
let child = this.children[i], end = offset + child.length, endLine = line + child.lines - 1; |
|
if ((isLine ? endLine : end) >= target) |
|
return child.lineInner(target, isLine, line, offset); |
|
offset = end + 1; |
|
line = endLine + 1; |
|
} |
|
} |
|
decompose(from, to, target, open) { |
|
for (let i = 0, pos = 0; pos <= to && i < this.children.length; i++) { |
|
let child = this.children[i], end = pos + child.length; |
|
if (from <= end && to >= pos) { |
|
let childOpen = open & ((pos <= from ? 1 : 0) | (end >= to ? 2 : 0)); |
|
if (pos >= from && end <= to && !childOpen) |
|
target.push(child); |
|
else |
|
child.decompose(from - pos, to - pos, target, childOpen); |
|
} |
|
pos = end + 1; |
|
} |
|
} |
|
replace(from, to, text) { |
|
[from, to] = clip(this, from, to); |
|
if (text.lines < this.lines) |
|
for (let i = 0, pos = 0; i < this.children.length; i++) { |
|
let child = this.children[i], end = pos + child.length; |
|
if (from >= pos && to <= end) { |
|
let updated = child.replace(from - pos, to - pos, text); |
|
let totalLines = this.lines - child.lines + updated.lines; |
|
if (updated.lines < totalLines >> 5 - 1 && updated.lines > totalLines >> 5 + 1) { |
|
let copy = this.children.slice(); |
|
copy[i] = updated; |
|
return new _TextNode(copy, this.length - (to - from) + text.length); |
|
} |
|
return super.replace(pos, end, updated); |
|
} |
|
pos = end + 1; |
|
} |
|
return super.replace(from, to, text); |
|
} |
|
sliceString(from, to = this.length, lineSep = "\n") { |
|
[from, to] = clip(this, from, to); |
|
let result = ""; |
|
for (let i = 0, pos = 0; i < this.children.length && pos <= to; i++) { |
|
let child = this.children[i], end = pos + child.length; |
|
if (pos > from && i) |
|
result += lineSep; |
|
if (from < end && to > pos) |
|
result += child.sliceString(from - pos, to - pos, lineSep); |
|
pos = end + 1; |
|
} |
|
return result; |
|
} |
|
flatten(target) { |
|
for (let child of this.children) |
|
child.flatten(target); |
|
} |
|
scanIdentical(other, dir) { |
|
if (!(other instanceof _TextNode)) |
|
return 0; |
|
let length = 0; |
|
let [iA, iB, eA, eB] = dir > 0 ? [0, 0, this.children.length, other.children.length] : [this.children.length - 1, other.children.length - 1, -1, -1]; |
|
for (; ; iA += dir, iB += dir) { |
|
if (iA == eA || iB == eB) |
|
return length; |
|
let chA = this.children[iA], chB = other.children[iB]; |
|
if (chA != chB) |
|
return length + chA.scanIdentical(chB, dir); |
|
length += chA.length + 1; |
|
} |
|
} |
|
static from(children, length = children.reduce((l, ch) => l + ch.length + 1, -1)) { |
|
let lines = 0; |
|
for (let ch of children) |
|
lines += ch.lines; |
|
if (lines < 32) { |
|
let flat = []; |
|
for (let ch of children) |
|
ch.flatten(flat); |
|
return new TextLeaf(flat, length); |
|
} |
|
let chunk = Math.max( |
|
32, |
|
lines >> 5 |
|
|
|
), maxChunk = chunk << 1, minChunk = chunk >> 1; |
|
let chunked = [], currentLines = 0, currentLen = -1, currentChunk = []; |
|
function add(child) { |
|
let last; |
|
if (child.lines > maxChunk && child instanceof _TextNode) { |
|
for (let node of child.children) |
|
add(node); |
|
} else if (child.lines > minChunk && (currentLines > minChunk || !currentLines)) { |
|
flush(); |
|
chunked.push(child); |
|
} else if (child instanceof TextLeaf && currentLines && (last = currentChunk[currentChunk.length - 1]) instanceof TextLeaf && child.lines + last.lines <= 32) { |
|
currentLines += child.lines; |
|
currentLen += child.length + 1; |
|
currentChunk[currentChunk.length - 1] = new TextLeaf(last.text.concat(child.text), last.length + 1 + child.length); |
|
} else { |
|
if (currentLines + child.lines > chunk) |
|
flush(); |
|
currentLines += child.lines; |
|
currentLen += child.length + 1; |
|
currentChunk.push(child); |
|
} |
|
} |
|
function flush() { |
|
if (currentLines == 0) |
|
return; |
|
chunked.push(currentChunk.length == 1 ? currentChunk[0] : _TextNode.from(currentChunk, currentLen)); |
|
currentLen = -1; |
|
currentLines = currentChunk.length = 0; |
|
} |
|
for (let child of children) |
|
add(child); |
|
flush(); |
|
return chunked.length == 1 ? chunked[0] : new _TextNode(chunked, length); |
|
} |
|
}; |
|
Text.empty = new TextLeaf([""], 0); |
|
function textLength(text) { |
|
let length = -1; |
|
for (let line of text) |
|
length += line.length + 1; |
|
return length; |
|
} |
|
function appendText(text, target, from = 0, to = 1e9) { |
|
for (let pos = 0, i = 0, first = true; i < text.length && pos <= to; i++) { |
|
let line = text[i], end = pos + line.length; |
|
if (end >= from) { |
|
if (end > to) |
|
line = line.slice(0, to - pos); |
|
if (pos < from) |
|
line = line.slice(from - pos); |
|
if (first) { |
|
target[target.length - 1] += line; |
|
first = false; |
|
} else |
|
target.push(line); |
|
} |
|
pos = end + 1; |
|
} |
|
return target; |
|
} |
|
function sliceText(text, from, to) { |
|
return appendText(text, [""], from, to); |
|
} |
|
var RawTextCursor = class { |
|
constructor(text, dir = 1) { |
|
this.dir = dir; |
|
this.done = false; |
|
this.lineBreak = false; |
|
this.value = ""; |
|
this.nodes = [text]; |
|
this.offsets = [dir > 0 ? 1 : (text instanceof TextLeaf ? text.text.length : text.children.length) << 1]; |
|
} |
|
nextInner(skip, dir) { |
|
this.done = this.lineBreak = false; |
|
for (; ; ) { |
|
let last = this.nodes.length - 1; |
|
let top = this.nodes[last], offsetValue = this.offsets[last], offset = offsetValue >> 1; |
|
let size = top instanceof TextLeaf ? top.text.length : top.children.length; |
|
if (offset == (dir > 0 ? size : 0)) { |
|
if (last == 0) { |
|
this.done = true; |
|
this.value = ""; |
|
return this; |
|
} |
|
if (dir > 0) |
|
this.offsets[last - 1]++; |
|
this.nodes.pop(); |
|
this.offsets.pop(); |
|
} else if ((offsetValue & 1) == (dir > 0 ? 0 : 1)) { |
|
this.offsets[last] += dir; |
|
if (skip == 0) { |
|
this.lineBreak = true; |
|
this.value = "\n"; |
|
return this; |
|
} |
|
skip--; |
|
} else if (top instanceof TextLeaf) { |
|
let next = top.text[offset + (dir < 0 ? -1 : 0)]; |
|
this.offsets[last] += dir; |
|
if (next.length > Math.max(0, skip)) { |
|
this.value = skip == 0 ? next : dir > 0 ? next.slice(skip) : next.slice(0, next.length - skip); |
|
return this; |
|
} |
|
skip -= next.length; |
|
} else { |
|
let next = top.children[offset + (dir < 0 ? -1 : 0)]; |
|
if (skip > next.length) { |
|
skip -= next.length; |
|
this.offsets[last] += dir; |
|
} else { |
|
if (dir < 0) |
|
this.offsets[last]--; |
|
this.nodes.push(next); |
|
this.offsets.push(dir > 0 ? 1 : (next instanceof TextLeaf ? next.text.length : next.children.length) << 1); |
|
} |
|
} |
|
} |
|
} |
|
next(skip = 0) { |
|
if (skip < 0) { |
|
this.nextInner(-skip, -this.dir); |
|
skip = this.value.length; |
|
} |
|
return this.nextInner(skip, this.dir); |
|
} |
|
}; |
|
var PartialTextCursor = class { |
|
constructor(text, start, end) { |
|
this.value = ""; |
|
this.done = false; |
|
this.cursor = new RawTextCursor(text, start > end ? -1 : 1); |
|
this.pos = start > end ? text.length : 0; |
|
this.from = Math.min(start, end); |
|
this.to = Math.max(start, end); |
|
} |
|
nextInner(skip, dir) { |
|
if (dir < 0 ? this.pos <= this.from : this.pos >= this.to) { |
|
this.value = ""; |
|
this.done = true; |
|
return this; |
|
} |
|
skip += Math.max(0, dir < 0 ? this.pos - this.to : this.from - this.pos); |
|
let limit = dir < 0 ? this.pos - this.from : this.to - this.pos; |
|
if (skip > limit) |
|
skip = limit; |
|
limit -= skip; |
|
let { value } = this.cursor.next(skip); |
|
this.pos += (value.length + skip) * dir; |
|
this.value = value.length <= limit ? value : dir < 0 ? value.slice(value.length - limit) : value.slice(0, limit); |
|
this.done = !this.value; |
|
return this; |
|
} |
|
next(skip = 0) { |
|
if (skip < 0) |
|
skip = Math.max(skip, this.from - this.pos); |
|
else if (skip > 0) |
|
skip = Math.min(skip, this.to - this.pos); |
|
return this.nextInner(skip, this.cursor.dir); |
|
} |
|
get lineBreak() { |
|
return this.cursor.lineBreak && this.value != ""; |
|
} |
|
}; |
|
var LineCursor = class { |
|
constructor(inner) { |
|
this.inner = inner; |
|
this.afterBreak = true; |
|
this.value = ""; |
|
this.done = false; |
|
} |
|
next(skip = 0) { |
|
let { done, lineBreak, value } = this.inner.next(skip); |
|
if (done && this.afterBreak) { |
|
this.value = ""; |
|
this.afterBreak = false; |
|
} else if (done) { |
|
this.done = true; |
|
this.value = ""; |
|
} else if (lineBreak) { |
|
if (this.afterBreak) { |
|
this.value = ""; |
|
} else { |
|
this.afterBreak = true; |
|
this.next(); |
|
} |
|
} else { |
|
this.value = value; |
|
this.afterBreak = false; |
|
} |
|
return this; |
|
} |
|
get lineBreak() { |
|
return false; |
|
} |
|
}; |
|
if (typeof Symbol != "undefined") { |
|
Text.prototype[Symbol.iterator] = function() { |
|
return this.iter(); |
|
}; |
|
RawTextCursor.prototype[Symbol.iterator] = PartialTextCursor.prototype[Symbol.iterator] = LineCursor.prototype[Symbol.iterator] = function() { |
|
return this; |
|
}; |
|
} |
|
var Line = class { |
|
|
|
|
|
|
|
constructor(from, to, number, text) { |
|
this.from = from; |
|
this.to = to; |
|
this.number = number; |
|
this.text = text; |
|
} |
|
|
|
|
|
|
|
get length() { |
|
return this.to - this.from; |
|
} |
|
}; |
|
function clip(text, from, to) { |
|
from = Math.max(0, Math.min(text.length, from)); |
|
return [from, Math.max(from, Math.min(text.length, to))]; |
|
} |
|
var 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); |
|
for (let i = 1; i < extend.length; i++) |
|
extend[i] += extend[i - 1]; |
|
function isExtendingChar(code) { |
|
for (let i = 1; i < extend.length; i += 2) |
|
if (extend[i] > code) |
|
return extend[i - 1] <= code; |
|
return false; |
|
} |
|
function isRegionalIndicator(code) { |
|
return code >= 127462 && code <= 127487; |
|
} |
|
var ZWJ = 8205; |
|
function findClusterBreak(str, pos, forward = true, includeExtending = true) { |
|
return (forward ? nextClusterBreak : prevClusterBreak)(str, pos, includeExtending); |
|
} |
|
function nextClusterBreak(str, pos, includeExtending) { |
|
if (pos == str.length) |
|
return pos; |
|
if (pos && surrogateLow(str.charCodeAt(pos)) && surrogateHigh(str.charCodeAt(pos - 1))) |
|
pos--; |
|
let prev = codePointAt(str, pos); |
|
pos += codePointSize(prev); |
|
while (pos < str.length) { |
|
let next = codePointAt(str, pos); |
|
if (prev == ZWJ || next == ZWJ || includeExtending && isExtendingChar(next)) { |
|
pos += codePointSize(next); |
|
prev = next; |
|
} else if (isRegionalIndicator(next)) { |
|
let countBefore = 0, i = pos - 2; |
|
while (i >= 0 && isRegionalIndicator(codePointAt(str, i))) { |
|
countBefore++; |
|
i -= 2; |
|
} |
|
if (countBefore % 2 == 0) |
|
break; |
|
else |
|
pos += 2; |
|
} else { |
|
break; |
|
} |
|
} |
|
return pos; |
|
} |
|
function prevClusterBreak(str, pos, includeExtending) { |
|
while (pos > 0) { |
|
let found = nextClusterBreak(str, pos - 2, includeExtending); |
|
if (found < pos) |
|
return found; |
|
pos--; |
|
} |
|
return 0; |
|
} |
|
function surrogateLow(ch) { |
|
return ch >= 56320 && ch < 57344; |
|
} |
|
function surrogateHigh(ch) { |
|
return ch >= 55296 && ch < 56320; |
|
} |
|
function codePointAt(str, pos) { |
|
let code0 = str.charCodeAt(pos); |
|
if (!surrogateHigh(code0) || pos + 1 == str.length) |
|
return code0; |
|
let code1 = str.charCodeAt(pos + 1); |
|
if (!surrogateLow(code1)) |
|
return code0; |
|
return (code0 - 55296 << 10) + (code1 - 56320) + 65536; |
|
} |
|
function fromCodePoint(code) { |
|
if (code <= 65535) |
|
return String.fromCharCode(code); |
|
code -= 65536; |
|
return String.fromCharCode((code >> 10) + 55296, (code & 1023) + 56320); |
|
} |
|
function codePointSize(code) { |
|
return code < 65536 ? 1 : 2; |
|
} |
|
var DefaultSplit = /\r\n?|\n/; |
|
var MapMode = function(MapMode2) { |
|
MapMode2[MapMode2["Simple"] = 0] = "Simple"; |
|
MapMode2[MapMode2["TrackDel"] = 1] = "TrackDel"; |
|
MapMode2[MapMode2["TrackBefore"] = 2] = "TrackBefore"; |
|
MapMode2[MapMode2["TrackAfter"] = 3] = "TrackAfter"; |
|
return MapMode2; |
|
}(MapMode || (MapMode = {})); |
|
var ChangeDesc = class _ChangeDesc { |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
constructor(sections) { |
|
this.sections = sections; |
|
} |
|
|
|
|
|
|
|
get length() { |
|
let result = 0; |
|
for (let i = 0; i < this.sections.length; i += 2) |
|
result += this.sections[i]; |
|
return result; |
|
} |
|
|
|
|
|
|
|
get newLength() { |
|
let result = 0; |
|
for (let i = 0; i < this.sections.length; i += 2) { |
|
let ins = this.sections[i + 1]; |
|
result += ins < 0 ? this.sections[i] : ins; |
|
} |
|
return result; |
|
} |
|
|
|
|
|
|
|
get empty() { |
|
return this.sections.length == 0 || this.sections.length == 2 && this.sections[1] < 0; |
|
} |
|
|
|
|
|
|
|
|
|
|
|
iterGaps(f) { |
|
for (let i = 0, posA = 0, posB = 0; i < this.sections.length; ) { |
|
let len = this.sections[i++], ins = this.sections[i++]; |
|
if (ins < 0) { |
|
f(posA, posB, len); |
|
posB += len; |
|
} else { |
|
posB += ins; |
|
} |
|
posA += len; |
|
} |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
iterChangedRanges(f, individual = false) { |
|
iterChanges(this, f, individual); |
|
} |
|
|
|
|
|
|
|
get invertedDesc() { |
|
let sections = []; |
|
for (let i = 0; i < this.sections.length; ) { |
|
let len = this.sections[i++], ins = this.sections[i++]; |
|
if (ins < 0) |
|
sections.push(len, ins); |
|
else |
|
sections.push(ins, len); |
|
} |
|
return new _ChangeDesc(sections); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
composeDesc(other) { |
|
return this.empty ? other : other.empty ? this : composeSets(this, other); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
mapDesc(other, before = false) { |
|
return other.empty ? this : mapSet(this, other, before); |
|
} |
|
mapPos(pos, assoc = -1, mode = MapMode.Simple) { |
|
let posA = 0, posB = 0; |
|
for (let i = 0; i < this.sections.length; ) { |
|
let len = this.sections[i++], ins = this.sections[i++], endA = posA + len; |
|
if (ins < 0) { |
|
if (endA > pos) |
|
return posB + (pos - posA); |
|
posB += len; |
|
} else { |
|
if (mode != MapMode.Simple && endA >= pos && (mode == MapMode.TrackDel && posA < pos && endA > pos || mode == MapMode.TrackBefore && posA < pos || mode == MapMode.TrackAfter && endA > pos)) |
|
return null; |
|
if (endA > pos || endA == pos && assoc < 0 && !len) |
|
return pos == posA || assoc < 0 ? posB : posB + ins; |
|
posB += ins; |
|
} |
|
posA = endA; |
|
} |
|
if (pos > posA) |
|
throw new RangeError(`Position ${pos} is out of range for changeset of length ${posA}`); |
|
return posB; |
|
} |
|
|
|
|
|
|
|
|
|
|
|
touchesRange(from, to = from) { |
|
for (let i = 0, pos = 0; i < this.sections.length && pos <= to; ) { |
|
let len = this.sections[i++], ins = this.sections[i++], end = pos + len; |
|
if (ins >= 0 && pos <= to && end >= from) |
|
return pos < from && end > to ? "cover" : true; |
|
pos = end; |
|
} |
|
return false; |
|
} |
|
|
|
|
|
|
|
toString() { |
|
let result = ""; |
|
for (let i = 0; i < this.sections.length; ) { |
|
let len = this.sections[i++], ins = this.sections[i++]; |
|
result += (result ? " " : "") + len + (ins >= 0 ? ":" + ins : ""); |
|
} |
|
return result; |
|
} |
|
|
|
|
|
|
|
toJSON() { |
|
return this.sections; |
|
} |
|
|
|
|
|
|
|
|
|
static fromJSON(json) { |
|
if (!Array.isArray(json) || json.length % 2 || json.some((a) => typeof a != "number")) |
|
throw new RangeError("Invalid JSON representation of ChangeDesc"); |
|
return new _ChangeDesc(json); |
|
} |
|
|
|
|
|
|
|
static create(sections) { |
|
return new _ChangeDesc(sections); |
|
} |
|
}; |
|
var ChangeSet = class _ChangeSet extends ChangeDesc { |
|
constructor(sections, inserted) { |
|
super(sections); |
|
this.inserted = inserted; |
|
} |
|
|
|
|
|
|
|
|
|
apply(doc) { |
|
if (this.length != doc.length) |
|
throw new RangeError("Applying change set to a document with the wrong length"); |
|
iterChanges(this, (fromA, toA, fromB, _toB, text) => doc = doc.replace(fromB, fromB + (toA - fromA), text), false); |
|
return doc; |
|
} |
|
mapDesc(other, before = false) { |
|
return mapSet(this, other, before, true); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
invert(doc) { |
|
let sections = this.sections.slice(), inserted = []; |
|
for (let i = 0, pos = 0; i < sections.length; i += 2) { |
|
let len = sections[i], ins = sections[i + 1]; |
|
if (ins >= 0) { |
|
sections[i] = ins; |
|
sections[i + 1] = len; |
|
let index = i >> 1; |
|
while (inserted.length < index) |
|
inserted.push(Text.empty); |
|
inserted.push(len ? doc.slice(pos, pos + len) : Text.empty); |
|
} |
|
pos += len; |
|
} |
|
return new _ChangeSet(sections, inserted); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
compose(other) { |
|
return this.empty ? other : other.empty ? this : composeSets(this, other, true); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
map(other, before = false) { |
|
return other.empty ? this : mapSet(this, other, before, true); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
iterChanges(f, individual = false) { |
|
iterChanges(this, f, individual); |
|
} |
|
|
|
|
|
|
|
|
|
get desc() { |
|
return ChangeDesc.create(this.sections); |
|
} |
|
|
|
|
|
|
|
filter(ranges) { |
|
let resultSections = [], resultInserted = [], filteredSections = []; |
|
let iter = new SectionIter(this); |
|
done: for (let i = 0, pos = 0; ; ) { |
|
let next = i == ranges.length ? 1e9 : ranges[i++]; |
|
while (pos < next || pos == next && iter.len == 0) { |
|
if (iter.done) |
|
break done; |
|
let len = Math.min(iter.len, next - pos); |
|
addSection(filteredSections, len, -1); |
|
let ins = iter.ins == -1 ? -1 : iter.off == 0 ? iter.ins : 0; |
|
addSection(resultSections, len, ins); |
|
if (ins > 0) |
|
addInsert(resultInserted, resultSections, iter.text); |
|
iter.forward(len); |
|
pos += len; |
|
} |
|
let end = ranges[i++]; |
|
while (pos < end) { |
|
if (iter.done) |
|
break done; |
|
let len = Math.min(iter.len, end - pos); |
|
addSection(resultSections, len, -1); |
|
addSection(filteredSections, len, iter.ins == -1 ? -1 : iter.off == 0 ? iter.ins : 0); |
|
iter.forward(len); |
|
pos += len; |
|
} |
|
} |
|
return { |
|
changes: new _ChangeSet(resultSections, resultInserted), |
|
filtered: ChangeDesc.create(filteredSections) |
|
}; |
|
} |
|
|
|
|
|
|
|
toJSON() { |
|
let parts = []; |
|
for (let i = 0; i < this.sections.length; i += 2) { |
|
let len = this.sections[i], ins = this.sections[i + 1]; |
|
if (ins < 0) |
|
parts.push(len); |
|
else if (ins == 0) |
|
parts.push([len]); |
|
else |
|
parts.push([len].concat(this.inserted[i >> 1].toJSON())); |
|
} |
|
return parts; |
|
} |
|
|
|
|
|
|
|
|
|
static of(changes, length, lineSep) { |
|
let sections = [], inserted = [], pos = 0; |
|
let total = null; |
|
function flush(force = false) { |
|
if (!force && !sections.length) |
|
return; |
|
if (pos < length) |
|
addSection(sections, length - pos, -1); |
|
let set = new _ChangeSet(sections, inserted); |
|
total = total ? total.compose(set.map(total)) : set; |
|
sections = []; |
|
inserted = []; |
|
pos = 0; |
|
} |
|
function process(spec) { |
|
if (Array.isArray(spec)) { |
|
for (let sub of spec) |
|
process(sub); |
|
} else if (spec instanceof _ChangeSet) { |
|
if (spec.length != length) |
|
throw new RangeError(`Mismatched change set length (got ${spec.length}, expected ${length})`); |
|
flush(); |
|
total = total ? total.compose(spec.map(total)) : spec; |
|
} else { |
|
let { from, to = from, insert: insert2 } = spec; |
|
if (from > to || from < 0 || to > length) |
|
throw new RangeError(`Invalid change range ${from} to ${to} (in doc of length ${length})`); |
|
let insText = !insert2 ? Text.empty : typeof insert2 == "string" ? Text.of(insert2.split(lineSep || DefaultSplit)) : insert2; |
|
let insLen = insText.length; |
|
if (from == to && insLen == 0) |
|
return; |
|
if (from < pos) |
|
flush(); |
|
if (from > pos) |
|
addSection(sections, from - pos, -1); |
|
addSection(sections, to - from, insLen); |
|
addInsert(inserted, sections, insText); |
|
pos = to; |
|
} |
|
} |
|
process(changes); |
|
flush(!total); |
|
return total; |
|
} |
|
|
|
|
|
|
|
static empty(length) { |
|
return new _ChangeSet(length ? [length, -1] : [], []); |
|
} |
|
|
|
|
|
|
|
|
|
static fromJSON(json) { |
|
if (!Array.isArray(json)) |
|
throw new RangeError("Invalid JSON representation of ChangeSet"); |
|
let sections = [], inserted = []; |
|
for (let i = 0; i < json.length; i++) { |
|
let part = json[i]; |
|
if (typeof part == "number") { |
|
sections.push(part, -1); |
|
} else if (!Array.isArray(part) || typeof part[0] != "number" || part.some((e, i2) => i2 && typeof e != "string")) { |
|
throw new RangeError("Invalid JSON representation of ChangeSet"); |
|
} else if (part.length == 1) { |
|
sections.push(part[0], 0); |
|
} else { |
|
while (inserted.length < i) |
|
inserted.push(Text.empty); |
|
inserted[i] = Text.of(part.slice(1)); |
|
sections.push(part[0], inserted[i].length); |
|
} |
|
} |
|
return new _ChangeSet(sections, inserted); |
|
} |
|
|
|
|
|
|
|
static createSet(sections, inserted) { |
|
return new _ChangeSet(sections, inserted); |
|
} |
|
}; |
|
function addSection(sections, len, ins, forceJoin = false) { |
|
if (len == 0 && ins <= 0) |
|
return; |
|
let last = sections.length - 2; |
|
if (last >= 0 && ins <= 0 && ins == sections[last + 1]) |
|
sections[last] += len; |
|
else if (len == 0 && sections[last] == 0) |
|
sections[last + 1] += ins; |
|
else if (forceJoin) { |
|
sections[last] += len; |
|
sections[last + 1] += ins; |
|
} else |
|
sections.push(len, ins); |
|
} |
|
function addInsert(values, sections, value) { |
|
if (value.length == 0) |
|
return; |
|
let index = sections.length - 2 >> 1; |
|
if (index < values.length) { |
|
values[values.length - 1] = values[values.length - 1].append(value); |
|
} else { |
|
while (values.length < index) |
|
values.push(Text.empty); |
|
values.push(value); |
|
} |
|
} |
|
function iterChanges(desc, f, individual) { |
|
let inserted = desc.inserted; |
|
for (let posA = 0, posB = 0, i = 0; i < desc.sections.length; ) { |
|
let len = desc.sections[i++], ins = desc.sections[i++]; |
|
if (ins < 0) { |
|
posA += len; |
|
posB += len; |
|
} else { |
|
let endA = posA, endB = posB, text = Text.empty; |
|
for (; ; ) { |
|
endA += len; |
|
endB += ins; |
|
if (ins && inserted) |
|
text = text.append(inserted[i - 2 >> 1]); |
|
if (individual || i == desc.sections.length || desc.sections[i + 1] < 0) |
|
break; |
|
len = desc.sections[i++]; |
|
ins = desc.sections[i++]; |
|
} |
|
f(posA, endA, posB, endB, text); |
|
posA = endA; |
|
posB = endB; |
|
} |
|
} |
|
} |
|
function mapSet(setA, setB, before, mkSet = false) { |
|
let sections = [], insert2 = mkSet ? [] : null; |
|
let a = new SectionIter(setA), b = new SectionIter(setB); |
|
for (let inserted = -1; ; ) { |
|
if (a.ins == -1 && b.ins == -1) { |
|
let len = Math.min(a.len, b.len); |
|
addSection(sections, len, -1); |
|
a.forward(len); |
|
b.forward(len); |
|
} else if (b.ins >= 0 && (a.ins < 0 || inserted == a.i || a.off == 0 && (b.len < a.len || b.len == a.len && !before))) { |
|
let len = b.len; |
|
addSection(sections, b.ins, -1); |
|
while (len) { |
|
let piece = Math.min(a.len, len); |
|
if (a.ins >= 0 && inserted < a.i && a.len <= piece) { |
|
addSection(sections, 0, a.ins); |
|
if (insert2) |
|
addInsert(insert2, sections, a.text); |
|
inserted = a.i; |
|
} |
|
a.forward(piece); |
|
len -= piece; |
|
} |
|
b.next(); |
|
} else if (a.ins >= 0) { |
|
let len = 0, left = a.len; |
|
while (left) { |
|
if (b.ins == -1) { |
|
let piece = Math.min(left, b.len); |
|
len += piece; |
|
left -= piece; |
|
b.forward(piece); |
|
} else if (b.ins == 0 && b.len < left) { |
|
left -= b.len; |
|
b.next(); |
|
} else { |
|
break; |
|
} |
|
} |
|
addSection(sections, len, inserted < a.i ? a.ins : 0); |
|
if (insert2 && inserted < a.i) |
|
addInsert(insert2, sections, a.text); |
|
inserted = a.i; |
|
a.forward(a.len - left); |
|
} else if (a.done && b.done) { |
|
return insert2 ? ChangeSet.createSet(sections, insert2) : ChangeDesc.create(sections); |
|
} else { |
|
throw new Error("Mismatched change set lengths"); |
|
} |
|
} |
|
} |
|
function composeSets(setA, setB, mkSet = false) { |
|
let sections = []; |
|
let insert2 = mkSet ? [] : null; |
|
let a = new SectionIter(setA), b = new SectionIter(setB); |
|
for (let open = false; ; ) { |
|
if (a.done && b.done) { |
|
return insert2 ? ChangeSet.createSet(sections, insert2) : ChangeDesc.create(sections); |
|
} else if (a.ins == 0) { |
|
addSection(sections, a.len, 0, open); |
|
a.next(); |
|
} else if (b.len == 0 && !b.done) { |
|
addSection(sections, 0, b.ins, open); |
|
if (insert2) |
|
addInsert(insert2, sections, b.text); |
|
b.next(); |
|
} else if (a.done || b.done) { |
|
throw new Error("Mismatched change set lengths"); |
|
} else { |
|
let len = Math.min(a.len2, b.len), sectionLen = sections.length; |
|
if (a.ins == -1) { |
|
let insB = b.ins == -1 ? -1 : b.off ? 0 : b.ins; |
|
addSection(sections, len, insB, open); |
|
if (insert2 && insB) |
|
addInsert(insert2, sections, b.text); |
|
} else if (b.ins == -1) { |
|
addSection(sections, a.off ? 0 : a.len, len, open); |
|
if (insert2) |
|
addInsert(insert2, sections, a.textBit(len)); |
|
} else { |
|
addSection(sections, a.off ? 0 : a.len, b.off ? 0 : b.ins, open); |
|
if (insert2 && !b.off) |
|
addInsert(insert2, sections, b.text); |
|
} |
|
open = (a.ins > len || b.ins >= 0 && b.len > len) && (open || sections.length > sectionLen); |
|
a.forward2(len); |
|
b.forward(len); |
|
} |
|
} |
|
} |
|
var SectionIter = class { |
|
constructor(set) { |
|
this.set = set; |
|
this.i = 0; |
|
this.next(); |
|
} |
|
next() { |
|
let { sections } = this.set; |
|
if (this.i < sections.length) { |
|
this.len = sections[this.i++]; |
|
this.ins = sections[this.i++]; |
|
} else { |
|
this.len = 0; |
|
this.ins = -2; |
|
} |
|
this.off = 0; |
|
} |
|
get done() { |
|
return this.ins == -2; |
|
} |
|
get len2() { |
|
return this.ins < 0 ? this.len : this.ins; |
|
} |
|
get text() { |
|
let { inserted } = this.set, index = this.i - 2 >> 1; |
|
return index >= inserted.length ? Text.empty : inserted[index]; |
|
} |
|
textBit(len) { |
|
let { inserted } = this.set, index = this.i - 2 >> 1; |
|
return index >= inserted.length && !len ? Text.empty : inserted[index].slice(this.off, len == null ? void 0 : this.off + len); |
|
} |
|
forward(len) { |
|
if (len == this.len) |
|
this.next(); |
|
else { |
|
this.len -= len; |
|
this.off += len; |
|
} |
|
} |
|
forward2(len) { |
|
if (this.ins == -1) |
|
this.forward(len); |
|
else if (len == this.ins) |
|
this.next(); |
|
else { |
|
this.ins -= len; |
|
this.off += len; |
|
} |
|
} |
|
}; |
|
var SelectionRange = class _SelectionRange { |
|
constructor(from, to, flags) { |
|
this.from = from; |
|
this.to = to; |
|
this.flags = flags; |
|
} |
|
|
|
|
|
|
|
|
|
get anchor() { |
|
return this.flags & 32 ? this.to : this.from; |
|
} |
|
|
|
|
|
|
|
|
|
get head() { |
|
return this.flags & 32 ? this.from : this.to; |
|
} |
|
|
|
|
|
|
|
get empty() { |
|
return this.from == this.to; |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
get assoc() { |
|
return this.flags & 8 ? -1 : this.flags & 16 ? 1 : 0; |
|
} |
|
|
|
|
|
|
|
|
|
get bidiLevel() { |
|
let level = this.flags & 7; |
|
return level == 7 ? null : level; |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
get goalColumn() { |
|
let value = this.flags >> 6; |
|
return value == 16777215 ? void 0 : value; |
|
} |
|
|
|
|
|
|
|
|
|
map(change, assoc = -1) { |
|
let from, to; |
|
if (this.empty) { |
|
from = to = change.mapPos(this.from, assoc); |
|
} else { |
|
from = change.mapPos(this.from, 1); |
|
to = change.mapPos(this.to, -1); |
|
} |
|
return from == this.from && to == this.to ? this : new _SelectionRange(from, to, this.flags); |
|
} |
|
|
|
|
|
|
|
extend(from, to = from) { |
|
if (from <= this.anchor && to >= this.anchor) |
|
return EditorSelection.range(from, to); |
|
let head = Math.abs(from - this.anchor) > Math.abs(to - this.anchor) ? from : to; |
|
return EditorSelection.range(this.anchor, head); |
|
} |
|
|
|
|
|
|
|
eq(other, includeAssoc = false) { |
|
return this.anchor == other.anchor && this.head == other.head && (!includeAssoc || !this.empty || this.assoc == other.assoc); |
|
} |
|
|
|
|
|
|
|
toJSON() { |
|
return { anchor: this.anchor, head: this.head }; |
|
} |
|
|
|
|
|
|
|
|
|
static fromJSON(json) { |
|
if (!json || typeof json.anchor != "number" || typeof json.head != "number") |
|
throw new RangeError("Invalid JSON representation for SelectionRange"); |
|
return EditorSelection.range(json.anchor, json.head); |
|
} |
|
|
|
|
|
|
|
static create(from, to, flags) { |
|
return new _SelectionRange(from, to, flags); |
|
} |
|
}; |
|
var EditorSelection = class _EditorSelection { |
|
constructor(ranges, mainIndex) { |
|
this.ranges = ranges; |
|
this.mainIndex = mainIndex; |
|
} |
|
|
|
|
|
|
|
|
|
map(change, assoc = -1) { |
|
if (change.empty) |
|
return this; |
|
return _EditorSelection.create(this.ranges.map((r) => r.map(change, assoc)), this.mainIndex); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
eq(other, includeAssoc = false) { |
|
if (this.ranges.length != other.ranges.length || this.mainIndex != other.mainIndex) |
|
return false; |
|
for (let i = 0; i < this.ranges.length; i++) |
|
if (!this.ranges[i].eq(other.ranges[i], includeAssoc)) |
|
return false; |
|
return true; |
|
} |
|
|
|
|
|
|
|
|
|
|
|
get main() { |
|
return this.ranges[this.mainIndex]; |
|
} |
|
|
|
|
|
|
|
|
|
asSingle() { |
|
return this.ranges.length == 1 ? this : new _EditorSelection([this.main], 0); |
|
} |
|
|
|
|
|
|
|
addRange(range, main = true) { |
|
return _EditorSelection.create([range].concat(this.ranges), main ? 0 : this.mainIndex + 1); |
|
} |
|
|
|
|
|
|
|
|
|
replaceRange(range, which = this.mainIndex) { |
|
let ranges = this.ranges.slice(); |
|
ranges[which] = range; |
|
return _EditorSelection.create(ranges, this.mainIndex); |
|
} |
|
|
|
|
|
|
|
|
|
toJSON() { |
|
return { ranges: this.ranges.map((r) => r.toJSON()), main: this.mainIndex }; |
|
} |
|
|
|
|
|
|
|
static fromJSON(json) { |
|
if (!json || !Array.isArray(json.ranges) || typeof json.main != "number" || json.main >= json.ranges.length) |
|
throw new RangeError("Invalid JSON representation for EditorSelection"); |
|
return new _EditorSelection(json.ranges.map((r) => SelectionRange.fromJSON(r)), json.main); |
|
} |
|
|
|
|
|
|
|
static single(anchor, head = anchor) { |
|
return new _EditorSelection([_EditorSelection.range(anchor, head)], 0); |
|
} |
|
|
|
|
|
|
|
|
|
static create(ranges, mainIndex = 0) { |
|
if (ranges.length == 0) |
|
throw new RangeError("A selection needs at least one range"); |
|
for (let pos = 0, i = 0; i < ranges.length; i++) { |
|
let range = ranges[i]; |
|
if (range.empty ? range.from <= pos : range.from < pos) |
|
return _EditorSelection.normalized(ranges.slice(), mainIndex); |
|
pos = range.to; |
|
} |
|
return new _EditorSelection(ranges, mainIndex); |
|
} |
|
|
|
|
|
|
|
|
|
static cursor(pos, assoc = 0, bidiLevel, goalColumn) { |
|
return SelectionRange.create(pos, pos, (assoc == 0 ? 0 : assoc < 0 ? 8 : 16) | (bidiLevel == null ? 7 : Math.min(6, bidiLevel)) | (goalColumn !== null && goalColumn !== void 0 ? goalColumn : 16777215) << 6); |
|
} |
|
|
|
|
|
|
|
static range(anchor, head, goalColumn, bidiLevel) { |
|
let flags = (goalColumn !== null && goalColumn !== void 0 ? goalColumn : 16777215) << 6 | (bidiLevel == null ? 7 : Math.min(6, bidiLevel)); |
|
return head < anchor ? SelectionRange.create(head, anchor, 32 | 16 | flags) : SelectionRange.create(anchor, head, (head > anchor ? 8 : 0) | flags); |
|
} |
|
|
|
|
|
|
|
static normalized(ranges, mainIndex = 0) { |
|
let main = ranges[mainIndex]; |
|
ranges.sort((a, b) => a.from - b.from); |
|
mainIndex = ranges.indexOf(main); |
|
for (let i = 1; i < ranges.length; i++) { |
|
let range = ranges[i], prev = ranges[i - 1]; |
|
if (range.empty ? range.from <= prev.to : range.from < prev.to) { |
|
let from = prev.from, to = Math.max(range.to, prev.to); |
|
if (i <= mainIndex) |
|
mainIndex--; |
|
ranges.splice(--i, 2, range.anchor > range.head ? _EditorSelection.range(to, from) : _EditorSelection.range(from, to)); |
|
} |
|
} |
|
return new _EditorSelection(ranges, mainIndex); |
|
} |
|
}; |
|
function checkSelection(selection, docLength) { |
|
for (let range of selection.ranges) |
|
if (range.to > docLength) |
|
throw new RangeError("Selection points outside of document"); |
|
} |
|
var nextID = 0; |
|
var Facet = class _Facet { |
|
constructor(combine, compareInput, compare2, isStatic, enables) { |
|
this.combine = combine; |
|
this.compareInput = compareInput; |
|
this.compare = compare2; |
|
this.isStatic = isStatic; |
|
this.id = nextID++; |
|
this.default = combine([]); |
|
this.extensions = typeof enables == "function" ? enables(this) : enables; |
|
} |
|
|
|
|
|
|
|
|
|
get reader() { |
|
return this; |
|
} |
|
|
|
|
|
|
|
static define(config = {}) { |
|
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); |
|
} |
|
|
|
|
|
|
|
of(value) { |
|
return new FacetProvider([], this, 0, value); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
compute(deps, get) { |
|
if (this.isStatic) |
|
throw new Error("Can't compute a static facet"); |
|
return new FacetProvider(deps, this, 1, get); |
|
} |
|
|
|
|
|
|
|
|
|
computeN(deps, get) { |
|
if (this.isStatic) |
|
throw new Error("Can't compute a static facet"); |
|
return new FacetProvider(deps, this, 2, get); |
|
} |
|
from(field, get) { |
|
if (!get) |
|
get = (x) => x; |
|
return this.compute([field], (state) => get(state.field(field))); |
|
} |
|
}; |
|
function sameArray(a, b) { |
|
return a == b || a.length == b.length && a.every((e, i) => e === b[i]); |
|
} |
|
var FacetProvider = class { |
|
constructor(dependencies, facet, type, value) { |
|
this.dependencies = dependencies; |
|
this.facet = facet; |
|
this.type = type; |
|
this.value = value; |
|
this.id = nextID++; |
|
} |
|
dynamicSlot(addresses) { |
|
var _a; |
|
let getter = this.value; |
|
let compare2 = this.facet.compareInput; |
|
let id = this.id, idx = addresses[id] >> 1, multi = this.type == 2; |
|
let depDoc = false, depSel = false, depAddrs = []; |
|
for (let dep of this.dependencies) { |
|
if (dep == "doc") |
|
depDoc = true; |
|
else if (dep == "selection") |
|
depSel = true; |
|
else if ((((_a = addresses[dep.id]) !== null && _a !== void 0 ? _a : 1) & 1) == 0) |
|
depAddrs.push(addresses[dep.id]); |
|
} |
|
return { |
|
create(state) { |
|
state.values[idx] = getter(state); |
|
return 1; |
|
}, |
|
update(state, tr) { |
|
if (depDoc && tr.docChanged || depSel && (tr.docChanged || tr.selection) || ensureAll(state, depAddrs)) { |
|
let newVal = getter(state); |
|
if (multi ? !compareArray(newVal, state.values[idx], compare2) : !compare2(newVal, state.values[idx])) { |
|
state.values[idx] = newVal; |
|
return 1; |
|
} |
|
} |
|
return 0; |
|
}, |
|
reconfigure: (state, oldState) => { |
|
let newVal, oldAddr = oldState.config.address[id]; |
|
if (oldAddr != null) { |
|
let oldVal = getAddr(oldState, oldAddr); |
|
if (this.dependencies.every((dep) => { |
|
return dep instanceof Facet ? oldState.facet(dep) === state.facet(dep) : dep instanceof StateField ? oldState.field(dep, false) == state.field(dep, false) : true; |
|
}) || (multi ? compareArray(newVal = getter(state), oldVal, compare2) : compare2(newVal = getter(state), oldVal))) { |
|
state.values[idx] = oldVal; |
|
return 0; |
|
} |
|
} else { |
|
newVal = getter(state); |
|
} |
|
state.values[idx] = newVal; |
|
return 1; |
|
} |
|
}; |
|
} |
|
}; |
|
function compareArray(a, b, compare2) { |
|
if (a.length != b.length) |
|
return false; |
|
for (let i = 0; i < a.length; i++) |
|
if (!compare2(a[i], b[i])) |
|
return false; |
|
return true; |
|
} |
|
function ensureAll(state, addrs) { |
|
let changed = false; |
|
for (let addr of addrs) |
|
if (ensureAddr(state, addr) & 1) |
|
changed = true; |
|
return changed; |
|
} |
|
function dynamicFacetSlot(addresses, facet, providers) { |
|
let providerAddrs = providers.map((p) => addresses[p.id]); |
|
let providerTypes = providers.map((p) => p.type); |
|
let dynamic = providerAddrs.filter((p) => !(p & 1)); |
|
let idx = addresses[facet.id] >> 1; |
|
function get(state) { |
|
let values = []; |
|
for (let i = 0; i < providerAddrs.length; i++) { |
|
let value = getAddr(state, providerAddrs[i]); |
|
if (providerTypes[i] == 2) |
|
for (let val of value) |
|
values.push(val); |
|
else |
|
values.push(value); |
|
} |
|
return facet.combine(values); |
|
} |
|
return { |
|
create(state) { |
|
for (let addr of providerAddrs) |
|
ensureAddr(state, addr); |
|
state.values[idx] = get(state); |
|
return 1; |
|
}, |
|
update(state, tr) { |
|
if (!ensureAll(state, dynamic)) |
|
return 0; |
|
let value = get(state); |
|
if (facet.compare(value, state.values[idx])) |
|
return 0; |
|
state.values[idx] = value; |
|
return 1; |
|
}, |
|
reconfigure(state, oldState) { |
|
let depChanged = ensureAll(state, providerAddrs); |
|
let oldProviders = oldState.config.facets[facet.id], oldValue = oldState.facet(facet); |
|
if (oldProviders && !depChanged && sameArray(providers, oldProviders)) { |
|
state.values[idx] = oldValue; |
|
return 0; |
|
} |
|
let value = get(state); |
|
if (facet.compare(value, oldValue)) { |
|
state.values[idx] = oldValue; |
|
return 0; |
|
} |
|
state.values[idx] = value; |
|
return 1; |
|
} |
|
}; |
|
} |
|
var initField = Facet.define({ static: true }); |
|
var StateField = class _StateField { |
|
constructor(id, createF, updateF, compareF, spec) { |
|
this.id = id; |
|
this.createF = createF; |
|
this.updateF = updateF; |
|
this.compareF = compareF; |
|
this.spec = spec; |
|
this.provides = void 0; |
|
} |
|
|
|
|
|
|
|
static define(config) { |
|
let field = new _StateField(nextID++, config.create, config.update, config.compare || ((a, b) => a === b), config); |
|
if (config.provide) |
|
field.provides = config.provide(field); |
|
return field; |
|
} |
|
create(state) { |
|
let init = state.facet(initField).find((i) => i.field == this); |
|
return ((init === null || init === void 0 ? void 0 : init.create) || this.createF)(state); |
|
} |
|
|
|
|
|
|
|
slot(addresses) { |
|
let idx = addresses[this.id] >> 1; |
|
return { |
|
create: (state) => { |
|
state.values[idx] = this.create(state); |
|
return 1; |
|
}, |
|
update: (state, tr) => { |
|
let oldVal = state.values[idx]; |
|
let value = this.updateF(oldVal, tr); |
|
if (this.compareF(oldVal, value)) |
|
return 0; |
|
state.values[idx] = value; |
|
return 1; |
|
}, |
|
reconfigure: (state, oldState) => { |
|
if (oldState.config.address[this.id] != null) { |
|
state.values[idx] = oldState.field(this); |
|
return 0; |
|
} |
|
state.values[idx] = this.create(state); |
|
return 1; |
|
} |
|
}; |
|
} |
|
|
|
|
|
|
|
|
|
|
|
init(create) { |
|
return [this, initField.of({ field: this, create })]; |
|
} |
|
|
|
|
|
|
|
|
|
|
|
get extension() { |
|
return this; |
|
} |
|
}; |
|
var Prec_ = { lowest: 4, low: 3, default: 2, high: 1, highest: 0 }; |
|
function prec(value) { |
|
return (ext) => new PrecExtension(ext, value); |
|
} |
|
var Prec = { |
|
|
|
|
|
|
|
|
|
highest: prec(Prec_.highest), |
|
|
|
|
|
|
|
|
|
high: prec(Prec_.high), |
|
|
|
|
|
|
|
|
|
default: prec(Prec_.default), |
|
|
|
|
|
|
|
low: prec(Prec_.low), |
|
|
|
|
|
|
|
|
|
lowest: prec(Prec_.lowest) |
|
}; |
|
var PrecExtension = class { |
|
constructor(inner, prec2) { |
|
this.inner = inner; |
|
this.prec = prec2; |
|
} |
|
}; |
|
var Compartment = class _Compartment { |
|
|
|
|
|
|
|
|
|
of(ext) { |
|
return new CompartmentInstance(this, ext); |
|
} |
|
|
|
|
|
|
|
|
|
reconfigure(content) { |
|
return _Compartment.reconfigure.of({ compartment: this, extension: content }); |
|
} |
|
|
|
|
|
|
|
|
|
get(state) { |
|
return state.config.compartments.get(this); |
|
} |
|
}; |
|
var CompartmentInstance = class { |
|
constructor(compartment, inner) { |
|
this.compartment = compartment; |
|
this.inner = inner; |
|
} |
|
}; |
|
var Configuration = class _Configuration { |
|
constructor(base, compartments, dynamicSlots, address, staticValues, facets) { |
|
this.base = base; |
|
this.compartments = compartments; |
|
this.dynamicSlots = dynamicSlots; |
|
this.address = address; |
|
this.staticValues = staticValues; |
|
this.facets = facets; |
|
this.statusTemplate = []; |
|
while (this.statusTemplate.length < dynamicSlots.length) |
|
this.statusTemplate.push( |
|
0 |
|
|
|
); |
|
} |
|
staticFacet(facet) { |
|
let addr = this.address[facet.id]; |
|
return addr == null ? facet.default : this.staticValues[addr >> 1]; |
|
} |
|
static resolve(base, compartments, oldState) { |
|
let fields = []; |
|
let facets = Object.create(null); |
|
let newCompartments = new Map(); |
|
for (let ext of flatten(base, compartments, newCompartments)) { |
|
if (ext instanceof StateField) |
|
fields.push(ext); |
|
else |
|
(facets[ext.facet.id] || (facets[ext.facet.id] = [])).push(ext); |
|
} |
|
let address = Object.create(null); |
|
let staticValues = []; |
|
let dynamicSlots = []; |
|
for (let field of fields) { |
|
address[field.id] = dynamicSlots.length << 1; |
|
dynamicSlots.push((a) => field.slot(a)); |
|
} |
|
let oldFacets = oldState === null || oldState === void 0 ? void 0 : oldState.config.facets; |
|
for (let id in facets) { |
|
let providers = facets[id], facet = providers[0].facet; |
|
let oldProviders = oldFacets && oldFacets[id] || []; |
|
if (providers.every( |
|
(p) => p.type == 0 |
|
|
|
)) { |
|
address[facet.id] = staticValues.length << 1 | 1; |
|
if (sameArray(oldProviders, providers)) { |
|
staticValues.push(oldState.facet(facet)); |
|
} else { |
|
let value = facet.combine(providers.map((p) => p.value)); |
|
staticValues.push(oldState && facet.compare(value, oldState.facet(facet)) ? oldState.facet(facet) : value); |
|
} |
|
} else { |
|
for (let p of providers) { |
|
if (p.type == 0) { |
|
address[p.id] = staticValues.length << 1 | 1; |
|
staticValues.push(p.value); |
|
} else { |
|
address[p.id] = dynamicSlots.length << 1; |
|
dynamicSlots.push((a) => p.dynamicSlot(a)); |
|
} |
|
} |
|
address[facet.id] = dynamicSlots.length << 1; |
|
dynamicSlots.push((a) => dynamicFacetSlot(a, facet, providers)); |
|
} |
|
} |
|
let dynamic = dynamicSlots.map((f) => f(address)); |
|
return new _Configuration(base, newCompartments, dynamic, address, staticValues, facets); |
|
} |
|
}; |
|
function flatten(extension, compartments, newCompartments) { |
|
let result = [[], [], [], [], []]; |
|
let seen = new Map(); |
|
function inner(ext, prec2) { |
|
let known = seen.get(ext); |
|
if (known != null) { |
|
if (known <= prec2) |
|
return; |
|
let found = result[known].indexOf(ext); |
|
if (found > -1) |
|
result[known].splice(found, 1); |
|
if (ext instanceof CompartmentInstance) |
|
newCompartments.delete(ext.compartment); |
|
} |
|
seen.set(ext, prec2); |
|
if (Array.isArray(ext)) { |
|
for (let e of ext) |
|
inner(e, prec2); |
|
} else if (ext instanceof CompartmentInstance) { |
|
if (newCompartments.has(ext.compartment)) |
|
throw new RangeError(`Duplicate use of compartment in extensions`); |
|
let content = compartments.get(ext.compartment) || ext.inner; |
|
newCompartments.set(ext.compartment, content); |
|
inner(content, prec2); |
|
} else if (ext instanceof PrecExtension) { |
|
inner(ext.inner, ext.prec); |
|
} else if (ext instanceof StateField) { |
|
result[prec2].push(ext); |
|
if (ext.provides) |
|
inner(ext.provides, prec2); |
|
} else if (ext instanceof FacetProvider) { |
|
result[prec2].push(ext); |
|
if (ext.facet.extensions) |
|
inner(ext.facet.extensions, Prec_.default); |
|
} else { |
|
let content = ext.extension; |
|
if (!content) |
|
throw new Error(`Unrecognized extension value in extension set (${ext}). This sometimes happens because multiple instances of @codemirror/state are loaded, breaking instanceof checks.`); |
|
inner(content, prec2); |
|
} |
|
} |
|
inner(extension, Prec_.default); |
|
return result.reduce((a, b) => a.concat(b)); |
|
} |
|
function ensureAddr(state, addr) { |
|
if (addr & 1) |
|
return 2; |
|
let idx = addr >> 1; |
|
let status = state.status[idx]; |
|
if (status == 4) |
|
throw new Error("Cyclic dependency between fields and/or facets"); |
|
if (status & 2) |
|
return status; |
|
state.status[idx] = 4; |
|
let changed = state.computeSlot(state, state.config.dynamicSlots[idx]); |
|
return state.status[idx] = 2 | changed; |
|
} |
|
function getAddr(state, addr) { |
|
return addr & 1 ? state.config.staticValues[addr >> 1] : state.values[addr >> 1]; |
|
} |
|
var languageData = Facet.define(); |
|
var allowMultipleSelections = Facet.define({ |
|
combine: (values) => values.some((v) => v), |
|
static: true |
|
}); |
|
var lineSeparator = Facet.define({ |
|
combine: (values) => values.length ? values[0] : void 0, |
|
static: true |
|
}); |
|
var changeFilter = Facet.define(); |
|
var transactionFilter = Facet.define(); |
|
var transactionExtender = Facet.define(); |
|
var readOnly = Facet.define({ |
|
combine: (values) => values.length ? values[0] : false |
|
}); |
|
var Annotation = class { |
|
|
|
|
|
|
|
constructor(type, value) { |
|
this.type = type; |
|
this.value = value; |
|
} |
|
|
|
|
|
|
|
static define() { |
|
return new AnnotationType(); |
|
} |
|
}; |
|
var AnnotationType = class { |
|
|
|
|
|
|
|
of(value) { |
|
return new Annotation(this, value); |
|
} |
|
}; |
|
var StateEffectType = class { |
|
|
|
|
|
|
|
constructor(map) { |
|
this.map = map; |
|
} |
|
|
|
|
|
|
|
|
|
of(value) { |
|
return new StateEffect(this, value); |
|
} |
|
}; |
|
var StateEffect = class _StateEffect { |
|
|
|
|
|
|
|
constructor(type, value) { |
|
this.type = type; |
|
this.value = value; |
|
} |
|
|
|
|
|
|
|
|
|
map(mapping) { |
|
let mapped = this.type.map(this.value, mapping); |
|
return mapped === void 0 ? void 0 : mapped == this.value ? this : new _StateEffect(this.type, mapped); |
|
} |
|
|
|
|
|
|
|
|
|
is(type) { |
|
return this.type == type; |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static define(spec = {}) { |
|
return new StateEffectType(spec.map || ((v) => v)); |
|
} |
|
|
|
|
|
|
|
static mapEffects(effects, mapping) { |
|
if (!effects.length) |
|
return effects; |
|
let result = []; |
|
for (let effect of effects) { |
|
let mapped = effect.map(mapping); |
|
if (mapped) |
|
result.push(mapped); |
|
} |
|
return result; |
|
} |
|
}; |
|
StateEffect.reconfigure = StateEffect.define(); |
|
StateEffect.appendConfig = StateEffect.define(); |
|
var Transaction = class _Transaction { |
|
constructor(startState, changes, selection, effects, annotations, scrollIntoView) { |
|
this.startState = startState; |
|
this.changes = changes; |
|
this.selection = selection; |
|
this.effects = effects; |
|
this.annotations = annotations; |
|
this.scrollIntoView = scrollIntoView; |
|
this._doc = null; |
|
this._state = null; |
|
if (selection) |
|
checkSelection(selection, changes.newLength); |
|
if (!annotations.some((a) => a.type == _Transaction.time)) |
|
this.annotations = annotations.concat(_Transaction.time.of(Date.now())); |
|
} |
|
|
|
|
|
|
|
static create(startState, changes, selection, effects, annotations, scrollIntoView) { |
|
return new _Transaction(startState, changes, selection, effects, annotations, scrollIntoView); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
get newDoc() { |
|
return this._doc || (this._doc = this.changes.apply(this.startState.doc)); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
get newSelection() { |
|
return this.selection || this.startState.selection.map(this.changes); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
get state() { |
|
if (!this._state) |
|
this.startState.applyTransaction(this); |
|
return this._state; |
|
} |
|
|
|
|
|
|
|
annotation(type) { |
|
for (let ann of this.annotations) |
|
if (ann.type == type) |
|
return ann.value; |
|
return void 0; |
|
} |
|
|
|
|
|
|
|
get docChanged() { |
|
return !this.changes.empty; |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
get reconfigured() { |
|
return this.startState.config != this.state.config; |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
isUserEvent(event) { |
|
let e = this.annotation(_Transaction.userEvent); |
|
return !!(e && (e == event || e.length > event.length && e.slice(0, event.length) == event && e[event.length] == ".")); |
|
} |
|
}; |
|
Transaction.time = Annotation.define(); |
|
Transaction.userEvent = Annotation.define(); |
|
Transaction.addToHistory = Annotation.define(); |
|
Transaction.remote = Annotation.define(); |
|
function joinRanges(a, b) { |
|
let result = []; |
|
for (let iA = 0, iB = 0; ; ) { |
|
let from, to; |
|
if (iA < a.length && (iB == b.length || b[iB] >= a[iA])) { |
|
from = a[iA++]; |
|
to = a[iA++]; |
|
} else if (iB < b.length) { |
|
from = b[iB++]; |
|
to = b[iB++]; |
|
} else |
|
return result; |
|
if (!result.length || result[result.length - 1] < from) |
|
result.push(from, to); |
|
else if (result[result.length - 1] < to) |
|
result[result.length - 1] = to; |
|
} |
|
} |
|
function mergeTransaction(a, b, sequential) { |
|
var _a; |
|
let mapForA, mapForB, changes; |
|
if (sequential) { |
|
mapForA = b.changes; |
|
mapForB = ChangeSet.empty(b.changes.length); |
|
changes = a.changes.compose(b.changes); |
|
} else { |
|
mapForA = b.changes.map(a.changes); |
|
mapForB = a.changes.mapDesc(b.changes, true); |
|
changes = a.changes.compose(mapForA); |
|
} |
|
return { |
|
changes, |
|
selection: b.selection ? b.selection.map(mapForB) : (_a = a.selection) === null || _a === void 0 ? void 0 : _a.map(mapForA), |
|
effects: StateEffect.mapEffects(a.effects, mapForA).concat(StateEffect.mapEffects(b.effects, mapForB)), |
|
annotations: a.annotations.length ? a.annotations.concat(b.annotations) : b.annotations, |
|
scrollIntoView: a.scrollIntoView || b.scrollIntoView |
|
}; |
|
} |
|
function resolveTransactionInner(state, spec, docSize) { |
|
let sel = spec.selection, annotations = asArray(spec.annotations); |
|
if (spec.userEvent) |
|
annotations = annotations.concat(Transaction.userEvent.of(spec.userEvent)); |
|
return { |
|
changes: spec.changes instanceof ChangeSet ? spec.changes : ChangeSet.of(spec.changes || [], docSize, state.facet(lineSeparator)), |
|
selection: sel && (sel instanceof EditorSelection ? sel : EditorSelection.single(sel.anchor, sel.head)), |
|
effects: asArray(spec.effects), |
|
annotations, |
|
scrollIntoView: !!spec.scrollIntoView |
|
}; |
|
} |
|
function resolveTransaction(state, specs, filter) { |
|
let s = resolveTransactionInner(state, specs.length ? specs[0] : {}, state.doc.length); |
|
if (specs.length && specs[0].filter === false) |
|
filter = false; |
|
for (let i = 1; i < specs.length; i++) { |
|
if (specs[i].filter === false) |
|
filter = false; |
|
let seq = !!specs[i].sequential; |
|
s = mergeTransaction(s, resolveTransactionInner(state, specs[i], seq ? s.changes.newLength : state.doc.length), seq); |
|
} |
|
let tr = Transaction.create(state, s.changes, s.selection, s.effects, s.annotations, s.scrollIntoView); |
|
return extendTransaction(filter ? filterTransaction(tr) : tr); |
|
} |
|
function filterTransaction(tr) { |
|
let state = tr.startState; |
|
let result = true; |
|
for (let filter of state.facet(changeFilter)) { |
|
let value = filter(tr); |
|
if (value === false) { |
|
result = false; |
|
break; |
|
} |
|
if (Array.isArray(value)) |
|
result = result === true ? value : joinRanges(result, value); |
|
} |
|
if (result !== true) { |
|
let changes, back; |
|
if (result === false) { |
|
back = tr.changes.invertedDesc; |
|
changes = ChangeSet.empty(state.doc.length); |
|
} else { |
|
let filtered = tr.changes.filter(result); |
|
changes = filtered.changes; |
|
back = filtered.filtered.mapDesc(filtered.changes).invertedDesc; |
|
} |
|
tr = Transaction.create(state, changes, tr.selection && tr.selection.map(back), StateEffect.mapEffects(tr.effects, back), tr.annotations, tr.scrollIntoView); |
|
} |
|
let filters = state.facet(transactionFilter); |
|
for (let i = filters.length - 1; i >= 0; i--) { |
|
let filtered = filters[i](tr); |
|
if (filtered instanceof Transaction) |
|
tr = filtered; |
|
else if (Array.isArray(filtered) && filtered.length == 1 && filtered[0] instanceof Transaction) |
|
tr = filtered[0]; |
|
else |
|
tr = resolveTransaction(state, asArray(filtered), false); |
|
} |
|
return tr; |
|
} |
|
function extendTransaction(tr) { |
|
let state = tr.startState, extenders = state.facet(transactionExtender), spec = tr; |
|
for (let i = extenders.length - 1; i >= 0; i--) { |
|
let extension = extenders[i](tr); |
|
if (extension && Object.keys(extension).length) |
|
spec = mergeTransaction(spec, resolveTransactionInner(state, extension, tr.changes.newLength), true); |
|
} |
|
return spec == tr ? tr : Transaction.create(state, tr.changes, tr.selection, spec.effects, spec.annotations, spec.scrollIntoView); |
|
} |
|
var none = []; |
|
function asArray(value) { |
|
return value == null ? none : Array.isArray(value) ? value : [value]; |
|
} |
|
var CharCategory = function(CharCategory2) { |
|
CharCategory2[CharCategory2["Word"] = 0] = "Word"; |
|
CharCategory2[CharCategory2["Space"] = 1] = "Space"; |
|
CharCategory2[CharCategory2["Other"] = 2] = "Other"; |
|
return CharCategory2; |
|
}(CharCategory || (CharCategory = {})); |
|
var nonASCIISingleCaseWordChar = /[\u00df\u0587\u0590-\u05f4\u0600-\u06ff\u3040-\u309f\u30a0-\u30ff\u3400-\u4db5\u4e00-\u9fcc\uac00-\ud7af]/; |
|
var wordChar; |
|
try { |
|
wordChar = new RegExp("[\\p{Alphabetic}\\p{Number}_]", "u"); |
|
} catch (_) { |
|
} |
|
function hasWordChar(str) { |
|
if (wordChar) |
|
return wordChar.test(str); |
|
for (let i = 0; i < str.length; i++) { |
|
let ch = str[i]; |
|
if (/\w/.test(ch) || ch > "" && (ch.toUpperCase() != ch.toLowerCase() || nonASCIISingleCaseWordChar.test(ch))) |
|
return true; |
|
} |
|
return false; |
|
} |
|
function makeCategorizer(wordChars) { |
|
return (char) => { |
|
if (!/\S/.test(char)) |
|
return CharCategory.Space; |
|
if (hasWordChar(char)) |
|
return CharCategory.Word; |
|
for (let i = 0; i < wordChars.length; i++) |
|
if (char.indexOf(wordChars[i]) > -1) |
|
return CharCategory.Word; |
|
return CharCategory.Other; |
|
}; |
|
} |
|
var EditorState = class _EditorState { |
|
constructor(config, doc, selection, values, computeSlot, tr) { |
|
this.config = config; |
|
this.doc = doc; |
|
this.selection = selection; |
|
this.values = values; |
|
this.status = config.statusTemplate.slice(); |
|
this.computeSlot = computeSlot; |
|
if (tr) |
|
tr._state = this; |
|
for (let i = 0; i < this.config.dynamicSlots.length; i++) |
|
ensureAddr(this, i << 1); |
|
this.computeSlot = null; |
|
} |
|
field(field, require2 = true) { |
|
let addr = this.config.address[field.id]; |
|
if (addr == null) { |
|
if (require2) |
|
throw new RangeError("Field is not present in this state"); |
|
return void 0; |
|
} |
|
ensureAddr(this, addr); |
|
return getAddr(this, addr); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
update(...specs) { |
|
return resolveTransaction(this, specs, true); |
|
} |
|
|
|
|
|
|
|
applyTransaction(tr) { |
|
let conf = this.config, { base, compartments } = conf; |
|
for (let effect of tr.effects) { |
|
if (effect.is(Compartment.reconfigure)) { |
|
if (conf) { |
|
compartments = new Map(); |
|
conf.compartments.forEach((val, key) => compartments.set(key, val)); |
|
conf = null; |
|
} |
|
compartments.set(effect.value.compartment, effect.value.extension); |
|
} else if (effect.is(StateEffect.reconfigure)) { |
|
conf = null; |
|
base = effect.value; |
|
} else if (effect.is(StateEffect.appendConfig)) { |
|
conf = null; |
|
base = asArray(base).concat(effect.value); |
|
} |
|
} |
|
let startValues; |
|
if (!conf) { |
|
conf = Configuration.resolve(base, compartments, this); |
|
let intermediateState = new _EditorState(conf, this.doc, this.selection, conf.dynamicSlots.map(() => null), (state, slot) => slot.reconfigure(state, this), null); |
|
startValues = intermediateState.values; |
|
} else { |
|
startValues = tr.startState.values.slice(); |
|
} |
|
let selection = tr.startState.facet(allowMultipleSelections) ? tr.newSelection : tr.newSelection.asSingle(); |
|
new _EditorState(conf, tr.newDoc, selection, startValues, (state, slot) => slot.update(state, tr), tr); |
|
} |
|
|
|
|
|
|
|
|
|
replaceSelection(text) { |
|
if (typeof text == "string") |
|
text = this.toText(text); |
|
return this.changeByRange((range) => ({ |
|
changes: { from: range.from, to: range.to, insert: text }, |
|
range: EditorSelection.cursor(range.from + text.length) |
|
})); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
changeByRange(f) { |
|
let sel = this.selection; |
|
let result1 = f(sel.ranges[0]); |
|
let changes = this.changes(result1.changes), ranges = [result1.range]; |
|
let effects = asArray(result1.effects); |
|
for (let i = 1; i < sel.ranges.length; i++) { |
|
let result = f(sel.ranges[i]); |
|
let newChanges = this.changes(result.changes), newMapped = newChanges.map(changes); |
|
for (let j = 0; j < i; j++) |
|
ranges[j] = ranges[j].map(newMapped); |
|
let mapBy = changes.mapDesc(newChanges, true); |
|
ranges.push(result.range.map(mapBy)); |
|
changes = changes.compose(newMapped); |
|
effects = StateEffect.mapEffects(effects, newMapped).concat(StateEffect.mapEffects(asArray(result.effects), mapBy)); |
|
} |
|
return { |
|
changes, |
|
selection: EditorSelection.create(ranges, sel.mainIndex), |
|
effects |
|
}; |
|
} |
|
|
|
|
|
|
|
|
|
|
|
changes(spec = []) { |
|
if (spec instanceof ChangeSet) |
|
return spec; |
|
return ChangeSet.of(spec, this.doc.length, this.facet(_EditorState.lineSeparator)); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
toText(string) { |
|
return Text.of(string.split(this.facet(_EditorState.lineSeparator) || DefaultSplit)); |
|
} |
|
|
|
|
|
|
|
sliceDoc(from = 0, to = this.doc.length) { |
|
return this.doc.sliceString(from, to, this.lineBreak); |
|
} |
|
|
|
|
|
|
|
facet(facet) { |
|
let addr = this.config.address[facet.id]; |
|
if (addr == null) |
|
return facet.default; |
|
ensureAddr(this, addr); |
|
return getAddr(this, addr); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
toJSON(fields) { |
|
let result = { |
|
doc: this.sliceDoc(), |
|
selection: this.selection.toJSON() |
|
}; |
|
if (fields) |
|
for (let prop in fields) { |
|
let value = fields[prop]; |
|
if (value instanceof StateField && this.config.address[value.id] != null) |
|
result[prop] = value.spec.toJSON(this.field(fields[prop]), this); |
|
} |
|
return result; |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
static fromJSON(json, config = {}, fields) { |
|
if (!json || typeof json.doc != "string") |
|
throw new RangeError("Invalid JSON representation for EditorState"); |
|
let fieldInit = []; |
|
if (fields) |
|
for (let prop in fields) { |
|
if (Object.prototype.hasOwnProperty.call(json, prop)) { |
|
let field = fields[prop], value = json[prop]; |
|
fieldInit.push(field.init((state) => field.spec.fromJSON(value, state))); |
|
} |
|
} |
|
return _EditorState.create({ |
|
doc: json.doc, |
|
selection: EditorSelection.fromJSON(json.selection), |
|
extensions: config.extensions ? fieldInit.concat([config.extensions]) : fieldInit |
|
}); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
static create(config = {}) { |
|
let configuration = Configuration.resolve(config.extensions || [], new Map()); |
|
let doc = config.doc instanceof Text ? config.doc : Text.of((config.doc || "").split(configuration.staticFacet(_EditorState.lineSeparator) || DefaultSplit)); |
|
let selection = !config.selection ? EditorSelection.single(0) : config.selection instanceof EditorSelection ? config.selection : EditorSelection.single(config.selection.anchor, config.selection.head); |
|
checkSelection(selection, doc.length); |
|
if (!configuration.staticFacet(allowMultipleSelections)) |
|
selection = selection.asSingle(); |
|
return new _EditorState(configuration, doc, selection, configuration.dynamicSlots.map(() => null), (state, slot) => slot.create(state), null); |
|
} |
|
|
|
|
|
|
|
|
|
get tabSize() { |
|
return this.facet(_EditorState.tabSize); |
|
} |
|
|
|
|
|
|
|
|
|
get lineBreak() { |
|
return this.facet(_EditorState.lineSeparator) || "\n"; |
|
} |
|
|
|
|
|
|
|
|
|
get readOnly() { |
|
return this.facet(readOnly); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
phrase(phrase, ...insert2) { |
|
for (let map of this.facet(_EditorState.phrases)) |
|
if (Object.prototype.hasOwnProperty.call(map, phrase)) { |
|
phrase = map[phrase]; |
|
break; |
|
} |
|
if (insert2.length) |
|
phrase = phrase.replace(/\$(\$|\d*)/g, (m, i) => { |
|
if (i == "$") |
|
return "$"; |
|
let n = +(i || 1); |
|
return !n || n > insert2.length ? m : insert2[n - 1]; |
|
}); |
|
return phrase; |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
languageDataAt(name, pos, side = -1) { |
|
let values = []; |
|
for (let provider of this.facet(languageData)) { |
|
for (let result of provider(this, pos, side)) { |
|
if (Object.prototype.hasOwnProperty.call(result, name)) |
|
values.push(result[name]); |
|
} |
|
} |
|
return values; |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
charCategorizer(at) { |
|
return makeCategorizer(this.languageDataAt("wordChars", at).join("")); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
wordAt(pos) { |
|
let { text, from, length } = this.doc.lineAt(pos); |
|
let cat = this.charCategorizer(pos); |
|
let start = pos - from, end = pos - from; |
|
while (start > 0) { |
|
let prev = findClusterBreak(text, start, false); |
|
if (cat(text.slice(prev, start)) != CharCategory.Word) |
|
break; |
|
start = prev; |
|
} |
|
while (end < length) { |
|
let next = findClusterBreak(text, end); |
|
if (cat(text.slice(end, next)) != CharCategory.Word) |
|
break; |
|
end = next; |
|
} |
|
return start == end ? null : EditorSelection.range(start + from, end + from); |
|
} |
|
}; |
|
EditorState.allowMultipleSelections = allowMultipleSelections; |
|
EditorState.tabSize = Facet.define({ |
|
combine: (values) => values.length ? values[0] : 4 |
|
}); |
|
EditorState.lineSeparator = lineSeparator; |
|
EditorState.readOnly = readOnly; |
|
EditorState.phrases = Facet.define({ |
|
compare(a, b) { |
|
let kA = Object.keys(a), kB = Object.keys(b); |
|
return kA.length == kB.length && kA.every((k) => a[k] == b[k]); |
|
} |
|
}); |
|
EditorState.languageData = languageData; |
|
EditorState.changeFilter = changeFilter; |
|
EditorState.transactionFilter = transactionFilter; |
|
EditorState.transactionExtender = transactionExtender; |
|
Compartment.reconfigure = StateEffect.define(); |
|
function combineConfig(configs, defaults, combine = {}) { |
|
let result = {}; |
|
for (let config of configs) |
|
for (let key of Object.keys(config)) { |
|
let value = config[key], current = result[key]; |
|
if (current === void 0) |
|
result[key] = value; |
|
else if (current === value || value === void 0) ; |
|
else if (Object.hasOwnProperty.call(combine, key)) |
|
result[key] = combine[key](current, value); |
|
else |
|
throw new Error("Config merge conflict for field " + key); |
|
} |
|
for (let key in defaults) |
|
if (result[key] === void 0) |
|
result[key] = defaults[key]; |
|
return result; |
|
} |
|
var RangeValue = class { |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
eq(other) { |
|
return this == other; |
|
} |
|
|
|
|
|
|
|
range(from, to = from) { |
|
return Range.create(from, to, this); |
|
} |
|
}; |
|
RangeValue.prototype.startSide = RangeValue.prototype.endSide = 0; |
|
RangeValue.prototype.point = false; |
|
RangeValue.prototype.mapMode = MapMode.TrackDel; |
|
var Range = class _Range { |
|
constructor(from, to, value) { |
|
this.from = from; |
|
this.to = to; |
|
this.value = value; |
|
} |
|
|
|
|
|
|
|
static create(from, to, value) { |
|
return new _Range(from, to, value); |
|
} |
|
}; |
|
function cmpRange(a, b) { |
|
return a.from - b.from || a.value.startSide - b.value.startSide; |
|
} |
|
var Chunk = class _Chunk { |
|
constructor(from, to, value, maxPoint) { |
|
this.from = from; |
|
this.to = to; |
|
this.value = value; |
|
this.maxPoint = maxPoint; |
|
} |
|
get length() { |
|
return this.to[this.to.length - 1]; |
|
} |
|
|
|
|
|
findIndex(pos, side, end, startAt = 0) { |
|
let arr = end ? this.to : this.from; |
|
for (let lo = startAt, hi = arr.length; ; ) { |
|
if (lo == hi) |
|
return lo; |
|
let mid = lo + hi >> 1; |
|
let diff = arr[mid] - pos || (end ? this.value[mid].endSide : this.value[mid].startSide) - side; |
|
if (mid == lo) |
|
return diff >= 0 ? lo : hi; |
|
if (diff >= 0) |
|
hi = mid; |
|
else |
|
lo = mid + 1; |
|
} |
|
} |
|
between(offset, from, to, f) { |
|
for (let i = this.findIndex(from, -1e9, true), e = this.findIndex(to, 1e9, false, i); i < e; i++) |
|
if (f(this.from[i] + offset, this.to[i] + offset, this.value[i]) === false) |
|
return false; |
|
} |
|
map(offset, changes) { |
|
let value = [], from = [], to = [], newPos = -1, maxPoint = -1; |
|
for (let i = 0; i < this.value.length; i++) { |
|
let val = this.value[i], curFrom = this.from[i] + offset, curTo = this.to[i] + offset, newFrom, newTo; |
|
if (curFrom == curTo) { |
|
let mapped = changes.mapPos(curFrom, val.startSide, val.mapMode); |
|
if (mapped == null) |
|
continue; |
|
newFrom = newTo = mapped; |
|
if (val.startSide != val.endSide) { |
|
newTo = changes.mapPos(curFrom, val.endSide); |
|
if (newTo < newFrom) |
|
continue; |
|
} |
|
} else { |
|
newFrom = changes.mapPos(curFrom, val.startSide); |
|
newTo = changes.mapPos(curTo, val.endSide); |
|
if (newFrom > newTo || newFrom == newTo && val.startSide > 0 && val.endSide <= 0) |
|
continue; |
|
} |
|
if ((newTo - newFrom || val.endSide - val.startSide) < 0) |
|
continue; |
|
if (newPos < 0) |
|
newPos = newFrom; |
|
if (val.point) |
|
maxPoint = Math.max(maxPoint, newTo - newFrom); |
|
value.push(val); |
|
from.push(newFrom - newPos); |
|
to.push(newTo - newPos); |
|
} |
|
return { mapped: value.length ? new _Chunk(from, to, value, maxPoint) : null, pos: newPos }; |
|
} |
|
}; |
|
var RangeSet = class _RangeSet { |
|
constructor(chunkPos, chunk, nextLayer, maxPoint) { |
|
this.chunkPos = chunkPos; |
|
this.chunk = chunk; |
|
this.nextLayer = nextLayer; |
|
this.maxPoint = maxPoint; |
|
} |
|
|
|
|
|
|
|
static create(chunkPos, chunk, nextLayer, maxPoint) { |
|
return new _RangeSet(chunkPos, chunk, nextLayer, maxPoint); |
|
} |
|
|
|
|
|
|
|
get length() { |
|
let last = this.chunk.length - 1; |
|
return last < 0 ? 0 : Math.max(this.chunkEnd(last), this.nextLayer.length); |
|
} |
|
|
|
|
|
|
|
get size() { |
|
if (this.isEmpty) |
|
return 0; |
|
let size = this.nextLayer.size; |
|
for (let chunk of this.chunk) |
|
size += chunk.value.length; |
|
return size; |
|
} |
|
|
|
|
|
|
|
chunkEnd(index) { |
|
return this.chunkPos[index] + this.chunk[index].length; |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
update(updateSpec) { |
|
let { add = [], sort = false, filterFrom = 0, filterTo = this.length } = updateSpec; |
|
let filter = updateSpec.filter; |
|
if (add.length == 0 && !filter) |
|
return this; |
|
if (sort) |
|
add = add.slice().sort(cmpRange); |
|
if (this.isEmpty) |
|
return add.length ? _RangeSet.of(add) : this; |
|
let cur = new LayerCursor(this, null, -1).goto(0), i = 0, spill = []; |
|
let builder = new RangeSetBuilder(); |
|
while (cur.value || i < add.length) { |
|
if (i < add.length && (cur.from - add[i].from || cur.startSide - add[i].value.startSide) >= 0) { |
|
let range = add[i++]; |
|
if (!builder.addInner(range.from, range.to, range.value)) |
|
spill.push(range); |
|
} else if (cur.rangeIndex == 1 && cur.chunkIndex < this.chunk.length && (i == add.length || this.chunkEnd(cur.chunkIndex) < add[i].from) && (!filter || filterFrom > this.chunkEnd(cur.chunkIndex) || filterTo < this.chunkPos[cur.chunkIndex]) && builder.addChunk(this.chunkPos[cur.chunkIndex], this.chunk[cur.chunkIndex])) { |
|
cur.nextChunk(); |
|
} else { |
|
if (!filter || filterFrom > cur.to || filterTo < cur.from || filter(cur.from, cur.to, cur.value)) { |
|
if (!builder.addInner(cur.from, cur.to, cur.value)) |
|
spill.push(Range.create(cur.from, cur.to, cur.value)); |
|
} |
|
cur.next(); |
|
} |
|
} |
|
return builder.finishInner(this.nextLayer.isEmpty && !spill.length ? _RangeSet.empty : this.nextLayer.update({ add: spill, filter, filterFrom, filterTo })); |
|
} |
|
|
|
|
|
|
|
map(changes) { |
|
if (changes.empty || this.isEmpty) |
|
return this; |
|
let chunks = [], chunkPos = [], maxPoint = -1; |
|
for (let i = 0; i < this.chunk.length; i++) { |
|
let start = this.chunkPos[i], chunk = this.chunk[i]; |
|
let touch = changes.touchesRange(start, start + chunk.length); |
|
if (touch === false) { |
|
maxPoint = Math.max(maxPoint, chunk.maxPoint); |
|
chunks.push(chunk); |
|
chunkPos.push(changes.mapPos(start)); |
|
} else if (touch === true) { |
|
let { mapped, pos } = chunk.map(start, changes); |
|
if (mapped) { |
|
maxPoint = Math.max(maxPoint, mapped.maxPoint); |
|
chunks.push(mapped); |
|
chunkPos.push(pos); |
|
} |
|
} |
|
} |
|
let next = this.nextLayer.map(changes); |
|
return chunks.length == 0 ? next : new _RangeSet(chunkPos, chunks, next || _RangeSet.empty, maxPoint); |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
between(from, to, f) { |
|
if (this.isEmpty) |
|
return; |
|
for (let i = 0; i < this.chunk.length; i++) { |
|
let start = this.chunkPos[i], chunk = this.chunk[i]; |
|
if (to >= start && from <= start + chunk.length && chunk.between(start, from - start, to - start, f) === false) |
|
return; |
|
} |
|
this.nextLayer.between(from, to, f); |
|
} |
|
|
|
|
|
|
|
|
|
iter(from = 0) { |
|
return HeapCursor.from([this]).goto(from); |
|
} |
|
|
|
|
|
|
|
get isEmpty() { |
|
return this.nextLayer == this; |
|
} |
|
|
|
|
|
|
|
|
|
static iter(sets, from = 0) { |
|
return HeapCursor.from(sets).goto(from); |
|
} |
|
|
|
|
|
|
|
|
|
static compare(oldSets, newSets, textDiff, comparator, minPointSize = -1) { |
|
let a = oldSets.filter((set) => set.maxPoint > 0 || !set.isEmpty && set.maxPoint >= minPointSize); |
|
let b = newSets.filter((set) => set.maxPoint > 0 || !set.isEmpty && set.maxPoint >= minPointSize); |
|
let sharedChunks = findSharedChunks(a, b, textDiff); |
|
let sideA = new SpanCursor(a, sharedChunks, minPointSize); |
|
let sideB = new SpanCursor(b, sharedChunks, minPointSize); |
|
textDiff.iterGaps((fromA, fromB, length) => compare(sideA, fromA, sideB, fromB, length, comparator)); |
|
if (textDiff.empty && textDiff.length == 0) |
|
compare(sideA, 0, sideB, 0, 0, comparator); |
|
} |
|
|
|
|
|
|
|
|
|
static eq(oldSets, newSets, from = 0, to) { |
|
if (to == null) |
|
to = 1e9 - 1; |
|
let a = oldSets.filter((set) => !set.isEmpty && newSets.indexOf(set) < 0); |
|
let b = newSets.filter((set) => !set.isEmpty && oldSets.indexOf(set) < 0); |
|
if (a.length != b.length) |
|
return false; |
|
if (!a.length) |
|
return true; |
|
let sharedChunks = findSharedChunks(a, b); |
|
let sideA = new SpanCursor(a, sharedChunks, 0).goto(from), sideB = new SpanCursor(b, sharedChunks, 0).goto(from); |
|
for (; ; ) { |
|
if (sideA.to != sideB.to || !sameValues(sideA.active, sideB.active) || sideA.point && (!sideB.point || !sideA.point.eq(sideB.point))) |
|
return false; |
|
if (sideA.to > to) |
|
return true; |
|
sideA.next(); |
|
sideB.next(); |
|
} |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static spans(sets, from, to, iterator, minPointSize = -1) { |
|
let cursor = new SpanCursor(sets, null, minPointSize).goto(from), pos = from; |
|
let openRanges = cursor.openStart; |
|
for (; ; ) { |
|
let curTo = Math.min(cursor.to, to); |
|
if (cursor.point) { |
|
let active = cursor.activeForPoint(cursor.to); |
|
let openCount = cursor.pointFrom < from ? active.length + 1 : cursor.point.startSide < 0 ? active.length : Math.min(active.length, openRanges); |
|
iterator.point(pos, curTo, cursor.point, active, openCount, cursor.pointRank); |
|
openRanges = Math.min(cursor.openEnd(curTo), active.length); |
|
} else if (curTo > pos) { |
|
iterator.span(pos, curTo, cursor.active, openRanges); |
|
openRanges = cursor.openEnd(curTo); |
|
} |
|
if (cursor.to > to) |
|
return openRanges + (cursor.point && cursor.to > to ? 1 : 0); |
|
pos = cursor.to; |
|
cursor.next(); |
|
} |
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static of(ranges, sort = false) { |
|
let build = new RangeSetBuilder(); |
|
for (let range of ranges instanceof Range ? [ranges] : sort ? lazySort(ranges) : ranges) |
|
build.add(range.from, range.to, range.value); |
|
return build.finish(); |
|
} |
|
|
|
|
|
|
|
static join(sets) { |
|
if (!sets.length) |
|
return _RangeSet.empty; |
|
let result = sets[sets.length - 1]; |
|
for (let i = sets.length - 2; i >= 0; i--) { |
|
for (let layer = sets[i]; layer != _RangeSet.empty; layer = layer.nextLayer) |
|
result = new _RangeSet(layer.chunkPos, layer.chunk, result, Math.max(layer.maxPoint, result.maxPoint)); |
|
} |
|
return result; |
|
} |
|
}; |
|
RangeSet.empty = new RangeSet([], [], null, -1); |
|
function lazySort(ranges) { |
|
if (ranges.length > 1) |
|
for (let prev = ranges[0], i = 1; i < ranges.length; i++) { |
|
let cur = ranges[i]; |
|
if (cmpRange(prev, cur) > 0) |
|
return ranges.slice().sort(cmpRange); |
|
prev = cur; |
|
} |
|
return ranges; |
|
} |
|
RangeSet.empty.nextLayer = RangeSet.empty; |
|
var RangeSetBuilder = class _RangeSetBuilder { |
|
finishChunk(newArrays) { |
|
this.chunks.push(new Chunk(this.from, this.to, this.value, this.maxPoint)); |
|
this.chunkPos.push(this.chunkStart); |
|
this.chunkStart = -1; |
|
this.setMaxPoint = Math.max(this.setMaxPoint, this.maxPoint); |
|
this.maxPoint = -1; |
|
if (newArrays) { |
|
this.from = []; |
|
this.to = []; |
|
this.value = []; |
|
} |
|
} |
|
|
|
|
|
|
|
constructor() { |
|
this.chunks = []; |
|
this.chunkPos = []; |
|
this.chunkStart = -1; |
|
this.last = null; |
|
this.lastFrom = -1e9; |
|
this.lastTo = -1e9; |
|
this.from = []; |
|
this.to = []; |
|
this.value = []; |
|
this.maxPoint = -1; |
|
this.setMaxPoint = -1; |
|
this.nextLayer = null; |
|
} |
|
|
|
|
|
|
|
|
|
add(from, to, value) { |
|
if (!this.addInner(from, to, value)) |
|
(this.nextLayer || (this.nextLayer = new _RangeSetBuilder())).add(from, to, value); |
|
} |
|
|
|
|
|
|
|
addInner(from, to, value) { |
|
let diff = from - this.lastTo || value.startSide - this.last.endSide; |
|
if (diff <= 0 && (from - this.lastFrom || value.startSide - this.last.startSide) < 0) |
|
throw new Error("Ranges must be added sorted by `from` position and `startSide`"); |
|
if (diff < 0) |
|
return false; |
|
if (this.from.length == 250) |
|
this.finishChunk(true); |
|
if (this.chunkStart < 0) |
|
this.chunkStart = from; |
|
this.from.push(from - this.chunkStart); |
|
this.to.push(to - this.chunkStart); |
|
this.last = value; |
|
this.lastFrom = from; |
|
this.lastTo = to; |
|
this.value.push(value); |
|
if (value.point) |
|
this.maxPoint = Math.max(this.maxPoint, to - from); |
|
return true; |
|
} |
|
|
|
|
|
|
|
addChunk(from, chunk) { |
|
if ((from - this.lastTo || chunk.value[0].startSide - this.last.endSide) < 0) |
|
return false; |
|
if (this.from.length) |
|
this.finishChunk(true); |
|
this.setMaxPoint = Math.max(this.setMaxPoint, chunk.maxPoint); |
|
this.chunks.push(chunk); |
|
this.chunkPos.push(from); |
|
let last = chunk.value.length - 1; |
|
this.last = chunk.value[last]; |
|
this.lastFrom = chunk.from[last] + from; |
|
this.lastTo = chunk.to[last] + from; |
|
return true; |
|
} |
|
|
|
|
|
|
|
|
|
finish() { |
|
return this.finishInner(RangeSet.empty); |
|
} |
|
|
|
|
|
|
|
finishInner(next) { |
|
if (this.from.length) |
|
this.finishChunk(false); |
|
if (this.chunks.length == 0) |
|
return next; |
|
let result = RangeSet.create(this.chunkPos, this.chunks, this.nextLayer ? this.nextLayer.finishInner(next) : next, this.setMaxPoint); |
|
this.from = null; |
|
return result; |
|
} |
|
}; |
|
function findSharedChunks(a, b, textDiff) { |
|
let inA = new Map(); |
|
for (let set of a) |
|
for (let i = 0; i < set.chunk.length; i++) |
|
if (set.chunk[i].maxPoint <= 0) |
|
inA.set(set.chunk[i], set.chunkPos[i]); |
|
let shared = new Set(); |
|
for (let set of b) |
|
for (let i = 0; i < set.chunk.length; i++) { |
|
let known = inA.get(set.chunk[i]); |
|
if (known != null && (textDiff ? textDiff.mapPos(known) : known) == set.chunkPos[i] && !(textDiff === null || textDiff === void 0 ? void 0 : textDiff.touchesRange(known, known + set.chunk[i].length))) |
|
shared.add(set.chunk[i]); |
|
} |
|
return shared; |
|
} |
|
var LayerCursor = class { |
|
constructor(layer, skip, minPoint, rank = 0) { |
|
this.layer = layer; |
|
this.skip = skip; |
|
this.minPoint = minPoint; |
|
this.rank = rank; |
|
} |
|
get startSide() { |
|
return this.value ? this.value.startSide : 0; |
|
} |
|
get endSide() { |
|
return this.value ? this.value.endSide : 0; |
|
} |
|
goto(pos, side = -1e9) { |
|
this.chunkIndex = this.rangeIndex = 0; |
|
this.gotoInner(pos, side, false); |
|
return this; |
|
} |
|
gotoInner(pos, side, forward) { |
|
while (this.chunkIndex < this.layer.chunk.length) { |
|
let next = this.layer.chunk[this.chunkIndex]; |
|
if (!(this.skip && this.skip.has(next) || this.layer.chunkEnd(this.chunkIndex) < pos || next.maxPoint < this.minPoint)) |
|
break; |
|
this.chunkIndex++; |
|
forward = false; |
|
} |
|
if (this.chunkIndex < this.layer.chunk.length) { |
|
let rangeIndex = this.layer.chunk[this.chunkIndex].findIndex(pos - this.layer.chunkPos[this.chunkIndex], side, true); |
|
if (!forward || this.rangeIndex < rangeIndex) |
|
this.setRangeIndex(rangeIndex); |
|
} |
|
this.next(); |
|
} |
|
forward(pos, side) { |
|
if ((this.to - pos || this.endSide - side) < 0) |
|
this.gotoInner(pos, side, true); |
|
} |
|
next() { |
|
for (; ; ) { |
|
if (this.chunkIndex == this.layer.chunk.length) { |
|
this.from = this.to = 1e9; |
|
this.value = null; |
|
break; |
|
} else { |
|
let chunkPos = this.layer.chunkPos[this.chunkIndex], chunk = this.layer.chunk[this.chunkIndex]; |
|
let from = chunkPos + chunk.from[this.rangeIndex]; |
|
this.from = from; |
|
this.to = chunkPos + chunk.to[this.rangeIndex]; |
|
this.value = chunk.value[this.rangeIndex]; |
|
this.setRangeIndex(this.rangeIndex + 1); |
|
if (this.minPoint < 0 || this.value.point && this.to - this.from >= this.minPoint) |
|
break; |
|
} |
|
} |
|
} |
|
setRangeIndex(index) { |
|
if (index == this.layer.chunk[this.chunkIndex].value.length) { |
|
this.chunkIndex++; |
|
if (this.skip) { |
|
while (this.chunkIndex < this.layer.chunk.length && this.skip.has(this.layer.chunk[this.chunkIndex])) |
|
this.chunkIndex++; |
|
} |
|
this.rangeIndex = 0; |
|
} else { |
|
this.rangeIndex = index; |
|
} |
|
} |
|
nextChunk() { |
|
this.chunkIndex++; |
|
this.rangeIndex = 0; |
|
this.next(); |
|
} |
|
compare(other) { |
|
return this.from - other.from || this.startSide - other.startSide || this.rank - other.rank || this.to - other.to || this.endSide - other.endSide; |
|
} |
|
}; |
|
var HeapCursor = class _HeapCursor { |
|
constructor(heap) { |
|
this.heap = heap; |
|
} |
|
static from(sets, skip = null, minPoint = -1) { |
|
let heap = []; |
|
for (let i = 0; i < sets.length; i++) { |
|
for (let cur = sets[i]; !cur.isEmpty; cur = cur.nextLayer) { |
|
if (cur.maxPoint >= minPoint) |
|
heap.push(new LayerCursor(cur, skip, minPoint, i)); |
|
} |
|
} |
|
return heap.length == 1 ? heap[0] : new _HeapCursor(heap); |
|
} |
|
get startSide() { |
|
return this.value ? this.value.startSide : 0; |
|
} |
|
goto(pos, side = -1e9) { |
|
for (let cur of this.heap) |
|
cur.goto(pos, side); |
|
for (let i = this.heap.length >> 1; i >= 0; i--) |
|
heapBubble(this.heap, i); |
|
this.next(); |
|
return this; |
|
} |
|
forward(pos, side) { |
|
for (let cur of this.heap) |
|
cur.forward(pos, side); |
|
for (let i = this.heap.length >> 1; i >= 0; i--) |
|
heapBubble(this.heap, i); |
|
if ((this.to - pos || this.value.endSide - side) < 0) |
|
this.next(); |
|
} |
|
next() { |
|
if (this.heap.length == 0) { |
|
this.from = this.to = 1e9; |
|
this.value = null; |
|
this.rank = -1; |
|
} else { |
|
let top = this.heap[0]; |
|
this.from = top.from; |
|
this.to = top.to; |
|
this.value = top.value; |
|
this.rank = top.rank; |
|
if (top.value) |
|
top.next(); |
|
heapBubble(this.heap, 0); |
|
} |
|
} |
|
}; |
|
function heapBubble(heap, index) { |
|
for (let cur = heap[index]; ; ) { |
|
let childIndex = (index << 1) + 1; |
|
if (childIndex >= heap.length) |
|
break; |
|
let child = heap[childIndex]; |
|
if (childIndex + 1 < heap.length && child.compare(heap[childIndex + 1]) >= 0) { |
|
child = heap[childIndex + 1]; |
|
childIndex++; |
|
} |
|
if (cur.compare(child) < 0) |
|
break; |
|
heap[childIndex] = cur; |
|
heap[index] = child; |
|
index = childIndex; |
|
} |
|
} |
|
var SpanCursor = class { |
|
constructor(sets, skip, minPoint) { |
|
this.minPoint = minPoint; |
|
this.active = []; |
|
this.activeTo = []; |
|
this.activeRank = []; |
|
this.minActive = -1; |
|
this.point = null; |
|
this.pointFrom = 0; |
|
this.pointRank = 0; |
|
this.to = -1e9; |
|
this.endSide = 0; |
|
this.openStart = -1; |
|
this.cursor = HeapCursor.from(sets, skip, minPoint); |
|
} |
|
goto(pos, side = -1e9) { |
|
this.cursor.goto(pos, side); |
|
this.active.length = this.activeTo.length = this.activeRank.length = 0; |
|
this.minActive = -1; |
|
this.to = pos; |
|
this.endSide = side; |
|
this.openStart = -1; |
|
this.next(); |
|
return this; |
|
} |
|
forward(pos, side) { |
|
while (this.minActive > -1 && (this.activeTo[this.minActive] - pos || this.active[this.minActive].endSide - side) < 0) |
|
this.removeActive(this.minActive); |
|
this.cursor.forward(pos, side); |
|
} |
|
removeActive(index) { |
|
remove(this.active, index); |
|
remove(this.activeTo, index); |
|
remove(this.activeRank, index); |
|
this.minActive = findMinIndex(this.active, this.activeTo); |
|
} |
|
addActive(trackOpen) { |
|
let i = 0, { value, to, rank } = this.cursor; |
|
while (i < this.activeRank.length && (rank - this.activeRank[i] || to - this.activeTo[i]) > 0) |
|
i++; |
|
insert(this.active, i, value); |
|
insert(this.activeTo, i, to); |
|
insert(this.activeRank, i, rank); |
|
if (trackOpen) |
|
insert(trackOpen, i, this.cursor.from); |
|
this.minActive = findMinIndex(this.active, this.activeTo); |
|
} |
|
|
|
|
|
next() { |
|
let from = this.to, wasPoint = this.point; |
|
this.point = null; |
|
let trackOpen = this.openStart < 0 ? [] : null; |
|
for (; ; ) { |
|
let a = this.minActive; |
|
if (a > -1 && (this.activeTo[a] - this.cursor.from || this.active[a].endSide - this.cursor.startSide) < 0) { |
|
if (this.activeTo[a] > from) { |
|
this.to = this.activeTo[a]; |
|
this.endSide = this.active[a].endSide; |
|
break; |
|
} |
|
this.removeActive(a); |
|
if (trackOpen) |
|
remove(trackOpen, a); |
|
} else if (!this.cursor.value) { |
|
this.to = this.endSide = 1e9; |
|
break; |
|
} else if (this.cursor.from > from) { |
|
this.to = this.cursor.from; |
|
this.endSide = this.cursor.startSide; |
|
break; |
|
} else { |
|
let nextVal = this.cursor.value; |
|
if (!nextVal.point) { |
|
this.addActive(trackOpen); |
|
this.cursor.next(); |
|
} else if (wasPoint && this.cursor.to == this.to && this.cursor.from < this.cursor.to) { |
|
this.cursor.next(); |
|
} else { |
|
this.point = nextVal; |
|
this.pointFrom = this.cursor.from; |
|
this.pointRank = this.cursor.rank; |
|
this.to = this.cursor.to; |
|
this.endSide = nextVal.endSide; |
|
this.cursor.next(); |
|
this.forward(this.to, this.endSide); |
|
break; |
|
} |
|
} |
|
} |
|
if (trackOpen) { |
|
this.openStart = 0; |
|
for (let i = trackOpen.length - 1; i >= 0 && trackOpen[i] < from; i--) |
|
this.openStart++; |
|
} |
|
} |
|
activeForPoint(to) { |
|
if (!this.active.length) |
|
return this.active; |
|
let active = []; |
|
for (let i = this.active.length - 1; i >= 0; i--) { |
|
if (this.activeRank[i] < this.pointRank) |
|
break; |
|
if (this.activeTo[i] > to || this.activeTo[i] == to && this.active[i].endSide >= this.point.endSide) |
|
active.push(this.active[i]); |
|
} |
|
return active.reverse(); |
|
} |
|
openEnd(to) { |
|
let open = 0; |
|
for (let i = this.activeTo.length - 1; i >= 0 && this.activeTo[i] > to; i--) |
|
open++; |
|
return open; |
|
} |
|
}; |
|
function compare(a, startA, b, startB, length, comparator) { |
|
a.goto(startA); |
|
b.goto(startB); |
|
let endB = startB + length; |
|
let pos = startB, dPos = startB - startA; |
|
for (; ; ) { |
|
let diff = a.to + dPos - b.to || a.endSide - b.endSide; |
|
let end = diff < 0 ? a.to + dPos : b.to, clipEnd = Math.min(end, endB); |
|
if (a.point || b.point) { |
|
if (!(a.point && b.point && (a.point == b.point || a.point.eq(b.point)) && sameValues(a.activeForPoint(a.to), b.activeForPoint(b.to)))) |
|
comparator.comparePoint(pos, clipEnd, a.point, b.point); |
|
} else { |
|
if (clipEnd > pos && !sameValues(a.active, b.active)) |
|
comparator.compareRange(pos, clipEnd, a.active, b.active); |
|
} |
|
if (end > endB) |
|
break; |
|
pos = end; |
|
if (diff <= 0) |
|
a.next(); |
|
if (diff >= 0) |
|
b.next(); |
|
} |
|
} |
|
function sameValues(a, b) { |
|
if (a.length != b.length) |
|
return false; |
|
for (let i = 0; i < a.length; i++) |
|
if (a[i] != b[i] && !a[i].eq(b[i])) |
|
return false; |
|
return true; |
|
} |
|
function remove(array, index) { |
|
for (let i = index, e = array.length - 1; i < e; i++) |
|
array[i] = array[i + 1]; |
|
array.pop(); |
|
} |
|
function insert(array, index, value) { |
|
for (let i = array.length - 1; i >= index; i--) |
|
array[i + 1] = array[i]; |
|
array[index] = value; |
|
} |
|
function findMinIndex(value, array) { |
|
let found = -1, foundPos = 1e9; |
|
for (let i = 0; i < array.length; i++) |
|
if ((array[i] - foundPos || value[i].endSide - value[found].endSide) < 0) { |
|
found = i; |
|
foundPos = array[i]; |
|
} |
|
return found; |
|
} |
|
function countColumn(string, tabSize, to = string.length) { |
|
let n = 0; |
|
for (let i = 0; i < to; ) { |
|
if (string.charCodeAt(i) == 9) { |
|
n += tabSize - n % tabSize; |
|
i++; |
|
} else { |
|
n++; |
|
i = findClusterBreak(string, i); |
|
} |
|
} |
|
return n; |
|
} |
|
function findColumn(string, col, tabSize, strict) { |
|
for (let i = 0, n = 0; ; ) { |
|
if (n >= col) |
|
return i; |
|
if (i == string.length) |
|
break; |
|
n += string.charCodeAt(i) == 9 ? tabSize - n % tabSize : 1; |
|
i = findClusterBreak(string, i); |
|
} |
|
return strict === true ? -1 : string.length; |
|
} |
|
|
|
export { |
|
Text, |
|
Line, |
|
findClusterBreak, |
|
codePointAt, |
|
fromCodePoint, |
|
codePointSize, |
|
MapMode, |
|
ChangeDesc, |
|
ChangeSet, |
|
SelectionRange, |
|
EditorSelection, |
|
Facet, |
|
StateField, |
|
Prec, |
|
Compartment, |
|
Annotation, |
|
AnnotationType, |
|
StateEffectType, |
|
StateEffect, |
|
Transaction, |
|
CharCategory, |
|
EditorState, |
|
combineConfig, |
|
RangeValue, |
|
Range, |
|
RangeSet, |
|
RangeSetBuilder, |
|
countColumn, |
|
findColumn |
|
}; |
|
|
|
|