Skip to content

Commit

Permalink
fix and add test
Browse files Browse the repository at this point in the history
  • Loading branch information
sekedus committed Nov 23, 2024
1 parent 318dd9a commit 3a15da5
Show file tree
Hide file tree
Showing 2 changed files with 131 additions and 22 deletions.
26 changes: 19 additions & 7 deletions src/search.js
Original file line number Diff line number Diff line change
Expand Up @@ -116,8 +116,9 @@ class Search {
row = row + len - 2;
}
} else {
for (var matches, i = 0, lng = lines.length; i < lng; i++) {
for (var matches, i = 0; i < lines.length; i++) {
if (this.$isMultilineSearch(options)) {
var lng = lines.length - 1;
matches = this.$multiLineForward(session, re, i, lng);
if (matches) {
var end_row = matches.endRow <= lng ? matches.endRow - 1 : lng;
Expand Down Expand Up @@ -162,6 +163,8 @@ class Search {
DollarSign: 36,
Ampersand: 38,
Digit0: 48,
Digit1: 49,
Digit9: 57,
Backslash: 92,
n: 110,
t: 116
Expand All @@ -175,21 +178,22 @@ class Search {
i++;
if (i >= len) {
// string ends with a \
replacement += "\\";
break;
}
var nextChCode = replaceString.charCodeAt(i);
switch (nextChCode) {
case CharCode.Backslash:
// \\ => inserts a "\"
replacement = '\\';
replacement += "\\";
break;
case CharCode.n:
// \n => inserts a LF
replacement= '\n';
replacement += "\n";
break;
case CharCode.t:
// \t => inserts a TAB
replacement = '\t';
replacement += "\t";
break;
}
continue;
Expand All @@ -200,21 +204,29 @@ class Search {
i++;
if (i >= len) {
// string ends with a $
replacement += "$";
break;
}
const nextChCode = replaceString.charCodeAt(i);
if (nextChCode === CharCode.DollarSign) {
// $$ => inserts a "$"
replacement = '$';
replacement += "$$";
continue;
}
if (nextChCode === CharCode.Digit0) {
if (nextChCode === CharCode.Digit0 || nextChCode === CharCode.Ampersand) {
// replace $0 to $&, making it compatible with JavaScript
// $0 and $& => inserts the matched substring.
replaceString = replaceString.replace(/\$0/, '$$&');
replacement += "$&";
continue;
}
if (CharCode.Digit1 <= nextChCode && nextChCode <= CharCode.Digit9) {
// $n
replacement += "$" + replaceString[i];
continue;
}
}

replacement += replaceString[i];
}
return replacement || replaceString;
}
Expand Down
127 changes: 112 additions & 15 deletions src/search_test.js
Original file line number Diff line number Diff line change
Expand Up @@ -153,7 +153,7 @@ module.exports = {
var range = search.find(session);
assert.position(range.start, 0, 12);
assert.position(range.end, 0, 13);

search.set({ needle: "ab\\{2}" });
range = search.find(session);
assert.position(range.start, 1, 8);
Expand Down Expand Up @@ -369,8 +369,8 @@ module.exports = {
assert.position(ranges[1].start, 2, 1);
assert.position(ranges[1].end, 2, 3);
},


"test: find all multiline matches" : function() {
var session = new EditSession(["juhu", "juhu", "juhu", "juhu"]);

Expand Down Expand Up @@ -420,13 +420,14 @@ module.exports = {

"test: replace with RegExp match and capture groups" : function() {
var search = new Search().set({
needle: "ab(\\d\\d)",
needle: "ab((\\d)\\d)",
regExp: true
});

assert.equal(search.replace("ab12", "cd$1"), "cd12");
assert.equal(search.replace("ab56", "pr$17$2"), "pr5675");
assert.equal(search.replace("ab12", "-$&-"), "-ab12-");
assert.equal(search.replace("ab12", "$$"), "$");
assert.equal(search.replace("ab12", "_$0_"), "_ab12_");
},

"test: replace() should correctly handle $$ in the replacement string": function () {
Expand All @@ -435,11 +436,11 @@ module.exports = {
});

// Expecting $$ to be preserved in the output
assert.equal(search.replace("example", "$test"), "$test");
assert.equal(search.replace("example", "$$test"), "$$test");

// Expecting $$$$ to be preserved as $$$$
assert.equal(search.replace("example", "$$$test"), "$$$test");
assert.equal(search.replace("example", "$$$$test"), "$$$$test");

search.set({
regExp: true,
needle: "(example)"
Expand All @@ -448,11 +449,40 @@ module.exports = {
// Tests that $1 is replaced by the text that matches the capturing group.
assert.equal(search.replace("example", "$1test"), "exampletest");

search.set({regExp: false});
assert.equal(search.replace("example", "$"), "$");
assert.equal(search.replace("example", "$$"), "$");
assert.equal(search.replace("example", "$$$"), "$$");
assert.equal(search.replace("example", "$$$$"), "$$");
assert.equal(search.replace("example", "$$$$$"), "$$$");
assert.equal(search.replace("example", "$$$$$$"), "$$$");
assert.equal(search.replace("example", "$$$$$$$"), "$$$$");

search.set({ regExp: false });
// Tests that without regular expression, "$1test" is treated as a literal string with $ escape.
assert.equal(search.replace("(example)", "$1test"), "$1test");
},

"test: replace() should correctly handle \\\\ in the replacement string": function () {
var search = new Search().set({
needle: "example"
});

// Expecting \\ to be preserved in the output
assert.equal(search.replace("example", "\\test"), "\\test");
assert.equal(search.replace("example", "\\\\test"), "\\\\test");
assert.equal(search.replace("example", "\\\\\\test"), "\\\\\\test");

search.set({ regExp: true });

assert.equal(search.replace("example", "\\"), "\\");
assert.equal(search.replace("example", "\\\\"), "\\");
assert.equal(search.replace("example", "\\\\\\"), "\\\\");
assert.equal(search.replace("example", "\\\\\\\\"), "\\\\");
assert.equal(search.replace("example", "\\\\\\\\\\"), "\\\\\\");
assert.equal(search.replace("example", "\\\\\\\\\\\\"), "\\\\\\");
assert.equal(search.replace("example", "\\\\\\\\\\\\\\"), "\\\\\\\\");
},

"test: find all using regular expresion containing $" : function() {
var session = new EditSession(["a", " b", "c ", "d"]);

Expand Down Expand Up @@ -518,15 +548,15 @@ module.exports = {
"test: find next empty range" : function() {
var session = new EditSession("foo foobar foo");
var editor = new Editor(new MockRenderer(), session);

var options = {
needle: "o*",
wrap: true,
regExp: true,
backwards: false
};
var positions = [4, 5.2, 7, 8, 9, 10, 11, 12.2, 14, 0, 1.2, 3];

session.selection.moveCursorTo(0, 3);
for (var i = 0; i < positions.length; i++) {
editor.find(options);
Expand All @@ -545,10 +575,11 @@ module.exports = {
assert.equal(start + 0.1 * len, positions[i]);
}
},

"test: repeating text": function() {
var session = new EditSession("tttttt\ntttttt\ntttttt\ntttttt\ntttttt\ntttttt");
var editor = new Editor(new MockRenderer(), session);

var options = {
needle: "^",
wrap: true,
Expand All @@ -560,15 +591,15 @@ module.exports = {
var range = editor.selection.getRange();
assert.range(range, sl, sc, el, ec);
}

session.selection.moveCursorTo(1, 3);
check(2, 0, 2, 0);

options.needle = "tttt\ntttt";
check(2, 2, 3, 4);
check(4, 2, 5, 4);
check(0, 2, 1, 4);

options.backwards = true;
check(4, 2, 5, 4);
check(2, 2, 3, 4);
Expand Down Expand Up @@ -601,6 +632,72 @@ module.exports = {
assert.position(ranges[1].end, 1, 39);
assert.position(ranges[2].start, 2, 4);
assert.position(ranges[2].end, 2, 7);
},

"test: find all line breaks (\\r\\n, \\n) using regular expression" : function() {
var session = new EditSession('\nfunction foo(items, nada) {\n for (var i=0; i<items.length; i++) {\n alert(items[i] + "juhu\\n");\n }\t/* Real Tab */\n\n\n\n\n}\n\n\n// test search/replace line break with regexp\r\n\r\n\t\t\t\t\n');

var search = new Search().set({
needle: "\\n",
regExp: true,
wrap: true
});

var ranges = search.findAll(session);
assert.equal(ranges.length, 15);

search.set({ needle: "\\n{2,}" });
ranges = search.findAll(session);
assert.equal(ranges.length, 3);

search.set({ needle: "\\n\\s+" });
ranges = search.findAll(session);
assert.equal(ranges.length, 6);

search.set({ needle: "\\)\\s\\{\\n\\s+" });
ranges = search.findAll(session);
assert.equal(ranges.length, 2);

search.set({ needle: "\\n+" });
ranges = search.findAll(session);

assert.equal(ranges.length, 8);
assert.position(ranges[0].start, 0, 0);
assert.position(ranges[0].end, 1, 0);
assert.position(ranges[1].start, 1, 27);
assert.position(ranges[1].end, 2, 0);
assert.position(ranges[2].start, 2, 40);
assert.position(ranges[2].end, 3, 0);
assert.position(ranges[3].start, 3, 35);
assert.position(ranges[3].end, 4, 0);
assert.position(ranges[4].start, 4, 20);
assert.position(ranges[4].end, 9, 0);
assert.position(ranges[5].start, 9, 1);
assert.position(ranges[5].end, 12, 0);
assert.position(ranges[6].start, 12, 45);
assert.position(ranges[6].end, 14, 0);
assert.position(ranges[7].start, 14, 4);
assert.position(ranges[7].end, 15, 0);
},

"test: replace with line breaks (\\n) and TAB (\\t) using regular expression" : function() {
var session = new EditSession('\nfunction foo(items, nada) {\n for (var i=0; i<items.length; i++) {\n alert(items[i] + "juhu\\n");\n }\t/* Real Tab */\n\n\n\n\n}\n\n\n// test search/replace line break with regexp\r\n\r\n\t\t\t\t\n');

var search = new Search().set({
needle: "with",
regExp: true,
wrap: true
});

assert.equal(search.replace("with", "\n// $0"), "\n// with");
assert.equal(search.replace("with", "\t-\t$0"), "\t-\twith");

search.set({ needle: "(\\n+)" });
assert.equal(search.replace("\n", ""), "");
assert.equal(search.replace("\n", "\t"), "\t");
assert.equal(search.replace("\n\n\n", "\n"), "\n");
assert.equal(search.replace("\n\t\n\n", "\t$1"), "\t\n\t\t\n\n");
assert.equal(search.replace("\r\n /* CRLF */", "\n"), "\n /* CRLF */");
}
};

Expand Down

0 comments on commit 3a15da5

Please sign in to comment.