annotate .cms/lib/codemirror/addon/search/searchcursor.js @ 1:1d486627aa1e draft default tip

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