topical media & game development

talk show tell print

mobile-query-three-www-live-playground-vendor-CodeMirror2-lib-util-search.js / js



  // Define search commands. Depends on dialog.js or another
  // implementation of the openDialog method.
  
  // Replace works a little oddly -- it will do the replace on the next
  // Ctrl-G (or whatever is bound to findNext) press. You prevent a
  // replace by making sure the match is no longer selected when hitting
  // Ctrl-G.
  
  (function() {
    function SearchState() {
      this.posFrom = this.posTo = this.query = null;
      this.marked = [];
    }
    function getSearchState(cm) {
      return cm._searchState || (cm._searchState = new SearchState());
    }
    function dialog(cm, text, shortText, f) {
      if (cm.openDialog) cm.openDialog(text, f);
      else f(prompt(shortText, ""));
    }
    function confirmDialog(cm, text, shortText, fs) {
      if (cm.openConfirm) cm.openConfirm(text, fs);
      else if (confirm(shortText)) fs[0]();
    }
    function parseQuery(query) {
      var isRE = query.match(/^\/(.*)\//);
      return isRE ? new RegExp(isRE[1]) : query;
    }
    var queryDialog =
      'Search: <input type="text" style="width: 10em"> <span style="color: #888">(Use /re/ syntax for regexp search)</span>';
    function doSearch(cm, rev) {
      var state = getSearchState(cm);
      if (state.query) return findNext(cm, rev);
      dialog(cm, queryDialog, "Search for:", function(query) {
        cm.operation(function() {
          if (!query || state.query) return;
          state.query = parseQuery(query);
          if (cm.lineCount() < 2000) { // This is too expensive on big documents.
            for (var cursor = cm.getSearchCursor(query); cursor.findNext();)
              state.marked.push(cm.markText(cursor.from(), cursor.to(), "CodeMirror-searching"));
          }
          state.posFrom = state.posTo = cm.getCursor();
          findNext(cm, rev);
        });
      });
    }
    function findNext(cm, rev) {cm.operation(function() {
      var state = getSearchState(cm);
      var cursor = cm.getSearchCursor(state.query, rev ? state.posFrom : state.posTo);
      if (!cursor.find(rev)) {
        cursor = cm.getSearchCursor(state.query, rev ? {line: cm.lineCount() - 1} : {line: 0, ch: 0});
        if (!cursor.find(rev)) return;
      }
      cm.setSelection(cursor.from(), cursor.to());
      state.posFrom = cursor.from(); state.posTo = cursor.to();
    })}
    function clearSearch(cm) {cm.operation(function() {
      var state = getSearchState(cm);
      if (!state.query) return;
      state.query = null;
      for (var i = 0; i < state.marked.length; ++i) state.marked[i].clear();
      state.marked.length = 0;
    })}
  
    var replaceQueryDialog =
      'Replace: <input type="text" style="width: 10em"> <span style="color: #888">(Use /re/ syntax for regexp search)</span>';
    var replacementQueryDialog = 'With: <input type="text" style="width: 10em">';
    var doReplaceConfirm = "Replace? <button>Yes</button> <button>No</button> <button>Stop</button>";
    function replace(cm, all) {
      dialog(cm, replaceQueryDialog, "Replace:", function(query) {
        if (!query) return;
        query = parseQuery(query);
        dialog(cm, replacementQueryDialog, "Replace with:", function(text) {
          if (all) {
            cm.operation(function() {
              for (var cursor = cm.getSearchCursor(query); cursor.findNext();) {
                if (typeof query != "string") {
                  var match = cm.getRange(cursor.from(), cursor.to()).match(query);
                  cursor.replace(text.replace(/$(\d)/, function(w, i) {return match[i];}));
                } else cursor.replace(text);
              }
            });
          } else {
            clearSearch(cm);
            var cursor = cm.getSearchCursor(query, cm.getCursor());
            function advance() {
              var start = cursor.from(), match;
              if (!(match = cursor.findNext())) {
                cursor = cm.getSearchCursor(query);
                if (!(match = cursor.findNext()) ||
                    (cursor.from().line == start.line && cursor.from().ch == start.ch)) return;
              }
              cm.setSelection(cursor.from(), cursor.to());
              confirmDialog(cm, doReplaceConfirm, "Replace?",
                            [function() {doReplace(match);}, advance]);
            }
            function doReplace(match) {
              cursor.replace(typeof query == "string" ? text :
                             text.replace(/$(\d)/, function(w, i) {return match[i];}));
              advance();
            }
            advance();
          }
        });
      });
    }
  
    CodeMirror.commands.find = function(cm) {clearSearch(cm); doSearch(cm);};
    CodeMirror.commands.findNext = doSearch;
    CodeMirror.commands.findPrev = function(cm) {doSearch(cm, true);};
    CodeMirror.commands.clearSearch = clearSearch;
    CodeMirror.commands.replace = replace;
    CodeMirror.commands.replaceAll = function(cm) {replace(cm, true);};
  })();
  


(C) Æliens 04/09/2009

You may not copy or print any of this material without explicit permission of the author or the publisher. In case of other copyright issues, contact the author.