File modules/editor/codemirror/addon/search/searchcursor.min.js

Last commit: Tue May 22 22:39:54 2018 +0200	Jan Dankert	Fix für PHP 7.2: 'Object' darf nun nicht mehr als Klassennamen verwendet werden. AUCH NICHT IN EINEM NAMESPACE! WTF, wozu habe ich das in einen verfickten Namespace gepackt? Wozu soll der sonst da sein??? Amateure. Daher nun notgedrungen unbenannt in 'BaseObject'.
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 ensureGlobal(regexp) { 23 return regexp.global ? regexp : new RegExp(regexp.source, regexpFlags(regexp) + "g") 24 } 25 26 function maybeMultiline(regexp) { 27 return /\\s|\\n|\n|\\W|\\D|\[\^/.test(regexp.source) 28 } 29 30 function searchRegexpForward(doc, regexp, start) { 31 regexp = ensureGlobal(regexp) 32 for (var line = start.line, ch = start.ch, last = doc.lastLine(); line <= last; line++, ch = 0) { 33 regexp.lastIndex = ch 34 var string = doc.getLine(line), match = regexp.exec(string) 35 if (match) 36 return {from: Pos(line, match.index), 37 to: Pos(line, match.index + match[0].length), 38 match: match} 39 } 40 } 41 42 function searchRegexpForwardMultiline(doc, regexp, start) { 43 if (!maybeMultiline(regexp)) return searchRegexpForward(doc, regexp, start) 44 45 regexp = ensureGlobal(regexp) 46 var string, chunk = 1 47 for (var line = start.line, last = doc.lastLine(); line <= last;) { 48 // This grows the search buffer in exponentially-sized chunks 49 // between matches, so that nearby matches are fast and don't 50 // require concatenating the whole document (in case we're 51 // searching for something that has tons of matches), but at the 52 // same time, the amount of retries is limited. 53 for (var i = 0; i < chunk; i++) { 54 var curLine = doc.getLine(line++) 55 string = string == null ? curLine : string + "\n" + curLine 56 } 57 chunk = chunk * 2 58 regexp.lastIndex = start.ch 59 var match = regexp.exec(string) 60 if (match) { 61 var before = string.slice(0, match.index).split("\n"), inside = match[0].split("\n") 62 var startLine = start.line + before.length - 1, startCh = before[before.length - 1].length 63 return {from: Pos(startLine, startCh), 64 to: Pos(startLine + inside.length - 1, 65 inside.length == 1 ? startCh + inside[0].length : inside[inside.length - 1].length), 66 match: match} 67 } 68 } 69 } 70 71 function lastMatchIn(string, regexp) { 72 var cutOff = 0, match 73 for (;;) { 74 regexp.lastIndex = cutOff 75 var newMatch = regexp.exec(string) 76 if (!newMatch) return match 77 match = newMatch 78 cutOff = match.index + (match[0].length || 1) 79 if (cutOff == string.length) return match 80 } 81 } 82 83 function searchRegexpBackward(doc, regexp, start) { 84 regexp = ensureGlobal(regexp) 85 for (var line = start.line, ch = start.ch, first = doc.firstLine(); line >= first; line--, ch = -1) { 86 var string = doc.getLine(line) 87 if (ch > -1) string = string.slice(0, ch) 88 var match = lastMatchIn(string, regexp) 89 if (match) 90 return {from: Pos(line, match.index), 91 to: Pos(line, match.index + match[0].length), 92 match: match} 93 } 94 } 95 96 function searchRegexpBackwardMultiline(doc, regexp, start) { 97 regexp = ensureGlobal(regexp) 98 var string, chunk = 1 99 for (var line = start.line, first = doc.firstLine(); line >= first;) { 100 for (var i = 0; i < chunk; i++) { 101 var curLine = doc.getLine(line--) 102 string = string == null ? curLine.slice(0, start.ch) : curLine + "\n" + string 103 } 104 chunk *= 2 105 106 var match = lastMatchIn(string, regexp) 107 if (match) { 108 var before = string.slice(0, match.index).split("\n"), inside = match[0].split("\n") 109 var startLine = line + before.length, startCh = before[before.length - 1].length 110 return {from: Pos(startLine, startCh), 111 to: Pos(startLine + inside.length - 1, 112 inside.length == 1 ? startCh + inside[0].length : inside[inside.length - 1].length), 113 match: match} 114 } 115 } 116 } 117 118 var doFold, noFold 119 if (String.prototype.normalize) { 120 doFold = function(str) { return str.normalize("NFD").toLowerCase() } 121 noFold = function(str) { return str.normalize("NFD") } 122 } else { 123 doFold = function(str) { return str.toLowerCase() } 124 noFold = function(str) { return str } 125 } 126 127 // Maps a position in a case-folded line back to a position in the original line 128 // (compensating for codepoints increasing in number during folding) 129 function adjustPos(orig, folded, pos, foldFunc) { 130 if (orig.length == folded.length) return pos 131 for (var min = 0, max = pos + Math.max(0, orig.length - folded.length);;) { 132 if (min == max) return min 133 var mid = (min + max) >> 1 134 var len = foldFunc(orig.slice(0, mid)).length 135 if (len == pos) return mid 136 else if (len > pos) max = mid 137 else min = mid + 1 138 } 139 } 140 141 function searchStringForward(doc, query, start, caseFold) { 142 // Empty string would match anything and never progress, so we 143 // define it to match nothing instead. 144 if (!query.length) return null 145 var fold = caseFold ? doFold : noFold 146 var lines = fold(query).split(/\r|\n\r?/) 147 148 search: for (var line = start.line, ch = start.ch, last = doc.lastLine() + 1 - lines.length; line <= last; line++, ch = 0) { 149 var orig = doc.getLine(line).slice(ch), string = fold(orig) 150 if (lines.length == 1) { 151 var found = string.indexOf(lines[0]) 152 if (found == -1) continue search 153 var start = adjustPos(orig, string, found, fold) + ch 154 return {from: Pos(line, adjustPos(orig, string, found, fold) + ch), 155 to: Pos(line, adjustPos(orig, string, found + lines[0].length, fold) + ch)} 156 } else { 157 var cutFrom = string.length - lines[0].length 158 if (string.slice(cutFrom) != lines[0]) continue search 159 for (var i = 1; i < lines.length - 1; i++) 160 if (fold(doc.getLine(line + i)) != lines[i]) continue search 161 var end = doc.getLine(line + lines.length - 1), endString = fold(end), lastLine = lines[lines.length - 1] 162 if (endString.slice(0, lastLine.length) != lastLine) continue search 163 return {from: Pos(line, adjustPos(orig, string, cutFrom, fold) + ch), 164 to: Pos(line + lines.length - 1, adjustPos(end, endString, lastLine.length, fold))} 165 } 166 } 167 } 168 169 function searchStringBackward(doc, query, start, caseFold) { 170 if (!query.length) return null 171 var fold = caseFold ? doFold : noFold 172 var lines = fold(query).split(/\r|\n\r?/) 173 174 search: for (var line = start.line, ch = start.ch, first = doc.firstLine() - 1 + lines.length; line >= first; line--, ch = -1) { 175 var orig = doc.getLine(line) 176 if (ch > -1) orig = orig.slice(0, ch) 177 var string = fold(orig) 178 if (lines.length == 1) { 179 var found = string.lastIndexOf(lines[0]) 180 if (found == -1) continue search 181 return {from: Pos(line, adjustPos(orig, string, found, fold)), 182 to: Pos(line, adjustPos(orig, string, found + lines[0].length, fold))} 183 } else { 184 var lastLine = lines[lines.length - 1] 185 if (string.slice(0, lastLine.length) != lastLine) continue search 186 for (var i = 1, start = line - lines.length + 1; i < lines.length - 1; i++) 187 if (fold(doc.getLine(start + i)) != lines[i]) continue search 188 var top = doc.getLine(line + 1 - lines.length), topString = fold(top) 189 if (topString.slice(topString.length - lines[0].length) != lines[0]) continue search 190 return {from: Pos(line + 1 - lines.length, adjustPos(top, topString, top.length - lines[0].length, fold)), 191 to: Pos(line, adjustPos(orig, string, lastLine.length, fold))} 192 } 193 } 194 } 195 196 function SearchCursor(doc, query, pos, options) { 197 this.atOccurrence = false 198 this.doc = doc 199 pos = pos ? doc.clipPos(pos) : Pos(0, 0) 200 this.pos = {from: pos, to: pos} 201 202 var caseFold 203 if (typeof options == "object") { 204 caseFold = options.caseFold 205 } else { // Backwards compat for when caseFold was the 4th argument 206 caseFold = options 207 options = null 208 } 209 210 if (typeof query == "string") { 211 if (caseFold == null) caseFold = false 212 this.matches = function(reverse, pos) { 213 return (reverse ? searchStringBackward : searchStringForward)(doc, query, pos, caseFold) 214 } 215 } else { 216 query = ensureGlobal(query) 217 if (!options || options.multiline !== false) 218 this.matches = function(reverse, pos) { 219 return (reverse ? searchRegexpBackwardMultiline : searchRegexpForwardMultiline)(doc, query, pos) 220 } 221 else 222 this.matches = function(reverse, pos) { 223 return (reverse ? searchRegexpBackward : searchRegexpForward)(doc, query, pos) 224 } 225 } 226 } 227 228 SearchCursor.prototype = { 229 findNext: function() {return this.find(false)}, 230 findPrevious: function() {return this.find(true)}, 231 232 find: function(reverse) { 233 var result = this.matches(reverse, this.doc.clipPos(reverse ? this.pos.from : this.pos.to)) 234 235 // Implements weird auto-growing behavior on null-matches for 236 // backwards-compatiblity with the vim code (unfortunately) 237 while (result && CodeMirror.cmpPos(result.from, result.to) == 0) { 238 if (reverse) { 239 if (result.from.ch) result.from = Pos(result.from.line, result.from.ch - 1) 240 else if (result.from.line == this.doc.firstLine()) result = null 241 else result = this.matches(reverse, this.doc.clipPos(Pos(result.from.line - 1))) 242 } else { 243 if (result.to.ch < this.doc.getLine(result.to.line).length) result.to = Pos(result.to.line, result.to.ch + 1) 244 else if (result.to.line == this.doc.lastLine()) result = null 245 else result = this.matches(reverse, Pos(result.to.line + 1, 0)) 246 } 247 } 248 249 if (result) { 250 this.pos = result 251 this.atOccurrence = true 252 return this.pos.match || true 253 } else { 254 var end = Pos(reverse ? this.doc.firstLine() : this.doc.lastLine() + 1, 0) 255 this.pos = {from: end, to: end} 256 return this.atOccurrence = false 257 } 258 }, 259 260 from: function() {if (this.atOccurrence) return this.pos.from}, 261 to: function() {if (this.atOccurrence) return this.pos.to}, 262 263 replace: function(newText, origin) { 264 if (!this.atOccurrence) return 265 var lines = CodeMirror.splitLines(newText) 266 this.doc.replaceRange(lines, this.pos.from, this.pos.to, origin) 267 this.pos.to = Pos(this.pos.from.line + lines.length - 1, 268 lines[lines.length - 1].length + (lines.length == 1 ? this.pos.from.ch : 0)) 269 } 270 } 271 272 CodeMirror.defineExtension("getSearchCursor", function(query, pos, caseFold) { 273 return new SearchCursor(this.doc, query, pos, caseFold) 274 }) 275 CodeMirror.defineDocExtension("getSearchCursor", function(query, pos, caseFold) { 276 return new SearchCursor(this, query, pos, caseFold) 277 }) 278 279 CodeMirror.defineExtension("selectMatches", function(query, caseFold) { 280 var ranges = [] 281 var cur = this.getSearchCursor(query, this.getCursor("from"), caseFold) 282 while (cur.findNext()) { 283 if (CodeMirror.cmpPos(cur.to(), this.getCursor("to")) > 0) break 284 ranges.push({anchor: cur.from(), head: cur.to()}) 285 } 286 if (ranges.length) 287 this.setSelections(ranges, 0) 288 }) 289 });
Download modules/editor/codemirror/addon/search/searchcursor.min.js
History Tue, 22 May 2018 22:39:54 +0200 Jan Dankert Fix für PHP 7.2: 'Object' darf nun nicht mehr als Klassennamen verwendet werden. AUCH NICHT IN EINEM NAMESPACE! WTF, wozu habe ich das in einen verfickten Namespace gepackt? Wozu soll der sonst da sein??? Amateure. Daher nun notgedrungen unbenannt in 'BaseObject'.