|
|
@@ -1,10 +1,5 @@
|
|
|
-// 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.
|
|
|
+// based on CodeMirror/addon/search/search.js
|
|
|
+// Modified by Gerald <[email protected]>
|
|
|
|
|
|
(function() {
|
|
|
function searchOverlay(query) {
|
|
|
@@ -33,34 +28,80 @@
|
|
|
// Heuristic: if the query string is all lowercase, do a case insensitive search.
|
|
|
return cm.getSearchCursor(query, pos, typeof query == "string" && query == query.toLowerCase());
|
|
|
}
|
|
|
- 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]();
|
|
|
+ var dialog=null;
|
|
|
+ function openDialog(cm, state, rep) {
|
|
|
+ function close(){
|
|
|
+ if(closed) return; closed=true;
|
|
|
+ cm.removeOverlay(state.overlay);
|
|
|
+ dialog.parentNode.removeChild(dialog);
|
|
|
+ dialog=null;clearSearch(cm);
|
|
|
+ cm.focus();
|
|
|
+ }
|
|
|
+ if(!dialog) {
|
|
|
+ var wrap = cm.getWrapperElement();
|
|
|
+ dialog = wrap.appendChild(document.createElement("div"));
|
|
|
+ dialog.className='CodeMirror-dialog';
|
|
|
+ }
|
|
|
+ var text='<input class=CodeMirror-search placeholder="Search for"><button class=CodeMirror-findNext>></button><button class=CodeMirror-findPrev><</button><button class=CodeMirror-cancel>×</button>',closed=false,iS,iR;
|
|
|
+ if(rep) text+='<br><input class=CodeMirror-replace placeholder="Replace with"><button class=CodeMirror-replaceNext>Replace</button><button class=CodeMirror-replaceAll>All</button>';
|
|
|
+ dialog.innerHTML=text;
|
|
|
+ iS=dialog.querySelector('.CodeMirror-search');
|
|
|
+ CodeMirror.on(dialog.querySelector('.CodeMirror-findNext'), "click", function(e) {findNext(cm);});
|
|
|
+ CodeMirror.on(dialog.querySelector('.CodeMirror-findPrev'), "click", function(e) {findNext(cm, true);});
|
|
|
+ CodeMirror.on(dialog.querySelector('.CodeMirror-cancel'), "click", close);
|
|
|
+ CodeMirror.on(dialog, "keydown", function(e) {
|
|
|
+ switch(e.keyCode) {
|
|
|
+ case 27:
|
|
|
+ close();break;
|
|
|
+ default:
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ CodeMirror.e_stop(e);
|
|
|
+ });
|
|
|
+ CodeMirror.on(iS, "keydown", function(e) {
|
|
|
+ switch(e.keyCode) {
|
|
|
+ case 13:
|
|
|
+ findNext(cm, e.shiftKey);break;
|
|
|
+ default:
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ CodeMirror.e_stop(e);
|
|
|
+ });
|
|
|
+ CodeMirror.on(iS, "keyup", function(e) {
|
|
|
+ if(state.query!=iS.value) {
|
|
|
+ state.query=iS.value;
|
|
|
+ cm.operation(function() {
|
|
|
+ cm.removeOverlay(state.overlay);
|
|
|
+ if(!state.query) return;
|
|
|
+ state.overlay = searchOverlay(state.query);
|
|
|
+ cm.addOverlay(state.overlay);
|
|
|
+ state.posTo=state.posFrom;
|
|
|
+ findNext(cm);
|
|
|
+ });
|
|
|
+ }
|
|
|
+ });
|
|
|
+ if(rep) {
|
|
|
+ iR=dialog.querySelector('.CodeMirror-replace');
|
|
|
+ function _replace(all) {
|
|
|
+ state.replace=iR.value;
|
|
|
+ replace(cm, all);
|
|
|
+ }
|
|
|
+ CodeMirror.on(dialog.querySelector('.CodeMirror-replaceNext'), "click", function(e) {_replace();});
|
|
|
+ CodeMirror.on(dialog.querySelector('.CodeMirror-replaceAll'), "click", function(e) {_replace(true);});
|
|
|
+ CodeMirror.on(iR, "keydown", function(e) {
|
|
|
+ switch(e.keyCode) {
|
|
|
+ default:
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ CodeMirror.e_stop(e);
|
|
|
+ });
|
|
|
+ }
|
|
|
+ iS.focus();
|
|
|
}
|
|
|
- function parseQuery(query) {
|
|
|
- var isRE = query.match(/^\/(.*)\/([a-z]*)$/);
|
|
|
- return isRE ? new RegExp(isRE[1], isRE[2].indexOf("i") == -1 ? "" : "i") : 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);
|
|
|
- cm.removeOverlay(state.overlay);
|
|
|
- state.overlay = searchOverlay(state.query);
|
|
|
- cm.addOverlay(state.overlay);
|
|
|
- state.posFrom = state.posTo = cm.getCursor();
|
|
|
- findNext(cm, rev);
|
|
|
- });
|
|
|
- });
|
|
|
+ openDialog(cm, state);
|
|
|
}
|
|
|
function findNext(cm, rev) {cm.operation(function() {
|
|
|
var state = getSearchState(cm);
|
|
|
@@ -79,47 +120,21 @@
|
|
|
cm.removeOverlay(state.overlay);
|
|
|
});}
|
|
|
|
|
|
- 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 = getSearchCursor(cm, query); cursor.findNext();) {
|
|
|
- if (typeof query != "string") {
|
|
|
- var match = cm.getRange(cursor.from(), cursor.to()).match(query);
|
|
|
- cursor.replace(text.replace(/\$(\d)/, function(_, i) {return match[i];}));
|
|
|
- } else cursor.replace(text);
|
|
|
- }
|
|
|
- });
|
|
|
- } else {
|
|
|
- clearSearch(cm);
|
|
|
- var cursor = getSearchCursor(cm, query, cm.getCursor());
|
|
|
- var advance = function() {
|
|
|
- var start = cursor.from(), match;
|
|
|
- if (!(match = cursor.findNext())) {
|
|
|
- cursor = getSearchCursor(cm, query);
|
|
|
- if (!(match = cursor.findNext()) ||
|
|
|
- (start && 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]);
|
|
|
- };
|
|
|
- var doReplace = function(match) {
|
|
|
- cursor.replace(typeof query == "string" ? text :
|
|
|
- text.replace(/\$(\d)/, function(_, i) {return match[i];}));
|
|
|
- advance();
|
|
|
- };
|
|
|
- advance();
|
|
|
- }
|
|
|
- });
|
|
|
- });
|
|
|
+ var state = getSearchState(cm);
|
|
|
+ if (!state.query) return openDialog(cm, state, true);
|
|
|
+ if(all) cm.operation(function() {
|
|
|
+ for (var cursor = getSearchCursor(cm, state.query); cursor.findNext();) {
|
|
|
+ cursor.replace(state.replace);
|
|
|
+ }
|
|
|
+ }); else {
|
|
|
+ var s=cm.getCursor('start'),e=cm.getCursor('end');
|
|
|
+ state.posTo=state.posFrom;findNext(cm);
|
|
|
+ var s1=cm.getCursor('start'),e1=cm.getCursor('end');
|
|
|
+ if(s.line==s1.line&&s.ch==s1.ch&&e.line==e1.line&&e.ch==e1.ch) {
|
|
|
+ cm.replaceRange(state.replace,s1,e1);findNext(cm);
|
|
|
+ }
|
|
|
+ }
|
|
|
}
|
|
|
|
|
|
CodeMirror.commands.find = function(cm) {clearSearch(cm); doSearch(cm);};
|