JAVASCRIPT   26

searchcursor

Guest on 9th May 2022 01:50:50 AM

  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 SearchCursor(doc, query, pos, caseFold) {
  16.     this.atOccurrence = false; this.doc = doc;
  17.     if (caseFold == null && typeof query == "string") caseFold = false;
  18.  
  19.     pos = pos ? doc.clipPos(pos) : Pos(0, 0);
  20.     this.pos = {from: pos, to: pos};
  21.  
  22.     // The matches method is filled in based on the type of query.
  23.     // It takes a position and a direction, and returns an object
  24.     // describing the next occurrence of the query, or null if no
  25.     // more matches were found.
  26.     if (typeof query != "string") { // Regexp match
  27.       if (!query.global) query = new RegExp(query.source, query.ignoreCase ? "ig" : "g");
  28.       this.matches = function(reverse, pos) {
  29.         if (reverse) {
  30.           query.lastIndex = 0;
  31.           var line = doc.getLine(pos.line).slice(0, pos.ch), cutOff = 0, match, start;
  32.           for (;;) {
  33.             query.lastIndex = cutOff;
  34.             var newMatch = query.exec(line);
  35.             if (!newMatch) break;
  36.             match = newMatch;
  37.             start = match.index;
  38.             cutOff = match.index + (match[0].length || 1);
  39.             if (cutOff == line.length) break;
  40.           }
  41.           var matchLen = (match && match[0].length) || 0;
  42.           if (!matchLen) {
  43.             if (start == 0 && line.length == 0) {match = undefined;}
  44.             else if (start != doc.getLine(pos.line).length) {
  45.               matchLen++;
  46.             }
  47.           }
  48.         } else {
  49.           query.lastIndex = pos.ch;
  50.           var line = doc.getLine(pos.line), match = query.exec(line);
  51.           var matchLen = (match && match[0].length) || 0;
  52.           var start = match && match.index;
  53.           if (start + matchLen != line.length && !matchLen) matchLen = 1;
  54.         }
  55.         if (match && matchLen)
  56.           return {from: Pos(pos.line, start),
  57.                   to: Pos(pos.line, start + matchLen),
  58.                   match: match};
  59.       };
  60.     } else { // String query
  61.       var origQuery = query;
  62.       if (caseFold) query = query.toLowerCase();
  63.       var fold = caseFold ? function(str){return str.toLowerCase();} : function(str){return str;};
  64.       var target = query.split("\n");
  65.       // Different methods for single-line and multi-line queries
  66.       if (target.length == 1) {
  67.         if (!query.length) {
  68.           // Empty string would match anything and never progress, so
  69.           // we define it to match nothing instead.
  70.           this.matches = function() {};
  71.         } else {
  72.           this.matches = function(reverse, pos) {
  73.             if (reverse) {
  74.               var orig = doc.getLine(pos.line).slice(0, pos.ch), line = fold(orig);
  75.               var match = line.lastIndexOf(query);
  76.               if (match > -1) {
  77.                 match = adjustPos(orig, line, match);
  78.                 return {from: Pos(pos.line, match), to: Pos(pos.line, match + origQuery.length)};
  79.               }
  80.              } else {
  81.                var orig = doc.getLine(pos.line).slice(pos.ch), line = fold(orig);
  82.                var match = line.indexOf(query);
  83.                if (match > -1) {
  84.                  match = adjustPos(orig, line, match) + pos.ch;
  85.                  return {from: Pos(pos.line, match), to: Pos(pos.line, match + origQuery.length)};
  86.                }
  87.             }
  88.           };
  89.         }
  90.       } else {
  91.         var origTarget = origQuery.split("\n");
  92.         this.matches = function(reverse, pos) {
  93.           var last = target.length - 1;
  94.           if (reverse) {
  95.             if (pos.line - (target.length - 1) < doc.firstLine()) return;
  96.             if (fold(doc.getLine(pos.line).slice(0, origTarget[last].length)) != target[target.length - 1]) return;
  97.             var to = Pos(pos.line, origTarget[last].length);
  98.             for (var ln = pos.line - 1, i = last - 1; i >= 1; --i, --ln)
  99.               if (target[i] != fold(doc.getLine(ln))) return;
  100.             var line = doc.getLine(ln), cut = line.length - origTarget[0].length;
  101.             if (fold(line.slice(cut)) != target[0]) return;
  102.             return {from: Pos(ln, cut), to: to};
  103.           } else {
  104.             if (pos.line + (target.length - 1) > doc.lastLine()) return;
  105.             var line = doc.getLine(pos.line), cut = line.length - origTarget[0].length;
  106.             if (fold(line.slice(cut)) != target[0]) return;
  107.             var from = Pos(pos.line, cut);
  108.             for (var ln = pos.line + 1, i = 1; i < last; ++i, ++ln)
  109.               if (target[i] != fold(doc.getLine(ln))) return;
  110.             if (fold(doc.getLine(ln).slice(0, origTarget[last].length)) != target[last]) return;
  111.             return {from: from, to: Pos(ln, origTarget[last].length)};
  112.           }
  113.         };
  114.       }
  115.     }
  116.   }
  117.  
  118.   SearchCursor.prototype = {
  119.     findNext: function() {return this.find(false);},
  120.     findPrevious: function() {return this.find(true);},
  121.  
  122.     find: function(reverse) {
  123.       var self = this, pos = this.doc.clipPos(reverse ? this.pos.from : this.pos.to);
  124.       function savePosAndFail(line) {
  125.         var pos = Pos(line, 0);
  126.         self.pos = {from: pos, to: pos};
  127.         self.atOccurrence = false;
  128.         return false;
  129.       }
  130.  
  131.       for (;;) {
  132.         if (this.pos = this.matches(reverse, pos)) {
  133.           this.atOccurrence = true;
  134.           return this.pos.match || true;
  135.         }
  136.         if (reverse) {
  137.           if (!pos.line) return savePosAndFail(0);
  138.           pos = Pos(pos.line-1, this.doc.getLine(pos.line-1).length);
  139.         }
  140.         else {
  141.           var maxLine = this.doc.lineCount();
  142.           if (pos.line == maxLine - 1) return savePosAndFail(maxLine);
  143.           pos = Pos(pos.line + 1, 0);
  144.         }
  145.       }
  146.     },
  147.  
  148.     from: function() {if (this.atOccurrence) return this.pos.from;},
  149.     to: function() {if (this.atOccurrence) return this.pos.to;},
  150.  
  151.     replace: function(newText, origin) {
  152.       if (!this.atOccurrence) return;
  153.       var lines = CodeMirror.splitLines(newText);
  154.       this.doc.replaceRange(lines, this.pos.from, this.pos.to, origin);
  155.       this.pos.to = Pos(this.pos.from.line + lines.length - 1,
  156.                         lines[lines.length - 1].length + (lines.length == 1 ? this.pos.from.ch : 0));
  157.     }
  158.   };
  159.  
  160.   // Maps a position in a case-folded line back to a position in the original line
  161.   // (compensating for codepoints increasing in number during folding)
  162.   function adjustPos(orig, folded, pos) {
  163.     if (orig.length == folded.length) return pos;
  164.     for (var pos1 = Math.min(pos, orig.length);;) {
  165.       var len1 = orig.slice(0, pos1).toLowerCase().length;
  166.       if (len1 < pos) ++pos1;
  167.       else if (len1 > pos) --pos1;
  168.       else return pos1;
  169.     }
  170.   }
  171.  
  172.   CodeMirror.defineExtension("getSearchCursor", function(query, pos, caseFold) {
  173.     return new SearchCursor(this.doc, query, pos, caseFold);
  174.   });
  175.   CodeMirror.defineDocExtension("getSearchCursor", function(query, pos, caseFold) {
  176.     return new SearchCursor(this, query, pos, caseFold);
  177.   });
  178.  
  179.   CodeMirror.defineExtension("selectMatches", function(query, caseFold) {
  180.     var ranges = [];
  181.     var cur = this.getSearchCursor(query, this.getCursor("from"), caseFold);
  182.     while (cur.findNext()) {
  183.       if (CodeMirror.cmpPos(cur.to(), this.getCursor("to")) > 0) break;
  184.       ranges.push({anchor: cur.from(), head: cur.to()});
  185.     }
  186.     if (ranges.length)
  187.       this.setSelections(ranges, 0);
  188.   });
  189. });

Raw Paste


Login or Register to edit or fork this paste. It's free.