Mercurial
comparison .cms/lib/codemirror/src/display/view_tracking.js @ 0:78edf6b517a0 draft
24.10
author | Coffee CMS <info@coffee-cms.ru> |
---|---|
date | Fri, 11 Oct 2024 22:40:23 +0000 |
parents | |
children |
comparison
equal
deleted
inserted
replaced
-1:000000000000 | 0:78edf6b517a0 |
---|---|
1 import { buildViewArray } from "../line/line_data.js" | |
2 import { sawCollapsedSpans } from "../line/saw_special_spans.js" | |
3 import { visualLineEndNo, visualLineNo } from "../line/spans.js" | |
4 import { findViewIndex } from "../measurement/position_measurement.js" | |
5 import { indexOf } from "../util/misc.js" | |
6 | |
7 // Updates the display.view data structure for a given change to the | |
8 // document. From and to are in pre-change coordinates. Lendiff is | |
9 // the amount of lines added or subtracted by the change. This is | |
10 // used for changes that span multiple lines, or change the way | |
11 // lines are divided into visual lines. regLineChange (below) | |
12 // registers single-line changes. | |
13 export function regChange(cm, from, to, lendiff) { | |
14 if (from == null) from = cm.doc.first | |
15 if (to == null) to = cm.doc.first + cm.doc.size | |
16 if (!lendiff) lendiff = 0 | |
17 | |
18 let display = cm.display | |
19 if (lendiff && to < display.viewTo && | |
20 (display.updateLineNumbers == null || display.updateLineNumbers > from)) | |
21 display.updateLineNumbers = from | |
22 | |
23 cm.curOp.viewChanged = true | |
24 | |
25 if (from >= display.viewTo) { // Change after | |
26 if (sawCollapsedSpans && visualLineNo(cm.doc, from) < display.viewTo) | |
27 resetView(cm) | |
28 } else if (to <= display.viewFrom) { // Change before | |
29 if (sawCollapsedSpans && visualLineEndNo(cm.doc, to + lendiff) > display.viewFrom) { | |
30 resetView(cm) | |
31 } else { | |
32 display.viewFrom += lendiff | |
33 display.viewTo += lendiff | |
34 } | |
35 } else if (from <= display.viewFrom && to >= display.viewTo) { // Full overlap | |
36 resetView(cm) | |
37 } else if (from <= display.viewFrom) { // Top overlap | |
38 let cut = viewCuttingPoint(cm, to, to + lendiff, 1) | |
39 if (cut) { | |
40 display.view = display.view.slice(cut.index) | |
41 display.viewFrom = cut.lineN | |
42 display.viewTo += lendiff | |
43 } else { | |
44 resetView(cm) | |
45 } | |
46 } else if (to >= display.viewTo) { // Bottom overlap | |
47 let cut = viewCuttingPoint(cm, from, from, -1) | |
48 if (cut) { | |
49 display.view = display.view.slice(0, cut.index) | |
50 display.viewTo = cut.lineN | |
51 } else { | |
52 resetView(cm) | |
53 } | |
54 } else { // Gap in the middle | |
55 let cutTop = viewCuttingPoint(cm, from, from, -1) | |
56 let cutBot = viewCuttingPoint(cm, to, to + lendiff, 1) | |
57 if (cutTop && cutBot) { | |
58 display.view = display.view.slice(0, cutTop.index) | |
59 .concat(buildViewArray(cm, cutTop.lineN, cutBot.lineN)) | |
60 .concat(display.view.slice(cutBot.index)) | |
61 display.viewTo += lendiff | |
62 } else { | |
63 resetView(cm) | |
64 } | |
65 } | |
66 | |
67 let ext = display.externalMeasured | |
68 if (ext) { | |
69 if (to < ext.lineN) | |
70 ext.lineN += lendiff | |
71 else if (from < ext.lineN + ext.size) | |
72 display.externalMeasured = null | |
73 } | |
74 } | |
75 | |
76 // Register a change to a single line. Type must be one of "text", | |
77 // "gutter", "class", "widget" | |
78 export function regLineChange(cm, line, type) { | |
79 cm.curOp.viewChanged = true | |
80 let display = cm.display, ext = cm.display.externalMeasured | |
81 if (ext && line >= ext.lineN && line < ext.lineN + ext.size) | |
82 display.externalMeasured = null | |
83 | |
84 if (line < display.viewFrom || line >= display.viewTo) return | |
85 let lineView = display.view[findViewIndex(cm, line)] | |
86 if (lineView.node == null) return | |
87 let arr = lineView.changes || (lineView.changes = []) | |
88 if (indexOf(arr, type) == -1) arr.push(type) | |
89 } | |
90 | |
91 // Clear the view. | |
92 export function resetView(cm) { | |
93 cm.display.viewFrom = cm.display.viewTo = cm.doc.first | |
94 cm.display.view = [] | |
95 cm.display.viewOffset = 0 | |
96 } | |
97 | |
98 function viewCuttingPoint(cm, oldN, newN, dir) { | |
99 let index = findViewIndex(cm, oldN), diff, view = cm.display.view | |
100 if (!sawCollapsedSpans || newN == cm.doc.first + cm.doc.size) | |
101 return {index: index, lineN: newN} | |
102 let n = cm.display.viewFrom | |
103 for (let i = 0; i < index; i++) | |
104 n += view[i].size | |
105 if (n != oldN) { | |
106 if (dir > 0) { | |
107 if (index == view.length - 1) return null | |
108 diff = (n + view[index].size) - oldN | |
109 index++ | |
110 } else { | |
111 diff = n - oldN | |
112 } | |
113 oldN += diff; newN += diff | |
114 } | |
115 while (visualLineNo(cm.doc, newN) != newN) { | |
116 if (index == (dir < 0 ? 0 : view.length - 1)) return null | |
117 newN += dir * view[index - (dir < 0 ? 1 : 0)].size | |
118 index += dir | |
119 } | |
120 return {index: index, lineN: newN} | |
121 } | |
122 | |
123 // Force the view to cover a given range, adding empty view element | |
124 // or clipping off existing ones as needed. | |
125 export function adjustView(cm, from, to) { | |
126 let display = cm.display, view = display.view | |
127 if (view.length == 0 || from >= display.viewTo || to <= display.viewFrom) { | |
128 display.view = buildViewArray(cm, from, to) | |
129 display.viewFrom = from | |
130 } else { | |
131 if (display.viewFrom > from) | |
132 display.view = buildViewArray(cm, from, display.viewFrom).concat(display.view) | |
133 else if (display.viewFrom < from) | |
134 display.view = display.view.slice(findViewIndex(cm, from)) | |
135 display.viewFrom = from | |
136 if (display.viewTo < to) | |
137 display.view = display.view.concat(buildViewArray(cm, display.viewTo, to)) | |
138 else if (display.viewTo > to) | |
139 display.view = display.view.slice(0, findViewIndex(cm, to)) | |
140 } | |
141 display.viewTo = to | |
142 } | |
143 | |
144 // Count the number of lines in the view whose DOM representation is | |
145 // out of date (or nonexistent). | |
146 export function countDirtyView(cm) { | |
147 let view = cm.display.view, dirty = 0 | |
148 for (let i = 0; i < view.length; i++) { | |
149 let lineView = view[i] | |
150 if (!lineView.hidden && (!lineView.node || lineView.changes)) ++dirty | |
151 } | |
152 return dirty | |
153 } |