PluginProbe ʕ •ᴥ•ʔ
SiteOrigin CSS / 1.5.7
SiteOrigin CSS v1.5.7
1.2.1 1.2.10 1.2.11 1.2.12 1.2.13 1.2.14 1.2.2 1.2.3 1.2.4 1.2.5 1.2.6 1.2.7 1.2.8 1.2.9 1.3.0 1.3.1 1.3.2 1.4.0 1.4.1 1.4.2 1.4.3 1.5.0 1.5.1 1.5.10 1.5.11 1.5.2 1.5.3 1.5.4 1.5.5 1.5.6 1.5.7 1.5.8 1.5.9 1.6.0 1.6.1 1.6.2 1.6.3 1.6.4 1.6.5 1.6.6 trunk 1.0 1.0.1 1.0.2 1.0.3 1.0.4 1.0.5 1.0.6 1.0.7 1.0.8 1.1 1.1.1 1.1.2 1.1.3 1.1.4 1.1.5 1.2.0
so-css / lib / codemirror / addon / search / searchcursor.js
so-css / lib / codemirror / addon / search Last commit date
jump-to-line.js 6 years ago jump-to-line.min.js 6 years ago match-highlighter.js 6 years ago match-highlighter.min.js 6 years ago matchesonscrollbar.css 6 years ago matchesonscrollbar.js 6 years ago matchesonscrollbar.min.js 6 years ago search.js 6 years ago search.min.js 6 years ago searchcursor.js 6 years ago searchcursor.min.js 6 years ago
searchcursor.js
294 lines
1 // CodeMirror, copyright (c) by Marijn Haverbeke and others
2 // Distributed under an MIT license: http://codemirror.net/LICENSE
3
4 (function(mod) {
5 if (typeof exports == "object" && typeof module == "object") // CommonJS
6 mod(require("../../lib/codemirror"))
7 else if (typeof define == "function" && define.amd) // AMD
8 define(["../../lib/codemirror"], mod)
9 else // Plain browser env
10 mod(CodeMirror)
11 })(function(CodeMirror) {
12 "use strict"
13 var Pos = CodeMirror.Pos
14
15 function regexpFlags(regexp) {
16 var flags = regexp.flags
17 return flags != null ? flags : (regexp.ignoreCase ? "i" : "")
18 + (regexp.global ? "g" : "")
19 + (regexp.multiline ? "m" : "")
20 }
21
22 function ensureFlags(regexp, flags) {
23 var current = regexpFlags(regexp), target = current
24 for (var i = 0; i < flags.length; i++) if (target.indexOf(flags.charAt(i)) == -1)
25 target += flags.charAt(i)
26 return current == target ? regexp : new RegExp(regexp.source, target)
27 }
28
29 function maybeMultiline(regexp) {
30 return /\\s|\\n|\n|\\W|\\D|\[\^/.test(regexp.source)
31 }
32
33 function searchRegexpForward(doc, regexp, start) {
34 regexp = ensureFlags(regexp, "g")
35 for (var line = start.line, ch = start.ch, last = doc.lastLine(); line <= last; line++, ch = 0) {
36 regexp.lastIndex = ch
37 var string = doc.getLine(line), match = regexp.exec(string)
38 if (match)
39 return {from: Pos(line, match.index),
40 to: Pos(line, match.index + match[0].length),
41 match: match}
42 }
43 }
44
45 function searchRegexpForwardMultiline(doc, regexp, start) {
46 if (!maybeMultiline(regexp)) return searchRegexpForward(doc, regexp, start)
47
48 regexp = ensureFlags(regexp, "gm")
49 var string, chunk = 1
50 for (var line = start.line, last = doc.lastLine(); line <= last;) {
51 // This grows the search buffer in exponentially-sized chunks
52 // between matches, so that nearby matches are fast and don't
53 // require concatenating the whole document (in case we're
54 // searching for something that has tons of matches), but at the
55 // same time, the amount of retries is limited.
56 for (var i = 0; i < chunk; i++) {
57 if (line > last) break
58 var curLine = doc.getLine(line++)
59 string = string == null ? curLine : string + "\n" + curLine
60 }
61 chunk = chunk * 2
62 regexp.lastIndex = start.ch
63 var match = regexp.exec(string)
64 if (match) {
65 var before = string.slice(0, match.index).split("\n"), inside = match[0].split("\n")
66 var startLine = start.line + before.length - 1, startCh = before[before.length - 1].length
67 return {from: Pos(startLine, startCh),
68 to: Pos(startLine + inside.length - 1,
69 inside.length == 1 ? startCh + inside[0].length : inside[inside.length - 1].length),
70 match: match}
71 }
72 }
73 }
74
75 function lastMatchIn(string, regexp) {
76 var cutOff = 0, match
77 for (;;) {
78 regexp.lastIndex = cutOff
79 var newMatch = regexp.exec(string)
80 if (!newMatch) return match
81 match = newMatch
82 cutOff = match.index + (match[0].length || 1)
83 if (cutOff == string.length) return match
84 }
85 }
86
87 function searchRegexpBackward(doc, regexp, start) {
88 regexp = ensureFlags(regexp, "g")
89 for (var line = start.line, ch = start.ch, first = doc.firstLine(); line >= first; line--, ch = -1) {
90 var string = doc.getLine(line)
91 if (ch > -1) string = string.slice(0, ch)
92 var match = lastMatchIn(string, regexp)
93 if (match)
94 return {from: Pos(line, match.index),
95 to: Pos(line, match.index + match[0].length),
96 match: match}
97 }
98 }
99
100 function searchRegexpBackwardMultiline(doc, regexp, start) {
101 regexp = ensureFlags(regexp, "gm")
102 var string, chunk = 1
103 for (var line = start.line, first = doc.firstLine(); line >= first;) {
104 for (var i = 0; i < chunk; i++) {
105 var curLine = doc.getLine(line--)
106 string = string == null ? curLine.slice(0, start.ch) : curLine + "\n" + string
107 }
108 chunk *= 2
109
110 var match = lastMatchIn(string, regexp)
111 if (match) {
112 var before = string.slice(0, match.index).split("\n"), inside = match[0].split("\n")
113 var startLine = line + before.length, startCh = before[before.length - 1].length
114 return {from: Pos(startLine, startCh),
115 to: Pos(startLine + inside.length - 1,
116 inside.length == 1 ? startCh + inside[0].length : inside[inside.length - 1].length),
117 match: match}
118 }
119 }
120 }
121
122 var doFold, noFold
123 if (String.prototype.normalize) {
124 doFold = function(str) { return str.normalize("NFD").toLowerCase() }
125 noFold = function(str) { return str.normalize("NFD") }
126 } else {
127 doFold = function(str) { return str.toLowerCase() }
128 noFold = function(str) { return str }
129 }
130
131 // Maps a position in a case-folded line back to a position in the original line
132 // (compensating for codepoints increasing in number during folding)
133 function adjustPos(orig, folded, pos, foldFunc) {
134 if (orig.length == folded.length) return pos
135 for (var min = 0, max = pos + Math.max(0, orig.length - folded.length);;) {
136 if (min == max) return min
137 var mid = (min + max) >> 1
138 var len = foldFunc(orig.slice(0, mid)).length
139 if (len == pos) return mid
140 else if (len > pos) max = mid
141 else min = mid + 1
142 }
143 }
144
145 function searchStringForward(doc, query, start, caseFold) {
146 // Empty string would match anything and never progress, so we
147 // define it to match nothing instead.
148 if (!query.length) return null
149 var fold = caseFold ? doFold : noFold
150 var lines = fold(query).split(/\r|\n\r?/)
151
152 search: for (var line = start.line, ch = start.ch, last = doc.lastLine() + 1 - lines.length; line <= last; line++, ch = 0) {
153 var orig = doc.getLine(line).slice(ch), string = fold(orig)
154 if (lines.length == 1) {
155 var found = string.indexOf(lines[0])
156 if (found == -1) continue search
157 var start = adjustPos(orig, string, found, fold) + ch
158 return {from: Pos(line, adjustPos(orig, string, found, fold) + ch),
159 to: Pos(line, adjustPos(orig, string, found + lines[0].length, fold) + ch)}
160 } else {
161 var cutFrom = string.length - lines[0].length
162 if (string.slice(cutFrom) != lines[0]) continue search
163 for (var i = 1; i < lines.length - 1; i++)
164 if (fold(doc.getLine(line + i)) != lines[i]) continue search
165 var end = doc.getLine(line + lines.length - 1), endString = fold(end), lastLine = lines[lines.length - 1]
166 if (endString.slice(0, lastLine.length) != lastLine) continue search
167 return {from: Pos(line, adjustPos(orig, string, cutFrom, fold) + ch),
168 to: Pos(line + lines.length - 1, adjustPos(end, endString, lastLine.length, fold))}
169 }
170 }
171 }
172
173 function searchStringBackward(doc, query, start, caseFold) {
174 if (!query.length) return null
175 var fold = caseFold ? doFold : noFold
176 var lines = fold(query).split(/\r|\n\r?/)
177
178 search: for (var line = start.line, ch = start.ch, first = doc.firstLine() - 1 + lines.length; line >= first; line--, ch = -1) {
179 var orig = doc.getLine(line)
180 if (ch > -1) orig = orig.slice(0, ch)
181 var string = fold(orig)
182 if (lines.length == 1) {
183 var found = string.lastIndexOf(lines[0])
184 if (found == -1) continue search
185 return {from: Pos(line, adjustPos(orig, string, found, fold)),
186 to: Pos(line, adjustPos(orig, string, found + lines[0].length, fold))}
187 } else {
188 var lastLine = lines[lines.length - 1]
189 if (string.slice(0, lastLine.length) != lastLine) continue search
190 for (var i = 1, start = line - lines.length + 1; i < lines.length - 1; i++)
191 if (fold(doc.getLine(start + i)) != lines[i]) continue search
192 var top = doc.getLine(line + 1 - lines.length), topString = fold(top)
193 if (topString.slice(topString.length - lines[0].length) != lines[0]) continue search
194 return {from: Pos(line + 1 - lines.length, adjustPos(top, topString, top.length - lines[0].length, fold)),
195 to: Pos(line, adjustPos(orig, string, lastLine.length, fold))}
196 }
197 }
198 }
199
200 function SearchCursor(doc, query, pos, options) {
201 this.atOccurrence = false
202 this.doc = doc
203 pos = pos ? doc.clipPos(pos) : Pos(0, 0)
204 this.pos = {from: pos, to: pos}
205
206 var caseFold
207 if (typeof options == "object") {
208 caseFold = options.caseFold
209 } else { // Backwards compat for when caseFold was the 4th argument
210 caseFold = options
211 options = null
212 }
213
214 if (typeof query == "string") {
215 if (caseFold == null) caseFold = false
216 this.matches = function(reverse, pos) {
217 return (reverse ? searchStringBackward : searchStringForward)(doc, query, pos, caseFold)
218 }
219 } else {
220 query = ensureFlags(query, "gm")
221 if (!options || options.multiline !== false)
222 this.matches = function(reverse, pos) {
223 return (reverse ? searchRegexpBackwardMultiline : searchRegexpForwardMultiline)(doc, query, pos)
224 }
225 else
226 this.matches = function(reverse, pos) {
227 return (reverse ? searchRegexpBackward : searchRegexpForward)(doc, query, pos)
228 }
229 }
230 }
231
232 SearchCursor.prototype = {
233 findNext: function() {return this.find(false)},
234 findPrevious: function() {return this.find(true)},
235
236 find: function(reverse) {
237 var result = this.matches(reverse, this.doc.clipPos(reverse ? this.pos.from : this.pos.to))
238
239 // Implements weird auto-growing behavior on null-matches for
240 // backwards-compatiblity with the vim code (unfortunately)
241 while (result && CodeMirror.cmpPos(result.from, result.to) == 0) {
242 if (reverse) {
243 if (result.from.ch) result.from = Pos(result.from.line, result.from.ch - 1)
244 else if (result.from.line == this.doc.firstLine()) result = null
245 else result = this.matches(reverse, this.doc.clipPos(Pos(result.from.line - 1)))
246 } else {
247 if (result.to.ch < this.doc.getLine(result.to.line).length) result.to = Pos(result.to.line, result.to.ch + 1)
248 else if (result.to.line == this.doc.lastLine()) result = null
249 else result = this.matches(reverse, Pos(result.to.line + 1, 0))
250 }
251 }
252
253 if (result) {
254 this.pos = result
255 this.atOccurrence = true
256 return this.pos.match || true
257 } else {
258 var end = Pos(reverse ? this.doc.firstLine() : this.doc.lastLine() + 1, 0)
259 this.pos = {from: end, to: end}
260 return this.atOccurrence = false
261 }
262 },
263
264 from: function() {if (this.atOccurrence) return this.pos.from},
265 to: function() {if (this.atOccurrence) return this.pos.to},
266
267 replace: function(newText, origin) {
268 if (!this.atOccurrence) return
269 var lines = CodeMirror.splitLines(newText)
270 this.doc.replaceRange(lines, this.pos.from, this.pos.to, origin)
271 this.pos.to = Pos(this.pos.from.line + lines.length - 1,
272 lines[lines.length - 1].length + (lines.length == 1 ? this.pos.from.ch : 0))
273 }
274 }
275
276 CodeMirror.defineExtension("getSearchCursor", function(query, pos, caseFold) {
277 return new SearchCursor(this.doc, query, pos, caseFold)
278 })
279 CodeMirror.defineDocExtension("getSearchCursor", function(query, pos, caseFold) {
280 return new SearchCursor(this, query, pos, caseFold)
281 })
282
283 CodeMirror.defineExtension("selectMatches", function(query, caseFold) {
284 var ranges = []
285 var cur = this.getSearchCursor(query, this.getCursor("from"), caseFold)
286 while (cur.findNext()) {
287 if (CodeMirror.cmpPos(cur.to(), this.getCursor("to")) > 0) break
288 ranges.push({anchor: cur.from(), head: cur.to()})
289 }
290 if (ranges.length)
291 this.setSelections(ranges, 0)
292 })
293 });
294