Skip to content

Commit 6ae6b18

Browse files
committed
Improve replace UI in search script
1 parent 99b5a84 commit 6ae6b18

File tree

2 files changed

+86
-42
lines changed

2 files changed

+86
-42
lines changed

lib/util/dialog.js

Lines changed: 60 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +1,63 @@
11
// Open simple dialogs on top of an editor. Relies on dialog.css.
22

3-
CodeMirror.defineExtension("openDialog", function(template, callback) {
4-
var wrap = this.getWrapperElement();
5-
var dialog = wrap.insertBefore(document.createElement("div"), wrap.firstChild);
6-
dialog.className = "CodeMirror-dialog";
7-
dialog.innerHTML = '<div>' + template + '</div>';
8-
var closed = false, me = this;
9-
function close() {
10-
if (closed) return;
11-
closed = true;
12-
dialog.parentNode.removeChild(dialog);
3+
(function() {
4+
function dialogDiv(cm, template) {
5+
var wrap = cm.getWrapperElement();
6+
var dialog = wrap.insertBefore(document.createElement("div"), wrap.firstChild);
7+
dialog.className = "CodeMirror-dialog";
8+
dialog.innerHTML = '<div>' + template + '</div>';
9+
return dialog;
1310
}
14-
var inp = dialog.getElementsByTagName("input")[0];
15-
if (inp) {
16-
CodeMirror.connect(inp, "keydown", function(e) {
17-
if (e.keyCode == 13 || e.keyCode == 27) {
18-
CodeMirror.e_stop(e);
19-
close();
20-
me.focus();
21-
if (e.keyCode == 13) callback(inp.value);
22-
}
23-
});
24-
inp.focus();
25-
CodeMirror.connect(inp, "blur", close);
26-
}
27-
return close;
28-
});
11+
12+
CodeMirror.defineExtension("openDialog", function(template, callback) {
13+
var dialog = dialogDiv(this, template);
14+
var closed = false, me = this;
15+
function close() {
16+
if (closed) return;
17+
closed = true;
18+
dialog.parentNode.removeChild(dialog);
19+
}
20+
var inp = dialog.getElementsByTagName("input")[0];
21+
if (inp) {
22+
CodeMirror.connect(inp, "keydown", function(e) {
23+
if (e.keyCode == 13 || e.keyCode == 27) {
24+
CodeMirror.e_stop(e);
25+
close();
26+
me.focus();
27+
if (e.keyCode == 13) callback(inp.value);
28+
}
29+
});
30+
inp.focus();
31+
CodeMirror.connect(inp, "blur", close);
32+
}
33+
return close;
34+
});
35+
36+
CodeMirror.defineExtension("openConfirm", function(template, callbacks) {
37+
var dialog = dialogDiv(this, template);
38+
var buttons = dialog.getElementsByTagName("button");
39+
var closed = false, me = this, blurring = 1;
40+
function close() {
41+
if (closed) return;
42+
closed = true;
43+
dialog.parentNode.removeChild(dialog);
44+
me.focus();
45+
}
46+
buttons[0].focus();
47+
for (var i = 0; i < buttons.length; ++i) {
48+
var b = buttons[i];
49+
(function(callback) {
50+
CodeMirror.connect(b, "click", function(e) {
51+
CodeMirror.e_preventDefault(e);
52+
close();
53+
if (callback) callback(me);
54+
});
55+
})(callbacks[i]);
56+
CodeMirror.connect(b, "blur", function() {
57+
--blurring;
58+
setTimeout(function() { if (blurring <= 0) close(); }, 200);
59+
});
60+
CodeMirror.connect(b, "focus", function() { ++blurring; });
61+
}
62+
});
63+
})();

lib/util/search.js

Lines changed: 26 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -8,8 +8,8 @@
88

99
(function() {
1010
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 = [];
1313
}
1414
function getSearchState(cm) {
1515
return cm._searchState || (cm._searchState = new SearchState());
@@ -18,6 +18,10 @@
1818
if (cm.openDialog) cm.openDialog(text, f);
1919
else f(prompt(shortText, ""));
2020
}
21+
function confirmDialog(cm, text, shortText, fs) {
22+
if (cm.openConfirm) cm.openConfirm(text, fs);
23+
else if (confirm(shortText)) fs[0]();
24+
}
2125
function parseQuery(query) {
2226
var isRE = query.match(/^\/(.*)\/$/);
2327
return isRE ? new RegExp(isRE[1]) : query;
@@ -42,15 +46,6 @@
4246
}
4347
function findNext(cm, rev) {cm.operation(function() {
4448
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-
}
5449
var cursor = cm.getSearchCursor(state.query, rev ? state.posFrom : state.posTo);
5550
if (!cursor.find(rev)) {
5651
cursor = cm.getSearchCursor(state.query, rev ? {line: cm.lineCount() - 1} : {line: 0, ch: 0});
@@ -62,14 +57,15 @@
6257
function clearSearch(cm) {cm.operation(function() {
6358
var state = getSearchState(cm);
6459
if (!state.query) return;
65-
state.query = state.replacing = null;
60+
state.query = null;
6661
for (var i = 0; i < state.marked.length; ++i) state.marked[i].clear();
6762
state.marked.length = 0;
6863
})}
6964

7065
var replaceQueryDialog =
7166
'Replace: <input type="text" style="width: 10em"> <span style="color: #888">(Use /re/ syntax for regexp search)</span>';
7267
var replacementQueryDialog = 'With: <input type="text" style="width: 10em">';
68+
var doReplaceConfirm = "Replace? <button>Yes</button> <button>No</button> <button>Stop</button>";
7369
function replace(cm, all) {
7470
dialog(cm, replaceQueryDialog, "Replace:", function(query) {
7571
if (!query) return;
@@ -85,12 +81,25 @@
8581
}
8682
});
8783
} else {
88-
var state = getSearchState(cm);
8984
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();
94103
}
95104
});
96105
});

0 commit comments

Comments
 (0)