Skip to content

Commit 6ed23aa

Browse files
mightyguavamarijnh
authored andcommitted
[vim keymap] Add count and empty query support for :s
1 parent 15d03e1 commit 6ed23aa

File tree

2 files changed

+38
-8
lines changed

2 files changed

+38
-8
lines changed

keymap/vim.js

Lines changed: 20 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2283,27 +2283,39 @@
22832283
var regexPart = argString.substring(slashes[0] + 1, slashes[1]);
22842284
var replacePart = '';
22852285
var flagsPart;
2286+
var count;
22862287
if (slashes[1]) {
22872288
replacePart = argString.substring(slashes[1] + 1, slashes[2]);
22882289
}
22892290
if (slashes[2]) {
2290-
flagsPart = argString.substring(slashes[2] + 1);
2291+
// After the 3rd slash, we can have flags followed by a space followed
2292+
// by count.
2293+
var trailing = argString.substring(slashes[2] + 1).split(' ');
2294+
flagsPart = trailing[0];
2295+
count = parseInt(trailing[1]);
22912296
}
22922297
if (flagsPart) {
22932298
regexPart = regexPart + '/' + flagsPart;
22942299
}
2295-
updateSearchQuery(cm, regexPart, true /** ignoreCase */,
2300+
if (regexPart) {
2301+
// If regex part is empty, then use the previous query. Otherwise use
2302+
// the regex part as the new query.
2303+
updateSearchQuery(cm, regexPart, true /** ignoreCase */,
22962304
true /** smartCase */);
2305+
}
22972306
var state = getSearchState(cm);
22982307
var query = state.getQuery();
2299-
var startPos = clipCursorToContent(cm, { line: params.line || 0,
2300-
ch: 0 });
2308+
var lineStart = params.line || 0;
2309+
var lineEnd = params.lineEnd || lineStart;
2310+
if (count) {
2311+
lineStart = lineEnd;
2312+
lineEnd = lineStart + count - 1;
2313+
}
2314+
var startPos = clipCursorToContent(cm, { line: lineStart, ch: 0 });
23012315
function doReplace() {
23022316
for (var cursor = cm.getSearchCursor(query, startPos);
2303-
cursor.findNext();) {
2304-
if (!isInRange(cursor.from(), params.line, params.lineEnd)) {
2305-
break;
2306-
}
2317+
cursor.findNext() &&
2318+
isInRange(cursor.from(), lineStart, lineEnd);) {
23072319
var text = cm.getRange(cursor.from(), cursor.to());
23082320
var newText = text.replace(query, replacePart);
23092321
cursor.replace(newText);

test/vim_test.js

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -897,6 +897,24 @@ testVim('ex_substitute_capture', function(cm, vim, helpers) {
897897
helpers.doEx('s/(\\d+)/$1$1/')
898898
eq('a1111 a1212 a1313', cm.getValue());
899899
}, { value: 'a11 a12 a13' });
900+
testVim('ex_substitute_empty_query', function(cm, vim, helpers) {
901+
// If the query is empty, use last query.
902+
cm.setCursor(1, 0);
903+
cm.openDialog = helpers.fakeOpenDialog('1');
904+
helpers.doKeys('/');
905+
helpers.doEx('s//b');
906+
eq('abb ab2 ab3', cm.getValue());
907+
}, { value: 'a11 a12 a13' });
908+
testVim('ex_substitute_count', function(cm, vim, helpers) {
909+
cm.setCursor(1, 0);
910+
helpers.doEx('s/\\d/0/i 2');
911+
eq('1\n0\n0\n4', cm.getValue());
912+
}, { value: '1\n2\n3\n4' });
913+
testVim('ex_substitute_count_with_range', function(cm, vim, helpers) {
914+
cm.setCursor(1, 0);
915+
helpers.doEx('1,3s/\\d/0/ 3');
916+
eq('1\n2\n0\n0', cm.getValue());
917+
}, { value: '1\n2\n3\n4' });
900918
// TODO: Reset key maps after each test.
901919
testVim('ex_map_key2key', function(cm, vim, helpers) {
902920
helpers.doEx('map a x');

0 commit comments

Comments
 (0)