Only rebuild changed line indentation decorations (#16092)

GitOrigin-RevId: 13855598e2cfc06d2ea2357d1c71875993a106a9
This commit is contained in:
Alf Eaton 2023-12-05 09:42:24 +00:00 committed by Copybot
parent 8cb76ce40b
commit c4b05f7a73

View file

@ -78,12 +78,14 @@ export const lineWrappingIndentation = (visual: boolean) => {
update(update: ViewUpdate) {
const maxIndent = view.state.field(field)
if (
maxIndent !== previousMaxIndent ||
update.geometryChanged ||
update.viewportChanged
) {
if (maxIndent !== previousMaxIndent) {
value.decorations = buildDecorations(view, maxIndent)
} else if (update.geometryChanged || update.viewportChanged) {
value.decorations = updateDecorations(
value.decorations,
update,
maxIndent
)
}
previousMaxIndent = maxIndent
@ -111,7 +113,6 @@ export const buildDecorations = (view: EditorView, maxIndent: number) => {
let from = 0
for (const line of doc.iterLines()) {
// const indent = line.match(/^(\s*)/)[1].length
const indent = calculateIndent(line, tabSize, maxIndent)
if (indent) {
@ -124,6 +125,66 @@ export const buildDecorations = (view: EditorView, maxIndent: number) => {
return Decoration.set(decorations)
}
export const updateDecorations = (
decorations: DecorationSet,
update: ViewUpdate,
maxIndent: number
) => {
const add: Range<Decoration>[] = []
const { doc, tabSize } = update.state
const changedLinesFrom = new Set()
let filterFrom = doc.length
let filterTo = 0
update.changes.iterChangedRanges((fromA, toA, fromB, toB) => {
// remove changed lines
const fromALineNumber = doc.lineAt(fromA).number
const toALineNumber = doc.lineAt(toA).number
for (
let lineNumber = fromALineNumber;
lineNumber <= toALineNumber;
lineNumber++
) {
const line = doc.line(lineNumber)
changedLinesFrom.add(line.from)
filterFrom = Math.min(line.from, filterFrom)
filterTo = Math.max(line.from, filterTo)
}
// add changed lines
const fromBLineNumber = doc.lineAt(fromB).number
const toBLineNumber = doc.lineAt(toB).number
for (
let lineNumber = fromBLineNumber;
lineNumber <= toBLineNumber;
lineNumber++
) {
const line = doc.line(lineNumber)
const indent = calculateIndent(line.text, tabSize, maxIndent)
if (indent) {
add.push(lineIndentDecoration(indent).range(line.from))
}
}
})
return decorations
.update({
filter(from) {
return !changedLinesFrom.has(from)
},
filterFrom,
filterTo,
})
.map(update.changes)
.update({ add })
}
const lineIndentDecoration = (indent: number) =>
Decoration.line({
attributes: {