annotate .cms/lib/codemirror/src/line/highlight.js @ 0:78edf6b517a0 draft

24.10
author Coffee CMS <info@coffee-cms.ru>
date Fri, 11 Oct 2024 22:40:23 +0000
parents
children
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
0
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
1 import { countColumn } from "../util/misc.js"
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
2 import { copyState, innerMode, startState } from "../modes.js"
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
3 import StringStream from "../util/StringStream.js"
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
4
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
5 import { getLine, lineNo } from "./utils_line.js"
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
6 import { clipPos } from "./pos.js"
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
7
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
8 class SavedContext {
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
9 constructor(state, lookAhead) {
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
10 this.state = state
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
11 this.lookAhead = lookAhead
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
12 }
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
13 }
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
14
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
15 class Context {
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
16 constructor(doc, state, line, lookAhead) {
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
17 this.state = state
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
18 this.doc = doc
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
19 this.line = line
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
20 this.maxLookAhead = lookAhead || 0
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
21 this.baseTokens = null
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
22 this.baseTokenPos = 1
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
23 }
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
24
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
25 lookAhead(n) {
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
26 let line = this.doc.getLine(this.line + n)
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
27 if (line != null && n > this.maxLookAhead) this.maxLookAhead = n
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
28 return line
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
29 }
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
30
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
31 baseToken(n) {
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
32 if (!this.baseTokens) return null
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
33 while (this.baseTokens[this.baseTokenPos] <= n)
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
34 this.baseTokenPos += 2
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
35 let type = this.baseTokens[this.baseTokenPos + 1]
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
36 return {type: type && type.replace(/( |^)overlay .*/, ""),
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
37 size: this.baseTokens[this.baseTokenPos] - n}
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
38 }
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
39
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
40 nextLine() {
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
41 this.line++
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
42 if (this.maxLookAhead > 0) this.maxLookAhead--
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
43 }
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
44
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
45 static fromSaved(doc, saved, line) {
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
46 if (saved instanceof SavedContext)
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
47 return new Context(doc, copyState(doc.mode, saved.state), line, saved.lookAhead)
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
48 else
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
49 return new Context(doc, copyState(doc.mode, saved), line)
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
50 }
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
51
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
52 save(copy) {
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
53 let state = copy !== false ? copyState(this.doc.mode, this.state) : this.state
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
54 return this.maxLookAhead > 0 ? new SavedContext(state, this.maxLookAhead) : state
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
55 }
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
56 }
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
57
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
58
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
59 // Compute a style array (an array starting with a mode generation
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
60 // -- for invalidation -- followed by pairs of end positions and
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
61 // style strings), which is used to highlight the tokens on the
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
62 // line.
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
63 export function highlightLine(cm, line, context, forceToEnd) {
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
64 // A styles array always starts with a number identifying the
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
65 // mode/overlays that it is based on (for easy invalidation).
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
66 let st = [cm.state.modeGen], lineClasses = {}
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
67 // Compute the base array of styles
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
68 runMode(cm, line.text, cm.doc.mode, context, (end, style) => st.push(end, style),
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
69 lineClasses, forceToEnd)
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
70 let state = context.state
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
71
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
72 // Run overlays, adjust style array.
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
73 for (let o = 0; o < cm.state.overlays.length; ++o) {
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
74 context.baseTokens = st
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
75 let overlay = cm.state.overlays[o], i = 1, at = 0
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
76 context.state = true
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
77 runMode(cm, line.text, overlay.mode, context, (end, style) => {
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
78 let start = i
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
79 // Ensure there's a token end at the current position, and that i points at it
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
80 while (at < end) {
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
81 let i_end = st[i]
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
82 if (i_end > end)
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
83 st.splice(i, 1, end, st[i+1], i_end)
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
84 i += 2
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
85 at = Math.min(end, i_end)
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
86 }
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
87 if (!style) return
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
88 if (overlay.opaque) {
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
89 st.splice(start, i - start, end, "overlay " + style)
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
90 i = start + 2
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
91 } else {
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
92 for (; start < i; start += 2) {
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
93 let cur = st[start+1]
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
94 st[start+1] = (cur ? cur + " " : "") + "overlay " + style
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
95 }
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
96 }
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
97 }, lineClasses)
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
98 context.state = state
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
99 context.baseTokens = null
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
100 context.baseTokenPos = 1
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
101 }
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
102
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
103 return {styles: st, classes: lineClasses.bgClass || lineClasses.textClass ? lineClasses : null}
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
104 }
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
105
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
106 export function getLineStyles(cm, line, updateFrontier) {
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
107 if (!line.styles || line.styles[0] != cm.state.modeGen) {
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
108 let context = getContextBefore(cm, lineNo(line))
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
109 let resetState = line.text.length > cm.options.maxHighlightLength && copyState(cm.doc.mode, context.state)
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
110 let result = highlightLine(cm, line, context)
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
111 if (resetState) context.state = resetState
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
112 line.stateAfter = context.save(!resetState)
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
113 line.styles = result.styles
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
114 if (result.classes) line.styleClasses = result.classes
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
115 else if (line.styleClasses) line.styleClasses = null
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
116 if (updateFrontier === cm.doc.highlightFrontier)
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
117 cm.doc.modeFrontier = Math.max(cm.doc.modeFrontier, ++cm.doc.highlightFrontier)
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
118 }
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
119 return line.styles
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
120 }
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
121
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
122 export function getContextBefore(cm, n, precise) {
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
123 let doc = cm.doc, display = cm.display
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
124 if (!doc.mode.startState) return new Context(doc, true, n)
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
125 let start = findStartLine(cm, n, precise)
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
126 let saved = start > doc.first && getLine(doc, start - 1).stateAfter
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
127 let context = saved ? Context.fromSaved(doc, saved, start) : new Context(doc, startState(doc.mode), start)
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
128
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
129 doc.iter(start, n, line => {
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
130 processLine(cm, line.text, context)
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
131 let pos = context.line
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
132 line.stateAfter = pos == n - 1 || pos % 5 == 0 || pos >= display.viewFrom && pos < display.viewTo ? context.save() : null
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
133 context.nextLine()
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
134 })
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
135 if (precise) doc.modeFrontier = context.line
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
136 return context
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
137 }
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
138
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
139 // Lightweight form of highlight -- proceed over this line and
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
140 // update state, but don't save a style array. Used for lines that
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
141 // aren't currently visible.
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
142 export function processLine(cm, text, context, startAt) {
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
143 let mode = cm.doc.mode
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
144 let stream = new StringStream(text, cm.options.tabSize, context)
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
145 stream.start = stream.pos = startAt || 0
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
146 if (text == "") callBlankLine(mode, context.state)
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
147 while (!stream.eol()) {
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
148 readToken(mode, stream, context.state)
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
149 stream.start = stream.pos
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
150 }
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
151 }
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
152
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
153 function callBlankLine(mode, state) {
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
154 if (mode.blankLine) return mode.blankLine(state)
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
155 if (!mode.innerMode) return
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
156 let inner = innerMode(mode, state)
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
157 if (inner.mode.blankLine) return inner.mode.blankLine(inner.state)
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
158 }
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
159
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
160 function readToken(mode, stream, state, inner) {
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
161 for (let i = 0; i < 10; i++) {
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
162 if (inner) inner[0] = innerMode(mode, state).mode
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
163 let style = mode.token(stream, state)
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
164 if (stream.pos > stream.start) return style
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
165 }
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
166 throw new Error("Mode " + mode.name + " failed to advance stream.")
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
167 }
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
168
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
169 class Token {
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
170 constructor(stream, type, state) {
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
171 this.start = stream.start; this.end = stream.pos
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
172 this.string = stream.current()
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
173 this.type = type || null
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
174 this.state = state
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
175 }
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
176 }
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
177
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
178 // Utility for getTokenAt and getLineTokens
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
179 export function takeToken(cm, pos, precise, asArray) {
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
180 let doc = cm.doc, mode = doc.mode, style
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
181 pos = clipPos(doc, pos)
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
182 let line = getLine(doc, pos.line), context = getContextBefore(cm, pos.line, precise)
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
183 let stream = new StringStream(line.text, cm.options.tabSize, context), tokens
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
184 if (asArray) tokens = []
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
185 while ((asArray || stream.pos < pos.ch) && !stream.eol()) {
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
186 stream.start = stream.pos
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
187 style = readToken(mode, stream, context.state)
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
188 if (asArray) tokens.push(new Token(stream, style, copyState(doc.mode, context.state)))
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
189 }
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
190 return asArray ? tokens : new Token(stream, style, context.state)
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
191 }
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
192
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
193 function extractLineClasses(type, output) {
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
194 if (type) for (;;) {
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
195 let lineClass = type.match(/(?:^|\s+)line-(background-)?(\S+)/)
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
196 if (!lineClass) break
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
197 type = type.slice(0, lineClass.index) + type.slice(lineClass.index + lineClass[0].length)
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
198 let prop = lineClass[1] ? "bgClass" : "textClass"
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
199 if (output[prop] == null)
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
200 output[prop] = lineClass[2]
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
201 else if (!(new RegExp("(?:^|\\s)" + lineClass[2] + "(?:$|\\s)")).test(output[prop]))
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
202 output[prop] += " " + lineClass[2]
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
203 }
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
204 return type
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
205 }
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
206
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
207 // Run the given mode's parser over a line, calling f for each token.
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
208 function runMode(cm, text, mode, context, f, lineClasses, forceToEnd) {
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
209 let flattenSpans = mode.flattenSpans
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
210 if (flattenSpans == null) flattenSpans = cm.options.flattenSpans
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
211 let curStart = 0, curStyle = null
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
212 let stream = new StringStream(text, cm.options.tabSize, context), style
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
213 let inner = cm.options.addModeClass && [null]
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
214 if (text == "") extractLineClasses(callBlankLine(mode, context.state), lineClasses)
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
215 while (!stream.eol()) {
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
216 if (stream.pos > cm.options.maxHighlightLength) {
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
217 flattenSpans = false
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
218 if (forceToEnd) processLine(cm, text, context, stream.pos)
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
219 stream.pos = text.length
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
220 style = null
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
221 } else {
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
222 style = extractLineClasses(readToken(mode, stream, context.state, inner), lineClasses)
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
223 }
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
224 if (inner) {
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
225 let mName = inner[0].name
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
226 if (mName) style = "m-" + (style ? mName + " " + style : mName)
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
227 }
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
228 if (!flattenSpans || curStyle != style) {
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
229 while (curStart < stream.start) {
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
230 curStart = Math.min(stream.start, curStart + 5000)
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
231 f(curStart, curStyle)
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
232 }
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
233 curStyle = style
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
234 }
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
235 stream.start = stream.pos
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
236 }
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
237 while (curStart < stream.pos) {
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
238 // Webkit seems to refuse to render text nodes longer than 57444
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
239 // characters, and returns inaccurate measurements in nodes
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
240 // starting around 5000 chars.
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
241 let pos = Math.min(stream.pos, curStart + 5000)
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
242 f(pos, curStyle)
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
243 curStart = pos
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
244 }
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
245 }
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
246
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
247 // Finds the line to start with when starting a parse. Tries to
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
248 // find a line with a stateAfter, so that it can start with a
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
249 // valid state. If that fails, it returns the line with the
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
250 // smallest indentation, which tends to need the least context to
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
251 // parse correctly.
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
252 function findStartLine(cm, n, precise) {
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
253 let minindent, minline, doc = cm.doc
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
254 let lim = precise ? -1 : n - (cm.doc.mode.innerMode ? 1000 : 100)
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
255 for (let search = n; search > lim; --search) {
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
256 if (search <= doc.first) return doc.first
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
257 let line = getLine(doc, search - 1), after = line.stateAfter
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
258 if (after && (!precise || search + (after instanceof SavedContext ? after.lookAhead : 0) <= doc.modeFrontier))
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
259 return search
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
260 let indented = countColumn(line.text, null, cm.options.tabSize)
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
261 if (minline == null || minindent > indented) {
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
262 minline = search - 1
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
263 minindent = indented
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
264 }
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
265 }
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
266 return minline
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
267 }
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
268
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
269 export function retreatFrontier(doc, n) {
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
270 doc.modeFrontier = Math.min(doc.modeFrontier, n)
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
271 if (doc.highlightFrontier < n - 10) return
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
272 let start = doc.first
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
273 for (let line = n - 1; line > start; line--) {
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
274 let saved = getLine(doc, line).stateAfter
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
275 // change is on 3
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
276 // state on line 1 looked ahead 2 -- so saw 3
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
277 // test 1 + 2 < 3 should cover this
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
278 if (saved && (!(saved instanceof SavedContext) || line + saved.lookAhead < n)) {
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
279 start = line + 1
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
280 break
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
281 }
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
282 }
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
283 doc.highlightFrontier = Math.min(doc.highlightFrontier, start)
Coffee CMS <info@coffee-cms.ru>
parents:
diff changeset
284 }