|
8 | 8 |
|
9 | 9 | (function() { |
10 | 10 | function SearchState() { |
11 | | - this.posFrom = this.posTo = null; |
12 | | - this.query = this.replacing = null; this.marked = []; |
| 11 | + this.posFrom = this.posTo = this.query = null; |
| 12 | + this.marked = []; |
13 | 13 | } |
14 | 14 | function getSearchState(cm) { |
15 | 15 | return cm._searchState || (cm._searchState = new SearchState()); |
|
18 | 18 | if (cm.openDialog) cm.openDialog(text, f); |
19 | 19 | else f(prompt(shortText, "")); |
20 | 20 | } |
| 21 | + function confirmDialog(cm, text, shortText, fs) { |
| 22 | + if (cm.openConfirm) cm.openConfirm(text, fs); |
| 23 | + else if (confirm(shortText)) fs[0](); |
| 24 | + } |
21 | 25 | function parseQuery(query) { |
22 | 26 | var isRE = query.match(/^\/(.*)\/$/); |
23 | 27 | return isRE ? new RegExp(isRE[1]) : query; |
|
42 | 46 | } |
43 | 47 | function findNext(cm, rev) {cm.operation(function() { |
44 | 48 | var state = getSearchState(cm); |
45 | | - if (state.replacing) { |
46 | | - var sel = cm.getSelection(); |
47 | | - if (typeof state.query == "string") { |
48 | | - if (sel == state.query) cm.replaceSelection(state.replacing); |
49 | | - } else { |
50 | | - var match = sel.match(state.query); |
51 | | - if (match) cm.replaceSelection(state.replacing.replace(/\$(\d)/, function(w, i) {return match[i];})); |
52 | | - } |
53 | | - } |
54 | 49 | var cursor = cm.getSearchCursor(state.query, rev ? state.posFrom : state.posTo); |
55 | 50 | if (!cursor.find(rev)) { |
56 | 51 | cursor = cm.getSearchCursor(state.query, rev ? {line: cm.lineCount() - 1} : {line: 0, ch: 0}); |
|
62 | 57 | function clearSearch(cm) {cm.operation(function() { |
63 | 58 | var state = getSearchState(cm); |
64 | 59 | if (!state.query) return; |
65 | | - state.query = state.replacing = null; |
| 60 | + state.query = null; |
66 | 61 | for (var i = 0; i < state.marked.length; ++i) state.marked[i].clear(); |
67 | 62 | state.marked.length = 0; |
68 | 63 | })} |
69 | 64 |
|
70 | 65 | var replaceQueryDialog = |
71 | 66 | 'Replace: <input type="text" style="width: 10em"> <span style="color: #888">(Use /re/ syntax for regexp search)</span>'; |
72 | 67 | var replacementQueryDialog = 'With: <input type="text" style="width: 10em">'; |
| 68 | + var doReplaceConfirm = "Replace? <button>Yes</button> <button>No</button> <button>Stop</button>"; |
73 | 69 | function replace(cm, all) { |
74 | 70 | dialog(cm, replaceQueryDialog, "Replace:", function(query) { |
75 | 71 | if (!query) return; |
|
85 | 81 | } |
86 | 82 | }); |
87 | 83 | } else { |
88 | | - var state = getSearchState(cm); |
89 | 84 | clearSearch(cm); |
90 | | - state.query = query; |
91 | | - state.replacing = text; |
92 | | - state.posFrom = state.posTo = cm.getCursor(); |
93 | | - findNext(cm); |
| 85 | + var cursor = cm.getSearchCursor(query, cm.getCursor()); |
| 86 | + function advance() { |
| 87 | + var start = cursor.from(), match; |
| 88 | + if (!(match = cursor.findNext())) { |
| 89 | + cursor = cm.getSearchCursor(query); |
| 90 | + if (!(match = cursor.findNext()) || |
| 91 | + (cursor.from().line == start.line && cursor.from().ch == start.ch)) return; |
| 92 | + } |
| 93 | + cm.setSelection(cursor.from(), cursor.to()); |
| 94 | + confirmDialog(cm, doReplaceConfirm, "Replace?", |
| 95 | + [function() {doReplace(match);}, advance]); |
| 96 | + } |
| 97 | + function doReplace(match) { |
| 98 | + cursor.replace(typeof query == "string" ? text : |
| 99 | + text.replace(/\$(\d)/, function(w, i) {return match[i];})); |
| 100 | + advance(); |
| 101 | + } |
| 102 | + advance(); |
94 | 103 | } |
95 | 104 | }); |
96 | 105 | }); |
|
0 commit comments