GPQAPP

Форк
0
305 строк · 11.9 Кб
1
// CodeMirror, copyright (c) by Marijn Haverbeke and others
2
// Distributed under an MIT license: https://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, endMargin) {
76
    var match, from = 0
77
    while (from <= string.length) {
78
      regexp.lastIndex = from
79
      var newMatch = regexp.exec(string)
80
      if (!newMatch) break
81
      var end = newMatch.index + newMatch[0].length
82
      if (end > string.length - endMargin) break
83
      if (!match || end > match.index + match[0].length)
84
        match = newMatch
85
      from = newMatch.index + 1
86
    }
87
    return match
88
  }
89

90
  function searchRegexpBackward(doc, regexp, start) {
91
    regexp = ensureFlags(regexp, "g")
92
    for (var line = start.line, ch = start.ch, first = doc.firstLine(); line >= first; line--, ch = -1) {
93
      var string = doc.getLine(line)
94
      var match = lastMatchIn(string, regexp, ch < 0 ? 0 : string.length - ch)
95
      if (match)
96
        return {from: Pos(line, match.index),
97
                to: Pos(line, match.index + match[0].length),
98
                match: match}
99
    }
100
  }
101

102
  function searchRegexpBackwardMultiline(doc, regexp, start) {
103
    if (!maybeMultiline(regexp)) return searchRegexpBackward(doc, regexp, start)
104
    regexp = ensureFlags(regexp, "gm")
105
    var string, chunkSize = 1, endMargin = doc.getLine(start.line).length - start.ch
106
    for (var line = start.line, first = doc.firstLine(); line >= first;) {
107
      for (var i = 0; i < chunkSize && line >= first; i++) {
108
        var curLine = doc.getLine(line--)
109
        string = string == null ? curLine : curLine + "\n" + string
110
      }
111
      chunkSize *= 2
112

113
      var match = lastMatchIn(string, regexp, endMargin)
114
      if (match) {
115
        var before = string.slice(0, match.index).split("\n"), inside = match[0].split("\n")
116
        var startLine = line + before.length, startCh = before[before.length - 1].length
117
        return {from: Pos(startLine, startCh),
118
                to: Pos(startLine + inside.length - 1,
119
                        inside.length == 1 ? startCh + inside[0].length : inside[inside.length - 1].length),
120
                match: match}
121
      }
122
    }
123
  }
124

125
  var doFold, noFold
126
  if (String.prototype.normalize) {
127
    doFold = function(str) { return str.normalize("NFD").toLowerCase() }
128
    noFold = function(str) { return str.normalize("NFD") }
129
  } else {
130
    doFold = function(str) { return str.toLowerCase() }
131
    noFold = function(str) { return str }
132
  }
133

134
  // Maps a position in a case-folded line back to a position in the original line
135
  // (compensating for codepoints increasing in number during folding)
136
  function adjustPos(orig, folded, pos, foldFunc) {
137
    if (orig.length == folded.length) return pos
138
    for (var min = 0, max = pos + Math.max(0, orig.length - folded.length);;) {
139
      if (min == max) return min
140
      var mid = (min + max) >> 1
141
      var len = foldFunc(orig.slice(0, mid)).length
142
      if (len == pos) return mid
143
      else if (len > pos) max = mid
144
      else min = mid + 1
145
    }
146
  }
147

148
  function searchStringForward(doc, query, start, caseFold) {
149
    // Empty string would match anything and never progress, so we
150
    // define it to match nothing instead.
151
    if (!query.length) return null
152
    var fold = caseFold ? doFold : noFold
153
    var lines = fold(query).split(/\r|\n\r?/)
154

155
    search: for (var line = start.line, ch = start.ch, last = doc.lastLine() + 1 - lines.length; line <= last; line++, ch = 0) {
156
      var orig = doc.getLine(line).slice(ch), string = fold(orig)
157
      if (lines.length == 1) {
158
        var found = string.indexOf(lines[0])
159
        if (found == -1) continue search
160
        var start = adjustPos(orig, string, found, fold) + ch
161
        return {from: Pos(line, adjustPos(orig, string, found, fold) + ch),
162
                to: Pos(line, adjustPos(orig, string, found + lines[0].length, fold) + ch)}
163
      } else {
164
        var cutFrom = string.length - lines[0].length
165
        if (string.slice(cutFrom) != lines[0]) continue search
166
        for (var i = 1; i < lines.length - 1; i++)
167
          if (fold(doc.getLine(line + i)) != lines[i]) continue search
168
        var end = doc.getLine(line + lines.length - 1), endString = fold(end), lastLine = lines[lines.length - 1]
169
        if (endString.slice(0, lastLine.length) != lastLine) continue search
170
        return {from: Pos(line, adjustPos(orig, string, cutFrom, fold) + ch),
171
                to: Pos(line + lines.length - 1, adjustPos(end, endString, lastLine.length, fold))}
172
      }
173
    }
174
  }
175

