diff --git a/src/search/FindReplace.js b/src/search/FindReplace.js
index 93daa4c5f77..f62bbbc83af 100644
--- a/src/search/FindReplace.js
+++ b/src/search/FindReplace.js
@@ -26,13 +26,12 @@
/*
* Adds Find and Replace commands
+ *
+ * Originally based on the code in CodeMirror2/lib/util/search.js.
*
* Define search commands. Depends on dialog.js or another
* implementation of the openDialog method.
*
- * This code was copied from CodeMirror2/lib/util/search.js so that the UI strings
- * could be localized.
- *
* Replace works a little oddly -- it will do the replace on the next findNext press.
* You prevent a replace by making sure the match is no longer selected when hitting
* findNext.
@@ -80,6 +79,10 @@ define(function (require, exports, module) {
fs[0]();
}
}
+
+ function getDialogTextField() {
+ return $(".CodeMirror-dialog input[type='text']");
+ }
function parseQuery(query) {
var isRE = query.match(/^\/(.*)\/([a-z]*)$/);
@@ -102,45 +105,69 @@ define(function (require, exports, module) {
});
}
+ function clearSearch(cm) {
+ cm.operation(function () {
+ var state = getSearchState(cm),
+ i;
+ if (!state.query) {
+ return;
+ }
+ state.query = null;
+
+ // Clear highlights
+ for (i = 0; i < state.marked.length; ++i) {
+ state.marked[i].clear();
+ }
+ state.marked.length = 0;
+ });
+ }
+
var queryDialog = Strings.CMD_FIND +
': (' +
Strings.SEARCH_REGEXP_INFO + ')';
+ /**
+ * If no search pending, opens the search dialog. If search is already open, moves to
+ * next/prev result (depending on 'rev')
+ */
function doSearch(cm, rev) {
var state = getSearchState(cm);
if (state.query) {
return findNext(cm, rev);
}
- dialog(cm, queryDialog, Strings.CMD_FIND, function (query) {
+
+ var searchStartPos = cm.getCursor();
+
+ // Called each time the search query changes while being typed. Jumps to the first matching
+ // result, starting from the original cursor position
+ function findFirst(query) {
cm.operation(function () {
- if (!query || state.query) {
+ if (!query) {
return;
}
+
+ if (state.query) {
+ clearSearch(cm); // clear highlights from previous query
+ }
state.query = parseQuery(query);
+
+ // Highlight all matches
+ // FUTURE: if last query was prefix of this one, could optimize by filtering existing result set
if (cm.lineCount() < 2000) { // This is too expensive on big documents.
var cursor = getSearchCursor(cm, query);
while (cursor.findNext()) {
state.marked.push(cm.markText(cursor.from(), cursor.to(), "CodeMirror-searching"));
}
}
- state.posFrom = state.posTo = cm.getCursor();
+
+ state.posFrom = state.posTo = searchStartPos;
findNext(cm, rev);
});
- });
- }
-
- function clearSearch(cm) {
- cm.operation(function () {
- var state = getSearchState(cm),
- i;
- if (!state.query) {
- return;
- }
- state.query = null;
- for (i = 0; i < state.marked.length; ++i) {
- state.marked[i].clear();
- }
- state.marked.length = 0;
+ }
+
+ dialog(cm, queryDialog, Strings.CMD_FIND, findFirst);
+ getDialogTextField().on("input", function () {
+ findFirst(getDialogTextField().attr("value"));
});
}
@@ -218,7 +245,7 @@ define(function (require, exports, module) {
doSearch(codeMirror);
// Prepopulate the search field with the current selection, if any
- $(".CodeMirror-dialog input[type='text']")
+ getDialogTextField()
.attr("value", codeMirror.getSelection())
.get(0).select();
}