diff --git a/keymap/vim.js b/keymap/vim.js
index 336f1a7cc0cca25b472de7ac9f0df5eb82b57d7d..d8a2d60d416c52cd505f90a1fd16e25bc21695a8 100644
--- a/keymap/vim.js
+++ b/keymap/vim.js
@@ -4509,6 +4509,10 @@
         if (tokens.length) {
           regexPart = tokens[0];
           replacePart = tokens[1];
+          if (regexPart && regexPart[regexPart.length - 1] === '$') {
+            regexPart = regexPart.slice(0, regexPart.length - 1) + '\\n';
+            replacePart = replacePart ? replacePart + '\n' : '\n';
+          }
           if (replacePart !== undefined) {
             if (getOption('pcre')) {
               replacePart = unescapeRegexReplace(replacePart);
diff --git a/test/vim_test.js b/test/vim_test.js
index 86a544756ac19bcff1354bdb6b3c19f3ce803bc1..da49a24cf6529b08970447b06bdb16279c6f8fc9 100644
--- a/test/vim_test.js
+++ b/test/vim_test.js
@@ -3789,6 +3789,14 @@ testSubstitute('ex_substitute_multibackslash_replacement', {
   value: 'one,two \n three,four',
   expectedValue: 'one\\\\\\\\two \n three\\\\\\\\four', // 2*8 backslashes.
   expr: '%s/,/\\\\\\\\\\\\\\\\/g'}); // 16 backslashes.
+testSubstitute('ex_substitute_dollar_match', {
+  value: 'one,two \n three,four',
+  expectedValue: 'one,two ,\n three,four',
+  expr: '%s/$/,/g'});
+testSubstitute('ex_substitute_newline_match', {
+  value: 'one,two \n three,four',
+  expectedValue: 'one,two , three,four',
+  expr: '%s/\\n/,/g'});
 testSubstitute('ex_substitute_newline_replacement', {
   value: 'one,two \n three,four',
   expectedValue: 'one\ntwo \n three\nfour',