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