Skip to content
This repository was archived by the owner on Sep 6, 2021. It is now read-only.

Commit b337028

Browse files
committed
Incremental search while typing in the Find bar
Although highlighting matches is turned off in our CSS, the changes here were tested & should work when/if highlights are made visible again. Also includes some docs improvements.
1 parent 4c7b775 commit b337028

1 file changed

Lines changed: 49 additions & 22 deletions

File tree

src/search/FindReplace.js

Lines changed: 49 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -26,13 +26,12 @@
2626

2727
/*
2828
* Adds Find and Replace commands
29+
*
30+
* Originally based on the code in CodeMirror2/lib/util/search.js.
2931
*
3032
* Define search commands. Depends on dialog.js or another
3133
* implementation of the openDialog method.
3234
*
33-
* This code was copied from CodeMirror2/lib/util/search.js so that the UI strings
34-
* could be localized.
35-
*
3635
* Replace works a little oddly -- it will do the replace on the next findNext press.
3736
* You prevent a replace by making sure the match is no longer selected when hitting
3837
* findNext.
@@ -80,6 +79,10 @@ define(function (require, exports, module) {
8079
fs[0]();
8180
}
8281
}
82+
83+
function getDialogTextField() {
84+
return $(".CodeMirror-dialog input[type='text']");
85+
}
8386

8487
function parseQuery(query) {
8588
var isRE = query.match(/^\/(.*)\/([a-z]*)$/);
@@ -102,45 +105,69 @@ define(function (require, exports, module) {
102105
});
103106
}
104107

108+
function clearSearch(cm) {
109+
cm.operation(function () {
110+
var state = getSearchState(cm),
111+
i;
112+
if (!state.query) {
113+
return;
114+
}
115+
state.query = null;
116+
117+
// Clear highlights
118+
for (i = 0; i < state.marked.length; ++i) {
119+
state.marked[i].clear();
120+
}
121+
state.marked.length = 0;
122+
});
123+
}
124+
105125
var queryDialog = Strings.CMD_FIND +
106126
': <input type="text" style="width: 10em"/> <span style="color: #888">(' +
107127
Strings.SEARCH_REGEXP_INFO + ')</span>';
108128

129+
/**
130+
* If no search pending, opens the search dialog. If search is already open, moves to
131+
* next/prev result (depending on 'rev')
132+
*/
109133
function doSearch(cm, rev) {
110134
var state = getSearchState(cm);
111135
if (state.query) {
112136
return findNext(cm, rev);
113137
}
114-
dialog(cm, queryDialog, Strings.CMD_FIND, function (query) {
138+
139+
var searchStartPos = cm.getCursor();
140+
141+
// Called each time the search query changes while being typed. Jumps to the first matching
142+
// result, starting from the original cursor position
143+
function findFirst(query) {
115144
cm.operation(function () {
116-
if (!query || state.query) {
145+
if (!query) {
117146
return;
118147
}
148+
149+
if (state.query) {
150+
clearSearch(cm); // clear highlights from previous query
151+
}
119152
state.query = parseQuery(query);
153+
154+
// Highlight all matches
155+
// FUTURE: if last query was prefix of this one, could optimize by filtering existing result set
120156
if (cm.lineCount() < 2000) { // This is too expensive on big documents.
121157
var cursor = getSearchCursor(cm, query);
122158
while (cursor.findNext()) {
123159
state.marked.push(cm.markText(cursor.from(), cursor.to(), "CodeMirror-searching"));
124160
}
125161
}
126-
state.posFrom = state.posTo = cm.getCursor();
162+
163+
state.posFrom = state.posTo = searchStartPos;
127164
findNext(cm, rev);
128165
});
129-
});
130-
}
131-
132-
function clearSearch(cm) {
133-
cm.operation(function () {
134-
var state = getSearchState(cm),
135-
i;
136-
if (!state.query) {
137-
return;
138-
}
139-
state.query = null;
140-
for (i = 0; i < state.marked.length; ++i) {
141-
state.marked[i].clear();
142-
}
143-
state.marked.length = 0;
166+
}
167+
168+
dialog(cm, queryDialog, Strings.CMD_FIND, findFirst);
169+
getDialogTextField().on("input", function () {
170+
findFirst(getDialogTextField().attr("value"));
144171
});
145172
}
146173

@@ -218,7 +245,7 @@ define(function (require, exports, module) {
218245
doSearch(codeMirror);
219246

220247
// Prepopulate the search field with the current selection, if any
221-
$(".CodeMirror-dialog input[type='text']")
248+
getDialogTextField()
222249
.attr("value", codeMirror.getSelection())
223250
.get(0).select();
224251
}

0 commit comments

Comments
 (0)