Remove quadratic complexity of adding lots of marks to a single line

(As long as this is done in an operation.)

Closes #6682
This commit is contained in:
Marijn Haverbeke 2021-05-17 12:18:33 +02:00
parent 687b6ddd87
commit 72579dd091
4 changed files with 15 additions and 5 deletions

View File

@ -36,7 +36,8 @@ export function startOperation(cm) {
scrollLeft: null, scrollTop: null, // Intermediate scroll position, not pushed to DOM yet
scrollToPos: null, // Used to scroll to a specific position
focus: false,
id: ++nextOpId // Unique ID
id: ++nextOpId, // Unique ID
markArrays: null // Used by addMarkedSpan
}
pushOperation(cm.curOp)
}

View File

@ -18,6 +18,7 @@ export function getMarkedSpanFor(spans, marker) {
if (span.marker == marker) return span
}
}
// Remove a span from an array, returning undefined if no spans are
// left (we don't store arrays for lines without spans).
export function removeMarkedSpan(spans, span) {
@ -26,9 +27,16 @@ export function removeMarkedSpan(spans, span) {
if (spans[i] != span) (r || (r = [])).push(spans[i])
return r
}
// Add a span to a line.
export function addMarkedSpan(line, span) {
line.markedSpans = line.markedSpans ? line.markedSpans.concat([span]) : [span]
export function addMarkedSpan(line, span, op) {
let inThisOp = op && window.WeakSet && (op.markedSpans || (op.markedSpans = new WeakSet))
if (inThisOp && inThisOp.has(line.markedSpans)) {
line.markedSpans.push(span)
} else {
line.markedSpans = line.markedSpans ? line.markedSpans.concat([span]) : [span]
if (inThisOp) inThisOp.add(line.markedSpans)
}
span.marker.attachLine(line)
}

View File

@ -187,7 +187,7 @@ export function markText(doc, from, to, options, type) {
if (marker.collapsed && curLine != from.line) updateLineHeight(line, 0)
addMarkedSpan(line, new MarkedSpan(marker,
curLine == from.line ? from.ch : null,
curLine == to.line ? to.ch : null))
curLine == to.line ? to.ch : null), doc.cm && doc.cm.curOp)
++curLine
})
// lineIsHidden depends on the presence of the spans, so needs a second pass

View File

@ -3,7 +3,7 @@ var blint = require("blint");
["mode", "lib", "addon", "keymap"].forEach(function(dir) {
blint.checkDir(dir, {
browser: true,
allowedGlobals: ["CodeMirror", "define", "test", "requirejs", "globalThis"],
allowedGlobals: ["CodeMirror", "define", "test", "requirejs", "globalThis", "WeakSet"],
ecmaVersion: 5,
tabs: dir == "lib"
});
@ -12,6 +12,7 @@ var blint = require("blint");
["src"].forEach(function(dir) {
blint.checkDir(dir, {
browser: true,
allowedGlobals: ["WeakSet"],
ecmaVersion: 6,
semicolons: false
});