[ Index ]

PHP Cross Reference of MyBB 1.8.37

title

Body

[close]

/admin/jscripts/codemirror/addon/search/ -> searchcursor.js (source)

   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 (end.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  });


2005 - 2021 © MyBB.de | Alle Rechte vorbehalten! | Sponsor: netcup Cross-referenced by PHPXref