diff --git a/src/vs/editor/contrib/find/common/replacePattern.ts b/src/vs/editor/contrib/find/common/replacePattern.ts index 7e15cdf97dacdb1555dd194f8be54cd28930d5d6..d721b7c03e0fab5073f303ab959b2fdba760fe2b 100644 --- a/src/vs/editor/contrib/find/common/replacePattern.ts +++ b/src/vs/editor/contrib/find/common/replacePattern.ts @@ -67,7 +67,9 @@ export class ReplacePattern { let remainder = ''; while (matchIndex > 0) { if (matchIndex < matches.length) { - return matches[matchIndex] + remainder; + // A match can be undefined + let match = (matches[matchIndex] || ''); + return match + remainder; } remainder = String(matchIndex % 10) + remainder; matchIndex = Math.floor(matchIndex / 10); diff --git a/src/vs/editor/contrib/find/test/common/findModel.test.ts b/src/vs/editor/contrib/find/test/common/findModel.test.ts index 73b2b1d6e15bd5d52540122ef760a3fa5db9df5b..5fbf02df835ea5b4a5a249c13df78131cf3febb9 100644 --- a/src/vs/editor/contrib/find/test/common/findModel.test.ts +++ b/src/vs/editor/contrib/find/test/common/findModel.test.ts @@ -2002,4 +2002,35 @@ suite('FindModel', () => { findModel.dispose(); findState.dispose(); }); + + findTest('issue #19740 Find and replace capture group/backreference inserts `undefined` instead of empty string', (editor, cursor) => { + let findState = new FindReplaceState(); + findState.change({ searchString: 'hello(z)?', replaceString: 'hi$1', isRegex: true, matchCase: true }, false); + let findModel = new FindModelBoundToEditorModel(editor, findState); + + assertFindState( + editor, + [1, 1, 1, 1], + null, + [ + [6, 14, 6, 19], + [7, 14, 7, 19], + [9, 14, 9, 19] + ] + ); + + findModel.replaceAll(); + assertFindState( + editor, + [1, 1, 1, 1], + null, + [] + ); + assert.equal(editor.getModel().getLineContent(6), ' cout << "hi world, Hello!" << endl;'); + assert.equal(editor.getModel().getLineContent(7), ' cout << "hi world again" << endl;'); + assert.equal(editor.getModel().getLineContent(9), ' cout << "hiworld again" << endl;'); + + findModel.dispose(); + findState.dispose(); + }); }); diff --git a/src/vs/editor/contrib/find/test/common/replacePattern.test.ts b/src/vs/editor/contrib/find/test/common/replacePattern.test.ts index 88fcaeeb3aa83d4d0f896dd5b801c4f2ff82b952..63105b824384846d515e8d9a81b69d21abf2ac25 100644 --- a/src/vs/editor/contrib/find/test/common/replacePattern.test.ts +++ b/src/vs/editor/contrib/find/test/common/replacePattern.test.ts @@ -147,4 +147,11 @@ suite('Replace Pattern test', () => { assertReplace('this is a bla text', /b(la)(?=\stext$)/, 'f$0', 'fbla'); assertReplace('this is a bla text', /b(la)(?=\stext$)/, '$0ah', 'blaah'); }); + + test('issue #19740 Find and replace capture group/backreference inserts `undefined` instead of empty string', () => { + let replacePattern = parseReplaceString('a{$1}'); + let matches = /a(z)?/.exec('abcd'); + let actual = replacePattern.buildReplaceString(matches); + assert.equal(actual, 'a{}'); + }); });