176
  function searchStringBackward(doc, query, start, caseFold) {
177
    if (!query.length) return null
178
    var fold = caseFold ? doFold : noFold
179
    var lines = fold(query).split(/\r|\n\r?/)
180

181
    search: for (var line = start.line, ch = start.ch, first = doc.firstLine() - 1 + lines.length; line >= first; line--, ch = -1) {
182
      var orig = doc.getLine(line)
183
      if (ch > -1) orig = orig.slice(0, ch)
184
      var string = fold(orig)
185
      if (lines.length == 1) {
186
        var found = string.lastIndexOf(lines[0])
187
        if (found == -1) continue search
188
        return {from: Pos(line, adjustPos(orig, string, found, fold)),
189
                to: Pos(line, adjustPos(orig, string, found + lines[0].length, fold))}
190
      } else {
191
        var lastLine = lines[lines.length - 1]
192
        if (string.slice(0, lastLine.length) != lastLine) continue search
193
        for (var i = 1, start = line - lines.length + 1; i < lines.length - 1; i++)
194
          if (fold(doc.getLine(start + i)) != lines[i]) continue search
195
        var top = doc.getLine(line + 1 - lines.length), topString = fold(top)
196
        if (topString.slice(topString.length - lines[0].length) != lines[0]) continue search
197
        return {from: Pos(line + 1 - lines.length, adjustPos(top, topString, top.length - lines[0].length, fold)),
198
                to: Pos(line, adjustPos(orig, string, lastLine.length, fold))}
199
      }
200
    }
201
  }
202

203
  function SearchCursor(doc, query, pos, options) {
204
    this.atOccurrence = false
205
    this.afterEmptyMatch = false
206
    this.doc = doc
207
    pos = pos ? doc.clipPos(pos) : Pos(0, 0)
208
    this.pos = {from: pos, to: pos}
209

210
    var caseFold
211
    if (typeof options == "object") {
212
      caseFold = options.caseFold
213
    } else { // Backwards compat for when caseFold was the 4th argument
214
      caseFold = options
215
      options = null
216
    }
217

218
    if (typeof query == "string") {
219
      if (caseFold == null) caseFold = false
220
      this.matches = function(reverse, pos) {
221
        return (reverse ? searchStringBackward : searchStringForward)(doc, query, pos, caseFold)
222
      }
223
    } else {
224
      query = ensureFlags(query, "gm")
225
      if (!options || options.multiline !== false)
226
        this.matches = function(reverse, pos) {
227
          return (reverse ? searchRegexpBackwardMultiline : searchRegexpForwardMultiline)(doc, query, pos)
228
        }
229
      else
230
        this.matches = function(reverse, pos) {
231
          return (reverse ? searchRegexpBackward : searchRegexpForward)(doc, query, pos)
232
        }
233
    }
234
  }
235

236
  SearchCursor.prototype = {
237
    findNext: function() {return this.find(false)},
238
    findPrevious: function() {return this.find(true)},
239

240
    find: function(reverse) {
241
      var head = this.doc.clipPos(reverse ? this.pos.from : this.pos.to);
242
      if (this.afterEmptyMatch && this.atOccurrence) {
243
        // do not return the same 0 width match twice
244
        head = Pos(head.line, head.ch)
245
        if (reverse) {
246
          head.ch--;
247
          if (head.ch < 0) {
248
            head.line--;
249
            head.ch = (this.doc.getLine(head.line) || "").length;
250
          }
251
        } else {
252
          head.ch++;
253
          if (head.ch > (this.doc.getLine(head.line) || "").length) {
254
            head.ch = 0;
255
            head.line++;
256
          }
257
        }
258
        if (CodeMirror.cmpPos(head, this.doc.clipPos(head)) != 0) {
259
           return this.atOccurrence = false
260
        }
261
      }
262
      var result = this.matches(reverse, head)
263
      this.afterEmptyMatch = result && CodeMirror.cmpPos(result.from, result.to) == 0
264

265
      if (result) {
266
        this.pos = result
267
        this.atOccurrence = true
268
        return this.pos.match || true
269
      } else {
270
        var end = Pos(reverse ? this.doc.firstLine() : this.doc.lastLine() + 1, 0)
271
        this.pos = {from: end, to: end}
272
        return this.atOccurrence = false
273
      }
274
    },
275

276
    from: function() {if (this.atOccurrence) return this.pos.from},
277
    to: function() {if (this.atOccurrence) return this.pos.to},
278

279
    replace: function(newText, origin) {
280
      if (!this.atOccurrence) return
281
      var lines = CodeMirror.splitLines(newText)
282
      this.doc.replaceRange(lines, this.pos.from, this.pos.to, origin)
283
      this.pos.to = Pos(this.pos.from.line + lines.length - 1,
284
                        lines[lines.length - 1].length + (lines.length == 1 ? this.pos.from.ch : 0))
285
    }
286
  }
287

288
  CodeMirror.defineExtension("getSearchCursor", function(query, pos, caseFold) {
289
    return new SearchCursor(this.doc, query, pos, caseFold)
290
  })
291
  CodeMirror.defineDocExtension("getSearchCursor", function(query, pos, caseFold) {
292
    return new SearchCursor(this, query, pos, caseFold)
293
  })
294

295
  CodeMirror.defineExtension("selectMatches", function(query, caseFold) {
296
    var ranges = []
297
    var cur = this.getSearchCursor(query, this.getCursor("from"), caseFold)
298
    while (cur.findNext()) {
299
      if (CodeMirror.cmpPos(cur.to(), this.getCursor("to")) > 0) break
300
      ranges.push({anchor: cur.from(), head: cur.to()})
301
    }
302
    if (ranges.length)
303
      this.setSelections(ranges, 0)
304
  })
305
});
306

Использование cookies

Мы используем файлы cookie в соответствии с Политикой конфиденциальности и Политикой использования cookies.

Нажимая кнопку «Принимаю», Вы даете АО «СберТех» согласие на обработку Ваших персональных данных в целях совершенствования нашего веб-сайта и Сервиса GitVerse, а также повышения удобства их использования.

Запретить использование cookies Вы можете самостоятельно в настройках Вашего браузера.