diff --git a/src/plugins/fakevim/fakevimhandler.cpp b/src/plugins/fakevim/fakevimhandler.cpp
index 6d06fde11bbabf38da0edffaff9e1bdae0bb743b..fd457b87e153b3dd22665d4f2a7f6ccef2f7bd8d 100644
--- a/src/plugins/fakevim/fakevimhandler.cpp
+++ b/src/plugins/fakevim/fakevimhandler.cpp
@@ -1030,6 +1030,9 @@ public:
     QList<QTextEdit::ExtraSelection> m_searchSelections;
     QTextCursor m_searchCursor;
     QString m_oldNeedle;
+    QString m_lastSubstituteFlags;
+    QRegExp m_lastSubstitutePattern;
+    QString m_lastSubstituteReplacement;
 
     bool handleExCommandHelper(const ExCommand &cmd); // Returns success.
     bool handleExPluginCommand(const ExCommand &cmd); // Handled by plugin?
@@ -2062,6 +2065,8 @@ EventResult FakeVimHandler::Private::handleCommandMode1(const Input &input)
         handleFfTt(m_semicolonKey);
         m_subsubmode = NoSubSubMode;
         finishMovement();
+    } else if (input.is('&')) {
+        handleExCommand(m_gflag ? "%s//~/&" : "s");
     } else if (input.is(':')) {
         enterExMode();
         g.commandHistory.restart();
@@ -3267,84 +3272,124 @@ void FakeVimHandler::Private::handleCommand(const QString &cmd)
 bool FakeVimHandler::Private::handleExSubstituteCommand(const ExCommand &cmd)
     // :substitute
 {
-    QString line = cmd.cmd + ' ' + cmd.args;
-    line = line.trimmed();
-    if (line.startsWith(_("substitute")))
-        line = line.mid(10);
-    else if (line.startsWith('s') && line.size() > 1
-            && !isalpha(line.at(1).unicode()))
-        line = line.mid(1);
-    else
-        return false;
-
-    // we have /{pattern}/{string}/[flags]  now
-    if (line.isEmpty())
-        return false;
-    const QChar separator = line.at(0);
-    int pos1 = -1;
-    int pos2 = -1;
-    int i;
-    for (i = 1; i < line.size(); ++i) {
-        if (line.at(i) == separator && line.at(i - 1) != '\\') {
-            pos1 = i;
-            break;
+    QString flags;
+    QRegExp pattern;
+    QString replacement;
+    int count = 0;
+
+    if (cmd.cmd.startsWith("&&")) {
+        flags = cmd.cmd.mid(2);
+        if (flags.isEmpty())
+            flags = m_lastSubstituteFlags;
+        pattern = m_lastSubstitutePattern;
+        replacement = m_lastSubstituteReplacement;
+        count = cmd.args.section(QLatin1Char(' '), 1, 1).toInt();
+    } else if (cmd.cmd.startsWith("&")) {
+        flags = cmd.cmd.mid(1);
+        if (flags.isEmpty())
+            flags = m_lastSubstituteFlags;
+        pattern = m_lastSubstitutePattern;
+        replacement = m_lastSubstituteReplacement;
+        count = cmd.args.section(QLatin1Char(' '), 1, 1).toInt();
+    } else if (cmd.matches("s", "substitute")) {
+        flags = m_lastSubstituteFlags;
+        if (flags.isEmpty())
+            flags = m_lastSubstituteFlags;
+        pattern = m_lastSubstitutePattern;
+        replacement = m_lastSubstituteReplacement;
+        count = cmd.args.section(QLatin1Char(' '), 2, 2).toInt();
+    } else {
+        QString line = cmd.cmd + ' ' + cmd.args;
+        line = line.trimmed();
+        if (line.startsWith(_("substitute")))
+            line = line.mid(10);
+        else if (line.startsWith('s') && line.size() > 1
+                && !isalpha(line.at(1).unicode()))
+            line = line.mid(1);
+        else
+            return false;
+        // we have /{pattern}/{string}/[flags]  now
+        if (line.isEmpty())
+            return false;
+        const QChar separator = line.at(0);
+        int pos1 = -1;
+        int pos2 = -1;
+        int i;
+        for (i = 1; i < line.size(); ++i) {
+            if (line.at(i) == separator && line.at(i - 1) != '\\') {
+                pos1 = i;
+                break;
+            }
         }
-    }
-    if (pos1 == -1)
-        return false;
-    for (++i; i < line.size(); ++i) {
-        if (line.at(i) == separator && line.at(i - 1) != '\\') {
-            pos2 = i;
-            break;
+        if (pos1 == -1)
+            return false;
+        for (++i; i < line.size(); ++i) {
+            if (line.at(i) == separator && line.at(i - 1) != '\\') {
+                pos2 = i;
+                break;
+            }
         }
+        if (pos2 == -1)
+            pos2 = line.size();
+
+        QString needle = line.mid(1, pos1 - 1);
+        replacement = line.mid(pos1 + 1, pos2 - pos1 - 1);
+        flags = line.mid(pos2 + 1);
+
+        needle.replace('$', '\n');
+        needle.replace("\\\n", "\\$");
+        pattern.setPattern(needle);
+
+        m_lastSubstituteFlags = flags;
+        m_lastSubstitutePattern = pattern;
+        m_lastSubstituteReplacement = replacement;
     }
-    if (pos2 == -1)
-        pos2 = line.size();
 
-    QString needle = line.mid(1, pos1 - 1);
-    const QString replacement = line.mid(pos1 + 1, pos2 - pos1 - 1);
-    QString flags = line.mid(pos2 + 1);
+    if (count == 0)
+        count = 1;
 
-    needle.replace('$', '\n');
-    needle.replace("\\\n", "\\$");
-    QRegExp pattern(needle);
     if (flags.contains('i'))
         pattern.setCaseSensitivity(Qt::CaseInsensitive);
-    const bool global = flags.contains('g');
-    const Range range = cmd.range.endPos == 0 ? rangeFromCurrentLine() : cmd.range;
-    const int beginLine = lineForPosition(range.beginPos);
-    const int endLine = lineForPosition(range.endPos);
+
     beginEditBlock();
-    for (int line = endLine; line >= beginLine; --line) {
-        QString origText = lineContents(line);
-        QString text = origText;
-        int pos = 0;
-        while (true) {
-            pos = pattern.indexIn(text, pos, QRegExp::CaretAtZero);
-            if (pos == -1)
-                break;
-            if (pattern.cap(0).isEmpty())
-                break;
-            QStringList caps = pattern.capturedTexts();
-            QString matched = text.mid(pos, caps.at(0).size());
-            QString repl = replacement;
-            for (int i = 1; i < caps.size(); ++i)
-                repl.replace("\\" + QString::number(i), caps.at(i));
-            for (int i = 0; i < repl.size(); ++i) {
-                if (repl.at(i) == '&' && (i == 0 || repl.at(i - 1) != '\\')) {
-                    repl.replace(i, 1, caps.at(0));
-                    i += caps.at(0).size();
+    const bool global = flags.contains('g');
+    for (int a = 0; a != count; ++a) {
+        const Range range = cmd.range.endPos == 0 ? rangeFromCurrentLine() : cmd.range;
+        const int beginLine = lineForPosition(range.beginPos);
+        const int endLine = lineForPosition(range.endPos);
+        for (int line = endLine; line >= beginLine; --line) {
+            QString origText = lineContents(line);
+            QString text = origText;
+            int pos = 0;
+            while (true) {
+                pos = pattern.indexIn(text, pos, QRegExp::CaretAtZero);
+                if (pos == -1)
+                    break;
+                if (pattern.cap(0).isEmpty())
+                    break;
+                QStringList caps = pattern.capturedTexts();
+                QString matched = text.mid(pos, caps.at(0).size());
+                QString repl = replacement;
+                for (int i = 1; i < caps.size(); ++i)
+                    repl.replace("\\" + QString::number(i), caps.at(i));
+                for (int i = 0; i < repl.size(); ++i) {
+                    if (repl.at(i) == '&' && (i == 0 || repl.at(i - 1) != '\\')) {
+                        repl.replace(i, 1, caps.at(0));
+                        i += caps.at(0).size();
+                    }
                 }
+                repl.replace("\\&", "&");
+                text = text.left(pos) + repl + text.mid(pos + matched.size());
+                pos += repl.size();
+                if (!global)
+                    break;
             }
-            repl.replace("\\&", "&");
-            text = text.left(pos) + repl + text.mid(pos + matched.size());
-            pos += repl.size();
-            if (!global)
-                break;
+            if (text != origText)
+                setLineContents(line, text);
         }
-        if (text != origText)
-            setLineContents(line, text);
     }
+    moveToStartOfLine();
+    setTargetColumn();
     endEditBlock();
     return true;
 }