diff --git a/keymap/vim.js b/keymap/vim.js index 0e64338659..95b19b2452 100644 --- a/keymap/vim.js +++ b/keymap/vim.js @@ -4073,7 +4073,7 @@ } // Unescape \ and / in the replace part, for PCRE mode. - var unescapes = {'\\/': '/', '\\\\': '\\', '\\n': '\n', '\\r': '\r', '\\t': '\t'}; + var unescapes = {'\\/': '/', '\\\\': '\\', '\\n': '\n', '\\r': '\r', '\\t': '\t', '\\&':'&'}; function unescapeRegexReplace(str) { var stream = new CodeMirror.StringStream(str); var output = []; @@ -4871,7 +4871,7 @@ } if (replacePart !== undefined) { if (getOption('pcre')) { - replacePart = unescapeRegexReplace(replacePart); + replacePart = unescapeRegexReplace(replacePart.replace(/([^\\])&/g,"$1$$&")); } else { replacePart = translateRegexReplace(replacePart); } diff --git a/test/vim_test.js b/test/vim_test.js index 6e3ded4984..72a9896b59 100644 --- a/test/vim_test.js +++ b/test/vim_test.js @@ -3939,6 +3939,24 @@ testSubstitute('ex_substitute_forward_slash_regex', { expectedValue: 'forward slash was here', expr: '%s#\\/##g', noPcreExpr: '%s#/##g'}); +testVim("ex_substitute_ampersand_pcre", function(cm, vim, helpers) { + cm.setCursor(0, 0); + CodeMirror.Vim.setOption('pcre', true); + helpers.doEx('%s/foo/namespace.&/'); + eq("namespace.foo", cm.getValue()); + }, { value: 'foo' }); +testVim("ex_substitute_ampersand_multiple_pcre", function(cm, vim, helpers) { + cm.setCursor(0, 0); + CodeMirror.Vim.setOption('pcre', true); + helpers.doEx('%s/f.o/namespace.&/'); + eq("namespace.foo\nnamespace.fzo", cm.getValue()); + }, { value: 'foo\nfzo' }); +testVim("ex_escaped_ampersand_should_not_substitute_pcre", function(cm, vim, helpers) { + cm.setCursor(0, 0); + CodeMirror.Vim.setOption('pcre', true); + helpers.doEx('%s/foo/namespace.\\&/'); + eq("namespace.&", cm.getValue()); + }, { value: 'foo' }); testSubstitute('ex_substitute_backslashslash_regex', { value: 'one\\two \n three\\four', expectedValue: 'one,two \n three,four',