diff --git a/src/plugins/fakevim/fakevimhandler.cpp b/src/plugins/fakevim/fakevimhandler.cpp
index 83f9c4d169a4658ce7882c5637cf7ebcef433ef9..fcd369080f5a16b224b3633b3d31b72ac39ad4f6 100644
--- a/src/plugins/fakevim/fakevimhandler.cpp
+++ b/src/plugins/fakevim/fakevimhandler.cpp
@@ -128,6 +128,7 @@ namespace Internal {
 #define EDITOR(s) (m_textedit ? m_textedit->s : m_plaintextedit->s)
 
 const int ParagraphSeparator = 0x00002029;
+typedef QLatin1String _;
 
 using namespace Qt;
 
@@ -232,6 +233,20 @@ enum EventResult
     EventPassedToCore
 };
 
+struct ExCommand
+{
+    ExCommand(const QString &c, int b = -1, int e = -1)
+        : line(c), beginLine(b), endLine(e) {}
+    QString line;
+    int beginLine;
+    int endLine;
+};
+
+QDebug operator<<(QDebug ts, const ExCommand &cmd)
+{
+    return ts << cmd.line << cmd.beginLine << cmd.endLine;
+}
+
 struct Column
 {
     Column(int p, int l) : physical(p), logical(l) {}
@@ -251,6 +266,7 @@ struct CursorPosition
 struct Register
 {
     Register() : rangemode(RangeCharMode) {}
+    Register(const QString &c) : contents(c), rangemode(RangeCharMode) {}
     Register(const QString &c, RangeMode m) : contents(c), rangemode(m) {}
     QString contents;
     RangeMode rangemode;
@@ -293,7 +309,7 @@ QString quoteUnprintable(const QString &ba)
         if (c.isPrint())
             res += c;
         else if (cc == '\n')
-            res += QLatin1String("<CR>");
+            res += _("<CR>");
         else
             res += QString("\\x%1").arg(c.unicode(), 2, 16, QLatin1Char('0'));
     }
@@ -313,7 +329,7 @@ static bool startsWithWhitespace(const QString &str, int col)
 
 inline QString msgMarkNotSet(const QString &text)
 {
-    return FakeVimHandler::tr("E20: Mark '%1' not set").arg(text);
+    return FakeVimHandler::tr("Mark '%1' not set").arg(text);
 }
 
 class Input
@@ -378,6 +394,11 @@ public:
 
     QString text() const { return m_text; }
 
+    QChar asChar() const
+    {
+        return (m_text.size() == 1 ? m_text.at(0) : QChar());
+    }
+
     int key() const { return m_key; }
 
     QDebug dump(QDebug ts) const
@@ -551,7 +572,7 @@ public:
     int lastPositionInLine(int line) const; // 1 based line, 0 based pos
     int lineForPosition(int pos) const;  // 1 based line, 0 based pos
     QString lineContents(int line) const; // 1 based line
-    void setLineContents(int line, const QString &contents) const; // 1 based line
+    void setLineContents(int line, const QString &contents); // 1 based line
 
     int linesOnScreen() const;
     int columnsOnScreen() const;
@@ -706,6 +727,7 @@ public:
     void transformText(const Range &range, Transformation transformation,
         const QVariant &extraData = QVariant());
 
+    void insertText(const Register &reg);
     void removeSelectedText();
     void removeText(const Range &range);
     void removeTransform(TransformationData *td);
@@ -756,8 +778,9 @@ public:
     VisualMode m_visualMode;
 
     // marks as lines
+    int mark(int code) const;
+    void setMark(int code, int position);
     QHash<int, int> m_marks;
-    QString m_oldNeedle;
 
     // vi style configuration
     QVariant config(int code) const { return theFakeVimSetting(code)->value(); }
@@ -783,22 +806,23 @@ public:
     QVector<CursorPosition> m_jumpListRedo;
 
     QList<QTextEdit::ExtraSelection> m_searchSelections;
+    QString m_oldNeedle;
 
-    bool handleExCommandHelper(const QString &cmd); // Returns success.
-    QString extractCommand(const QString &line, int *beginLine, int *endLine);
-    bool handleExBangCommand(const QString &line);
-    bool handleExDeleteCommand(const QString &line);
-    bool handleExGotoCommand(const QString &line);
-    bool handleExHistoryCommand(const QString &line);
-    bool handleExMapCommand(const QString &line);
-    bool handleExNormalCommand(const QString &line);
-    bool handleExReadCommand(const QString &line);
-    bool handleExRedoCommand(const QString &line);
-    bool handleExSetCommand(const QString &line);
-    bool handleExShiftRightCommand(const QString &line);
-    bool handleExSourceCommand(const QString &line);
-    bool handleExSubstituteCommand(const QString &line);
-    bool handleExWriteCommand(const QString &line);
+    bool handleExCommandHelper(const ExCommand &cmd); // Returns success.
+    ExCommand extractExCommand(const QString &line);
+    bool handleExBangCommand(const ExCommand &cmd);
+    bool handleExDeleteCommand(const ExCommand &cmd);
+    bool handleExGotoCommand(const ExCommand &cmd);
+    bool handleExHistoryCommand(const ExCommand &cmd);
+    bool handleExMapCommand(const ExCommand &cmd);
+    bool handleExNormalCommand(const ExCommand &cmd);
+    bool handleExReadCommand(const ExCommand &cmd);
+    bool handleExRedoCommand(const ExCommand &cmd);
+    bool handleExSetCommand(const ExCommand &cmd);
+    bool handleExShiftRightCommand(const ExCommand &cmd);
+    bool handleExSourceCommand(const ExCommand &cmd);
+    bool handleExSubstituteCommand(const ExCommand &cmd);
+    bool handleExWriteCommand(const ExCommand &cmd);
 
     void timerEvent(QTimerEvent *ev);
 
@@ -1028,8 +1052,8 @@ void FakeVimHandler::Private::importSelection()
         else
             tc.movePosition(Left, KeepAnchor);
     }
-    m_marks['<'] = anc;
-    m_marks['>'] = pos;
+    setMark('<', anc);
+    setMark('>', pos);
     m_anchor = anc;
     Qt::KeyboardModifiers mods = QApplication::keyboardModifiers();
     if (!tc.hasSelection())
@@ -1067,15 +1091,15 @@ void FakeVimHandler::Private::restoreWidget(int tabSize)
 
     if (isVisualLineMode()) {
         m_tc = EDITOR(textCursor());
-        int beginLine = lineForPosition(m_marks['<']);
-        int endLine = lineForPosition(m_marks['>']);
+        int beginLine = lineForPosition(mark('<'));
+        int endLine = lineForPosition(mark('>'));
         m_tc.setPosition(firstPositionInLine(beginLine), MoveAnchor);
         m_tc.setPosition(lastPositionInLine(endLine), KeepAnchor);
         EDITOR(setTextCursor(m_tc));
     } else if (isVisualCharMode() || isVisualBlockMode()) {
         m_tc = EDITOR(textCursor());
-        m_tc.setPosition(m_marks['<'], MoveAnchor);
-        m_tc.setPosition(m_marks['>'], KeepAnchor);
+        m_tc.setPosition(mark('<'), MoveAnchor);
+        m_tc.setPosition(mark('>'), KeepAnchor);
         EDITOR(setTextCursor(m_tc));
     }
 
@@ -1172,7 +1196,7 @@ void FakeVimHandler::Private::setAnchor()
     if (!isVisualMode()) {
         m_anchor = m_tc.position();
     } else {
-    //    m_marks['<'] = m_tc.position();
+    //    setMark('<', m_tc.position());
     }
 }
 
@@ -1246,7 +1270,7 @@ void FakeVimHandler::Private::finishMovement(const QString &dotCommand)
     }
 
     if (isVisualMode())
-        m_marks['>'] = m_tc.position();
+        setMark('>', m_tc.position());
 
     if (m_submode == ChangeSubMode
         || m_submode == DeleteSubMode
@@ -1314,7 +1338,7 @@ void FakeVimHandler::Private::finishMovement(const QString &dotCommand)
         const int la = lineForPosition(anchor());
         const int lp = lineForPosition(position());
         if (m_register != '"') {
-            setPosition(m_marks[m_register]);
+            setPosition(mark(m_register));
             moveToStartOfLine();
         } else {
             if (anchor() <= position())
@@ -1394,7 +1418,7 @@ void FakeVimHandler::Private::updateSelection()
         sel.format.setBackground(Qt::black);
 #endif
         const int cursorPos = m_tc.position();
-        const int anchorPos = m_marks['<'];
+        const int anchorPos = mark('<');
         //qDebug() << "POS: " << cursorPos << " ANCHOR: " << anchorPos;
         if (isVisualCharMode()) {
             sel.cursor.setPosition(qMin(cursorPos, anchorPos), MoveAnchor);
@@ -1602,12 +1626,13 @@ EventResult FakeVimHandler::Private::handleCommandSubSubMode(const Input &input)
             finishMovement();
         }
     } else if (m_subsubmode == MarkSubSubMode) {
-        m_marks[input.key()] = m_tc.position();
+        setMark(input.asChar().unicode(), m_tc.position());
         m_subsubmode = NoSubSubMode;
     } else if (m_subsubmode == BackTickSubSubMode
             || m_subsubmode == TickSubSubMode) {
-        if (m_marks.contains(input.key())) {
-            setPosition(m_marks[input.key()]);
+        int m = mark(input.asChar().unicode());
+        if (m != -1) {
+            setPosition(m);
             if (m_subsubmode == TickSubSubMode)
                 moveToFirstNonBlankOnLine();
             finishMovement();
@@ -1756,7 +1781,7 @@ EventResult FakeVimHandler::Private::handleCommandMode(const Input &input)
     } else if (input.is(':')) {
         enterExMode();
         m_currentMessage.clear();
-        m_commandPrefix = input.text().at(0);
+        m_commandPrefix = input.asChar();
         m_commandBuffer.clear();
         if (isVisualMode())
             m_commandBuffer = "'<,'>";
@@ -2414,7 +2439,7 @@ EventResult FakeVimHandler::Private::handleReplaceMode(const Input &input)
         }
         const QString text = input.text();
         m_lastInsertion += text;
-        m_tc.insertText(text);
+        insertText(text);
         //qDebug() << "REM/INS: " << m_lastDeletion << m_lastInsertion;
         endEditBlock();
         //   m_movetype = MoveExclusive;
@@ -2439,7 +2464,7 @@ EventResult FakeVimHandler::Private::handleInsertMode(const Input &input)
             setTargetColumn();
             for (int i = 0; i < m_visualInsertCount; ++i) {
                 moveDown();
-                m_tc.insertText(m_lastInsertion);
+                insertText(m_lastInsertion);
             }
             moveLeft(1);
             Range range(pos, position(), RangeBlockMode);
@@ -2448,13 +2473,12 @@ EventResult FakeVimHandler::Private::handleInsertMode(const Input &input)
             setDotCommand("p");
             endEditBlock();
         } else {
-            // normal insertion. start with '1', as one instance was
-            // already physically inserted while typing
-            QString data = m_lastInsertion;
-            for (int i = 1; i < count(); ++i) {
-                m_tc.insertText(m_lastInsertion);
+            // Normal insertion. Start with '1', as one instance was
+            // already physically inserted while typing.
+            QString data;
+            for (int i = 1; i < count(); ++i)
                 data += m_lastInsertion;
-            }
+            insertText(data);
             moveLeft(qMin(1, leftDist()));
             setTargetColumn();
             leaveVisualMode();
@@ -2544,7 +2568,7 @@ EventResult FakeVimHandler::Private::handleInsertMode(const Input &input)
         const int col = physicalCursorColumnInDocument();
         QString str = QString(ts - col % ts, ' ');
         m_lastInsertion.append(str);
-        m_tc.insertText(str);
+        insertText(str);
         setTargetColumn();
     } else if (input.isControl('d')) {
         // remove one level of indentation from the current line
@@ -2571,7 +2595,7 @@ EventResult FakeVimHandler::Private::handleInsertMode(const Input &input)
         m_justAutoIndented = 0;
         const QString text = input.text();
         m_lastInsertion.append(text);
-        m_tc.insertText(text);
+        insertText(text);
         if (hasConfig(ConfigSmartIndent) && isElectricCharacter(text.at(0))) {
             const QString leftText = m_tc.block().text()
                    .left(m_tc.position() - 1 - m_tc.block().position());
@@ -2706,7 +2730,7 @@ EventResult FakeVimHandler::Private::handleSearchSubSubMode(const Input &input)
     return EventHandled;
 }
 
-// 1 based.
+// This uses 1 based line counting.
 int FakeVimHandler::Private::readLineCode(QString &cmd)
 {
     //qDebug() << "CMD: " << cmd;
@@ -2714,19 +2738,32 @@ int FakeVimHandler::Private::readLineCode(QString &cmd)
         return -1;
     QChar c = cmd.at(0);
     cmd = cmd.mid(1);
-    if (c == '.')
+    if (c == '.') {
+        if (cmd.isEmpty())
+            return cursorLineInDocument() + 1;
+        QChar c1 = cmd.at(0);
+        if (c1 == '+' || c1 == '-') {
+            // Repeat for things like  .+4
+            cmd = cmd.mid(1);
+            return cursorLineInDocument() + readLineCode(cmd);
+        }
         return cursorLineInDocument() + 1;
+    }
     if (c == '$')
         return linesInDocument();
     if (c == '\'' && !cmd.isEmpty()) {
-        int mark = m_marks.value(cmd.at(0).unicode());
-        if (!mark) {
+        if (cmd.isEmpty()) {
+            showRedMessage(msgMarkNotSet(QString()));
+            return -1;
+        }
+        int m = mark(cmd.at(0).unicode());
+        if (m == -1) {
             showRedMessage(msgMarkNotSet(cmd.at(0)));
             cmd = cmd.mid(1);
             return -1;
         }
         cmd = cmd.mid(1);
-        return lineForPosition(mark);
+        return lineForPosition(m);
     }
     if (c == '-') {
         int n = readLineCode(cmd);
@@ -2737,8 +2774,7 @@ int FakeVimHandler::Private::readLineCode(QString &cmd)
         return cursorLineInDocument() + 1 + (n == -1 ? 1 : n);
     }
     if (c == '\'' && !cmd.isEmpty()) {
-        int pos = m_marks.value(cmd.at(0).unicode(), -1);
-        //qDebug() << " MARK: " << cmd.at(0) << pos << lineForPosition(pos);
+        int pos = mark(cmd.at(0).unicode());
         if (pos == -1) {
             showRedMessage(msgMarkNotSet(cmd.at(0)));
             cmd = cmd.mid(1);
@@ -2756,16 +2792,17 @@ int FakeVimHandler::Private::readLineCode(QString &cmd)
             cmd = cmd.mid(1);
             n = n * 10 + (c.unicode() - '0');
         }
-        //qDebug() << "N: " << n;
+        qDebug() << "N: " << n;
         return n;
     }
-    // not parsed
+    // Parsing failed.
     cmd = c + cmd;
     return -1;
 }
 
 void FakeVimHandler::Private::selectRange(int beginLine, int endLine)
 {
+    m_rangemode = RangeLineMode;
     if (beginLine == -1)
         beginLine = cursorLineInDocument();
     if (endLine == -1)
@@ -2787,71 +2824,44 @@ void FakeVimHandler::Private::handleCommand(const QString &cmd)
     EDITOR(setTextCursor(m_tc));
 }
 
-QString FakeVimHandler::Private::extractCommand(const QString &line,
-    int *beginLine, int *endLine)
-{
-    QString cmd = line;
-    *beginLine = -1;
-    *endLine = -1;
-
-    // FIXME: that seems to be different for %w and %s
-    if (cmd.startsWith(QLatin1Char('%')))
-        cmd = "1,$" + cmd.mid(1);
-
-    int lineNumber = readLineCode(cmd);
-    if (lineNumber != -1)
-        *beginLine = lineNumber;
-
-    if (cmd.startsWith(',')) {
-        cmd = cmd.mid(1);
-        lineNumber = readLineCode(cmd);
-        if (lineNumber != -1)
-            *endLine = lineNumber;
-    }
-    //qDebug() << "RANGE: " << beginLine << endLine << cmd << lineNumber << m_marks;
-    return cmd;
-}
-
-bool FakeVimHandler::Private::handleExSubstituteCommand(const QString &line)
+bool FakeVimHandler::Private::handleExSubstituteCommand(const ExCommand &cmd)
     // :substitute
 {
-    int beginLine, endLine;
-    QString cmd = extractCommand(line, &beginLine, &endLine);
-
-    if (cmd.startsWith(QLatin1String("substitute")))
-        cmd = cmd.mid(10);
-    else if (cmd.startsWith('s') && line.size() > 1
-            && !isalpha(cmd.at(1).unicode()))
-        cmd = cmd.mid(1);
+    QString line = cmd.line;
+    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 (cmd.isEmpty())
+    if (line.isEmpty())
         return false;
-    const QChar separator = cmd.at(0);
+    const QChar separator = line.at(0);
     int pos1 = -1;
     int pos2 = -1;
     int i;
-    for (i = 1; i < cmd.size(); ++i) {
-        if (cmd.at(i) == separator && cmd.at(i - 1) != '\\') {
+    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 < cmd.size(); ++i) {
-        if (cmd.at(i) == separator && cmd.at(i - 1) != '\\') {
+    for (++i; i < line.size(); ++i) {
+        if (line.at(i) == separator && line.at(i - 1) != '\\') {
             pos2 = i;
             break;
         }
     }
     if (pos2 == -1)
-        pos2 = cmd.size();
+        pos2 = line.size();
 
-    QString needle = cmd.mid(1, pos1 - 1);
-    const QString replacement = cmd.mid(pos1 + 1, pos2 - pos1 - 1);
-    QString flags = cmd.mid(pos2 + 1);
+    QString needle = line.mid(1, pos1 - 1);
+    const QString replacement = line.mid(pos1 + 1, pos2 - pos1 - 1);
+    QString flags = line.mid(pos2 + 1);
 
     needle.replace('$', '\n');
     needle.replace("\\\n", "\\$");
@@ -2860,7 +2870,7 @@ bool FakeVimHandler::Private::handleExSubstituteCommand(const QString &line)
         pattern.setCaseSensitivity(Qt::CaseInsensitive);
     const bool global = flags.contains('g');
     beginEditBlock();
-    for (int line = endLine; line >= beginLine; --line) {
+    for (int line = cmd.endLine; line >= cmd.beginLine; --line) {
         QString origText = lineContents(line);
         QString text = origText;
         int pos = 0;
@@ -2893,14 +2903,14 @@ bool FakeVimHandler::Private::handleExSubstituteCommand(const QString &line)
     return true;
 }
 
-bool FakeVimHandler::Private::handleExMapCommand(const QString &line) // :map
+bool FakeVimHandler::Private::handleExMapCommand(const ExCommand &cmd0) // :map
 {
-    const int pos1 = line.indexOf(QLatin1Char(' '));
+    const int pos1 = cmd0.line.indexOf(QLatin1Char(' '));
 
     QByteArray modes;
     enum Type { Map, Noremap, Unmap } type;
 
-    QByteArray cmd = line.left(pos1).toLatin1();
+    QByteArray cmd = cmd0.line.left(pos1).toLatin1();
 
     // Strange formatting. But everything else is even uglier.
     if (cmd == "map") { modes = "nvo"; type = Map; } else
@@ -2938,15 +2948,15 @@ bool FakeVimHandler::Private::handleExMapCommand(const QString &line) // :map
     else
         return false;
 
-    const int pos2 = line.indexOf(QLatin1Char(' '), pos1 + 1);
+    const int pos2 = cmd0.line.indexOf(QLatin1Char(' '), pos1 + 1);
     if (pos1 == -1 || pos2 == -1) {
         // FIXME: Dump mappings here.
         //qDebug() << g.mappings;
         return true;;
     }
 
-    QString lhs = line.mid(pos1 + 1, pos2 - pos1 - 1);
-    QString rhs = line.mid(pos2 + 1);
+    QString lhs = cmd0.line.mid(pos1 + 1, pos2 - pos1 - 1);
+    QString rhs = cmd0.line.mid(pos2 + 1);
     Inputs key;
     key.parseFrom(lhs);
     //qDebug() << "MAPPING: " << modes << lhs << rhs;
@@ -2969,10 +2979,10 @@ bool FakeVimHandler::Private::handleExMapCommand(const QString &line) // :map
     return true;
 }
 
-bool FakeVimHandler::Private::handleExHistoryCommand(const QString &cmd) // :history
+bool FakeVimHandler::Private::handleExHistoryCommand(const ExCommand &cmd) // :history
 {
     static QRegExp reHistory("^his(tory)?( (.*))?$");
-    if (reHistory.indexIn(cmd) == -1)
+    if (reHistory.indexIn(cmd.line) == -1)
         return false;
 
     QString arg = reHistory.cap(3);
@@ -2992,10 +3002,10 @@ bool FakeVimHandler::Private::handleExHistoryCommand(const QString &cmd) // :his
     return true;
 }
 
-bool FakeVimHandler::Private::handleExSetCommand(const QString &cmd) // :set
+bool FakeVimHandler::Private::handleExSetCommand(const ExCommand &cmd) // :set
 {
     static QRegExp reSet("^set?( (.*))?$");
-    if (reSet.indexIn(cmd) == -1)
+    if (reSet.indexIn(cmd.line) == -1)
         return false;
 
     showBlackMessage(QString());
@@ -3013,7 +3023,7 @@ bool FakeVimHandler::Private::handleExSetCommand(const QString &cmd) // :set
     } else if (act) {
         // non-boolean to show
         showBlackMessage(arg + '=' + act->value().toString());
-    } else if (arg.startsWith(QLatin1String("no"))
+    } else if (arg.startsWith(_("no"))
             && (act = theFakeVimSettings()->item(arg.mid(2)))) {
         // boolean config to be switched off
         bool oldValue = act->value().toBool();
@@ -3035,27 +3045,24 @@ bool FakeVimHandler::Private::handleExSetCommand(const QString &cmd) // :set
     return true;
 }
 
-bool FakeVimHandler::Private::handleExNormalCommand(const QString &cmd) // :normal
+bool FakeVimHandler::Private::handleExNormalCommand(const ExCommand &cmd) // :normal
 {
     static QRegExp reNormal("^norm(al)?( (.*))?$");
-    if (reNormal.indexIn(cmd) == -1)
+    if (reNormal.indexIn(cmd.line) == -1)
         return false;
     //qDebug() << "REPLAY NORMAL: " << quoteUnprintable(reNormal.cap(3));
     replay(reNormal.cap(3), 1);
     return true;
 }
 
-bool FakeVimHandler::Private::handleExDeleteCommand(const QString &line) // :d
+bool FakeVimHandler::Private::handleExDeleteCommand(const ExCommand &cmd) // :d
 {
-    int beginLine, endLine;
-    QString cmd = extractCommand(line, &beginLine, &endLine);
-
-    static QRegExp reDelete("^d( (.*))?$");
-    if (reDelete.indexIn(cmd) != -1)
+    static QRegExp reDelete("^d(elete)?( (.*))?$");
+    if (reDelete.indexIn(cmd.line) == -1)
         return false;
 
-    selectRange(beginLine, endLine);
-    QString reg = reDelete.cap(2);
+    selectRange(cmd.beginLine, cmd.endLine);
+    QString reg = reDelete.cap(3);
     QString text = selectedText();
     removeSelectedText();
     if (!reg.isEmpty()) {
@@ -3066,28 +3073,27 @@ bool FakeVimHandler::Private::handleExDeleteCommand(const QString &line) // :d
     return true;
 }
 
-bool FakeVimHandler::Private::handleExWriteCommand(const QString &line)
+bool FakeVimHandler::Private::handleExWriteCommand(const ExCommand &cmd)
     // :w, :x, :q, :wq, ...
 {
-    int beginLine, endLine;
-    QString cmd = extractCommand(line, &beginLine, &endLine);
-
     static QRegExp reWrite("^[wx]q?a?!?( (.*))?$");
-    if (reWrite.indexIn(cmd) == -1) // :w and :x
+    if (reWrite.indexIn(cmd.line) == -1) // :w and :x
         return false;
 
+    int beginLine = cmd.beginLine;
+    int endLine = cmd.endLine;
     bool noArgs = (beginLine == -1);
     if (beginLine == -1)
         beginLine = 0;
     if (endLine == -1)
         endLine = linesInDocument();
     //qDebug() << "LINES: " << beginLine << endLine;
-    int indexOfSpace = cmd.indexOf(QChar(' '));
+    int indexOfSpace = cmd.line.indexOf(QChar(' '));
     QString prefix;
     if (indexOfSpace < 0)
-        prefix = cmd;
+        prefix = cmd.line;
     else
-        prefix = cmd.left(indexOfSpace);
+        prefix = cmd.line.left(indexOfSpace);
     bool forced = prefix.contains(QChar('!'));
     bool quit = prefix.contains(QChar('q')) || prefix.contains(QChar('x'));
     bool quitAll = quit && prefix.contains(QChar('a'));
@@ -3140,16 +3146,16 @@ bool FakeVimHandler::Private::handleExWriteCommand(const QString &line)
     return true;
 }
 
-bool FakeVimHandler::Private::handleExReadCommand(const QString &line) // :r
+bool FakeVimHandler::Private::handleExReadCommand(const ExCommand &cmd) // :r
 {
-    if (!line.startsWith(QLatin1String("r ")))
+    if (!cmd.line.startsWith(_("r ")))
         return false;
 
     beginEditBlock();
     moveToStartOfLine();
     setTargetColumn();
     moveDown();
-    m_currentFileName = line.mid(2);
+    m_currentFileName = cmd.line.mid(2).trimmed();
     QFile file(m_currentFileName);
     file.open(QIODevice::ReadOnly);
     QTextStream ts(&file);
@@ -3161,23 +3167,20 @@ bool FakeVimHandler::Private::handleExReadCommand(const QString &line) // :r
     return true;
 }
 
-bool FakeVimHandler::Private::handleExBangCommand(const QString &line) // :!
+bool FakeVimHandler::Private::handleExBangCommand(const ExCommand &cmd) // :!
 {
-    int beginLine, endLine;
-    QString cmd = extractCommand(line, &beginLine, &endLine);
-
-    if (!cmd.startsWith(QLatin1Char('!')))
+    if (!cmd.line.startsWith(QLatin1Char('!')))
         return false;
 
-    selectRange(beginLine, endLine);
-    int targetPosition = firstPositionInLine(beginLine);
-    QString command = cmd.mid(1).trimmed();
+    selectRange(cmd.beginLine, cmd.endLine);
+    int targetPosition = firstPositionInLine(cmd.beginLine);
+    QString command = cmd.line.mid(1).trimmed();
     QString text = selectedText();
     QProcess proc;
     proc.start(command);
     proc.waitForStarted();
 #ifdef Q_OS_WIN
-    text.replace(QLatin1String("\n"), QLatin1String("\r\n"));
+    text.replace(_("\n"), _("\r\n"));
 #endif
     proc.write(text.toUtf8());
     proc.closeWriteChannel();
@@ -3185,7 +3188,7 @@ bool FakeVimHandler::Private::handleExBangCommand(const QString &line) // :!
     QString result = QString::fromUtf8(proc.readAllStandardOutput());
     beginEditBlock(targetPosition);
     removeSelectedText();
-    m_tc.insertText(result);
+    insertText(result);
     setPosition(targetPosition);
     endEditBlock();
     leaveVisualMode();
@@ -3195,26 +3198,23 @@ bool FakeVimHandler::Private::handleExBangCommand(const QString &line) // :!
     return true;
 }
 
-bool FakeVimHandler::Private::handleExShiftRightCommand(const QString &line) // :>
+bool FakeVimHandler::Private::handleExShiftRightCommand(const ExCommand &cmd) // :>
 {
-    int beginLine, endLine;
-    QString cmd = extractCommand(line, &beginLine, &endLine);
-
-    if (!cmd.startsWith(QLatin1Char('>')))
+    if (!cmd.line.startsWith(QLatin1Char('>')))
         return false;
 
-    m_anchor = firstPositionInLine(beginLine);
-    setPosition(firstPositionInLine(endLine));
+    m_anchor = firstPositionInLine(cmd.beginLine);
+    setPosition(firstPositionInLine(cmd.endLine));
     shiftRegionRight(1);
     leaveVisualMode();
     showBlackMessage(FakeVimHandler::tr("%n lines >ed %1 time", 0,
-        (endLine - beginLine + 1)).arg(1));
+        (cmd.endLine - cmd.beginLine + 1)).arg(1));
     return true;
 }
 
-bool FakeVimHandler::Private::handleExRedoCommand(const QString &line) // :redo
+bool FakeVimHandler::Private::handleExRedoCommand(const ExCommand &cmd) // :redo
 {
-    if (line != "red" && line != "redo")
+    if (cmd.line != "red" && cmd.line != "redo")
         return false;
 
     redo();
@@ -3222,26 +3222,23 @@ bool FakeVimHandler::Private::handleExRedoCommand(const QString &line) // :redo
     return true;
 }
 
-bool FakeVimHandler::Private::handleExGotoCommand(const QString &line) // :<nr>
+bool FakeVimHandler::Private::handleExGotoCommand(const ExCommand &cmd) // :<nr>
 {
-    int beginLine, endLine;
-    QString cmd = extractCommand(line, &beginLine, &endLine);
-
-    if (!cmd.isEmpty())
+    if (!cmd.line.isEmpty())
         return false;
 
-    setPosition(firstPositionInLine(beginLine));
+    setPosition(firstPositionInLine(cmd.beginLine));
     showBlackMessage(QString());
     return true;
 }
 
-bool FakeVimHandler::Private::handleExSourceCommand(const QString &line) // :source
+bool FakeVimHandler::Private::handleExSourceCommand(const ExCommand &cmd) // :source
 {
-    int pos = line.indexOf(' ');
-    if (line.leftRef(pos) != "so" && line.leftRef(pos) != "source")
+    const int pos = cmd.line.indexOf(' ');
+    if (cmd.line.leftRef(pos) != "so" && cmd.line.leftRef(pos) != "source")
         return false;
 
-    QString fileName = line.mid(pos + 1);
+    QString fileName = cmd.line.mid(pos + 1).trimmed();
     QFile file(fileName);
     if (!file.open(QIODevice::ReadOnly)) {
         showRedMessage(FakeVimHandler::tr("Can't open file %1").arg(fileName));
@@ -3274,28 +3271,41 @@ bool FakeVimHandler::Private::handleExSourceCommand(const QString &line) // :sou
 void FakeVimHandler::Private::handleExCommand(const QString &line0)
 {
     QString line = line0; // Make sure we have a copy to prevent aliasing.
+    ExCommand cmd(line, -1, -1);
+
+    // FIXME: that seems to be different for %w and %s
+    if (line.startsWith(QLatin1Char('%')))
+        line = "1,$" + line.mid(1);
+
+    cmd.beginLine = readLineCode(line);
+    if (line.startsWith(',')) {
+        line = line.mid(1);
+        cmd.endLine = readLineCode(line);
+    }
+    cmd.line = line;
+    //qDebug() << "CMD: " << cmd;
+
     enterCommandMode();
     showBlackMessage(QString());
-    if (handleExCommandHelper(line))
-        return;
-    int beginLine, endLine;
-    passUnknownExCommand(extractCommand(line, &beginLine, &endLine));
+    if (!handleExCommandHelper(cmd))
+        passUnknownExCommand(cmd.line);
 }
 
-bool FakeVimHandler::Private::handleExCommandHelper(const QString &line)
+bool FakeVimHandler::Private::handleExCommandHelper(const ExCommand &cmd)
 {
-    return handleExGotoCommand(line)
-        || handleExBangCommand(line)
-        || handleExHistoryCommand(line)
-        || handleExMapCommand(line)
-        || handleExNormalCommand(line)
-        || handleExReadCommand(line)
-        || handleExRedoCommand(line)
-        || handleExSetCommand(line)
-        || handleExShiftRightCommand(line)
-        || handleExSourceCommand(line)
-        || handleExSubstituteCommand(line)
-        || handleExWriteCommand(line);
+    return handleExGotoCommand(cmd)
+        || handleExBangCommand(cmd)
+        || handleExHistoryCommand(cmd)
+        || handleExDeleteCommand(cmd)
+        || handleExMapCommand(cmd)
+        || handleExNormalCommand(cmd)
+        || handleExReadCommand(cmd)
+        || handleExRedoCommand(cmd)
+        || handleExSetCommand(cmd)
+        || handleExShiftRightCommand(cmd)
+        || handleExSourceCommand(cmd)
+        || handleExSubstituteCommand(cmd)
+        || handleExWriteCommand(cmd);
 }
 
 void FakeVimHandler::Private::passUnknownExCommand(const QString &cmd)
@@ -3311,17 +3321,17 @@ void FakeVimHandler::Private::passUnknownSetCommand(const QString &arg)
     bool handled = false;
     emit q->handleSetCommandRequested(&handled, arg);
     if (!handled) {
-        showRedMessage(FakeVimHandler::tr("E512: Unknown option: ") + arg);
+        showRedMessage(FakeVimHandler::tr("Unknown option: ") + arg);
     }
 }
 
 static void vimPatternToQtPattern(QString *needle, QTextDocument::FindFlags *flags)
 {
     // FIXME: Rough mapping of a common case
-    if (needle->startsWith(QLatin1String("\\<")) && needle->endsWith(QLatin1String("\\>")))
+    if (needle->startsWith(_("\\<")) && needle->endsWith(_("\\>")))
         (*flags) |= QTextDocument::FindWholeWords;
-    needle->remove(QLatin1String("\\<")); // start of word
-    needle->remove(QLatin1String("\\>")); // end of word
+    needle->remove(_("\\<")); // start of word
+    needle->remove(_("\\>")); // end of word
     //qDebug() << "NEEDLE " << needle0 << needle;
 }
 
@@ -3462,6 +3472,7 @@ int FakeVimHandler::Private::indentText(const Range &range, QChar typedChar)
     // lineForPosition has returned 1-based line numbers
     emit q->indentRegion(&amount, beginLine-1, endLine-1, typedChar);
 
+    showBlackMessage("MARKS ARE OFF NOW");
     return amount;
 }
 
@@ -3970,6 +3981,14 @@ void FakeVimHandler::Private::transformText(const Range &range,
     }
 }
 
+void FakeVimHandler::Private::insertText(const Register &reg)
+{
+    QTC_ASSERT(reg.rangemode == RangeCharMode,
+        qDebug() << "WRONG INSERT MODE: " << reg.rangemode; return);
+    fixMarks(position(), reg.contents.length());
+    m_tc.insertText(reg.contents);
+}
+
 void FakeVimHandler::Private::removeSelectedText()
 {
     Range range(anchor(), position(), m_rangemode);
@@ -4047,8 +4066,7 @@ void FakeVimHandler::Private::pasteText(bool afterCursor)
             for (int i = count(); --i >= 0; ) {
                 if (afterCursor && rightDist() > 0)
                     moveRight();
-                fixMarks(position(), text.length());
-                m_tc.insertText(text);
+                insertText(text);
                 if (!afterCursor && atEndOfLine())
                     moveLeft();
                 moveLeft();
@@ -4062,8 +4080,7 @@ void FakeVimHandler::Private::pasteText(bool afterCursor)
             for (int i = count(); --i >= 0; ) {
                 if (afterCursor)
                     moveDown();
-                fixMarks(position(), text.length());
-                m_tc.insertText(text);
+                insertText(text);
                 moveUp(lines.size() - 1);
             }
             moveToFirstNonBlankOnLine();
@@ -4088,8 +4105,8 @@ void FakeVimHandler::Private::pasteText(bool afterCursor)
                 } else {
                     tc.movePosition(Right, MoveAnchor, col - 1 + afterCursor);
                 }
-                qDebug() << "INSERT " << line << " AT " << tc.position()
-                    << "COL: " << col;
+                //qDebug() << "INSERT " << line << " AT " << tc.position()
+                //    << "COL: " << col;
                 fixMarks(position(), line.length());
                 tc.insertText(line);
                 tc.movePosition(StartOfLine, MoveAnchor);
@@ -4109,16 +4126,38 @@ void FakeVimHandler::Private::pasteText(bool afterCursor)
 }
 
 //FIXME: This needs to called after undo/insert
-void FakeVimHandler::Private::fixMarks(int positionAction, int positionChange)
-{
-    QHashIterator<int, int> i(m_marks);
-    while (i.hasNext()) {
-        i.next();
-        if (i.value() >= positionAction) {
-            if (i.value() + positionChange > 0)
-                m_marks[i.key()] = i.value() + positionChange;
-            else
-                m_marks.remove(i.key());
+// The position 'from' is the cursor position after the change. If 'delta'
+// is positive there was a string of size 'delta' inserted after 'from'
+// and consequently all marks beyond 'from + delta' need to be incremented
+// by 'delta'. If text was removed, 'delta' is negative. All marks between
+// 'from' and 'from - delta' need to be removed, everything behing
+// 'from - delta' adjusted by 'delta'.
+void FakeVimHandler::Private::fixMarks(int from, int delta)
+{
+    //qDebug() << "ADJUSTING MARKS FROM " << from << " BY " << delta;
+    if (delta == 0)
+        return;
+    QHashIterator<int, int> it(m_marks);
+    while (it.hasNext()) {
+        it.next();
+        int pos = it.value();
+        if (delta > 0) {
+            // Inserted text.
+            if (pos >= from) {
+                //qDebug() << "MODIFIED: " << it.key() << pos;
+                setMark(it.key(), pos + delta);
+            }
+        } else {
+            // Removed text.
+            if (pos < from) {
+                // Nothing to do.
+            } else if (pos < from - delta) {
+                //qDebug() << "GONE: " << it.key();
+                m_marks.remove(it.key());
+            } else {
+                //qDebug() << "MODIFIED: " << it.key() << pos;
+                setMark(it.key(), pos + delta);
+             }
         }
     }
 }
@@ -4128,13 +4167,15 @@ QString FakeVimHandler::Private::lineContents(int line) const
     return m_tc.document()->findBlockByNumber(line - 1).text();
 }
 
-void FakeVimHandler::Private::setLineContents(int line, const QString &contents) const
+void FakeVimHandler::Private::setLineContents(int line, const QString &contents)
 {
     QTextBlock block = m_tc.document()->findBlockByNumber(line - 1);
     QTextCursor tc = m_tc;
     tc.setPosition(block.position());
     tc.setPosition(block.position() + block.length() - 1, KeepAnchor);
     tc.removeSelectedText();
+    fixMarks(block.position(),
+        block.position() + block.length() - 1 - contents.size());
     tc.insertText(contents);
 }
 
@@ -4161,8 +4202,8 @@ void FakeVimHandler::Private::enterVisualMode(VisualMode visualMode)
     setAnchor();
     m_positionPastEnd = m_anchorPastEnd = false;
     m_visualMode = visualMode;
-    m_marks['<'] = m_tc.position();
-    m_marks['>'] = m_tc.position();
+    setMark('<', m_tc.position());
+    setMark('>', m_tc.position());
     updateMiniBuffer();
     updateSelection();
 }
@@ -4189,11 +4230,16 @@ QWidget *FakeVimHandler::Private::editor() const
 void FakeVimHandler::Private::undo()
 {
     //qDebug() << " CURSOR POS: " << m_undoCursorPosition;
-    int current = m_tc.document()->availableUndoSteps();
-    //endEditBlock();
+    QTextDocument *doc = m_tc.document();
+    // FIXME: That's only an approximaxtion. The real solution might
+    // be to store marks and old userData with QTextBlock setUserData
+    // and retrieve them afterward.
+    const int current = doc->availableUndoSteps();
+    const int oldCount = doc->characterCount();
     EDITOR(undo());
-    //beginEditBlock();
-    int rev = m_tc.document()->availableUndoSteps();
+    const int delta = doc->characterCount() - oldCount;
+    fixMarks(position(), delta);
+    const int rev = doc->availableUndoSteps();
     if (current == rev)
         showBlackMessage(FakeVimHandler::tr("Already at oldest change"));
     else
@@ -4207,11 +4253,13 @@ void FakeVimHandler::Private::undo()
 
 void FakeVimHandler::Private::redo()
 {
-    int current = m_tc.document()->availableUndoSteps();
-    //endEditBlock();
+    QTextDocument *doc = m_tc.document();
+    const int current = m_tc.document()->availableUndoSteps();
+    const int oldCount = doc->characterCount();
     EDITOR(redo());
-    //beginEditBlock();
-    int rev = m_tc.document()->availableUndoSteps();
+    const int delta = doc->characterCount() - oldCount;
+    fixMarks(position(), delta);
+    const int rev = doc->availableUndoSteps();
     if (rev == current)
         showBlackMessage(FakeVimHandler::tr("Already at newest change"));
     else
@@ -4319,6 +4367,7 @@ void FakeVimHandler::Private::insertAutomaticIndentation(bool goingDown)
     if (hasConfig(ConfigSmartIndent)) {
         Range range(m_tc.block().position(), m_tc.block().position());
         m_justAutoIndented = indentText(range, QLatin1Char('\n'));
+        fixMarks(m_tc.block().position(), m_justAutoIndented);
     } else {
         QTextBlock block = goingDown ? m_tc.block().previous() : m_tc.block().next();
         QString text = block.text();
@@ -4328,7 +4377,7 @@ void FakeVimHandler::Private::insertAutomaticIndentation(bool goingDown)
             ++pos;
         text.truncate(pos);
         // FIXME: handle 'smartindent' and 'cindent'
-        m_tc.insertText(text);
+        insertText(text);
         m_justAutoIndented = text.size();
     }
 }
@@ -4339,6 +4388,7 @@ bool FakeVimHandler::Private::removeAutomaticIndentation()
         return false;
     m_tc.movePosition(StartOfLine, KeepAnchor);
     m_tc.removeSelectedText();
+    fixMarks(m_tc.position(), -m_justAutoIndented);
     m_lastInsertion.chop(m_justAutoIndented);
     m_justAutoIndented = 0;
     return true;
@@ -4371,7 +4421,7 @@ void FakeVimHandler::Private::selectWordTextObject(bool inner)
     setAnchor();
     // FIXME: Rework the 'anchor' concept.
     if (isVisualMode())
-        m_marks['<'] = m_tc.position();
+        setMark('<', m_tc.position());
     moveToWordBoundary(false, true, true);
     m_movetype = MoveInclusive;
 }
@@ -4384,7 +4434,7 @@ void FakeVimHandler::Private::selectWORDTextObject(bool inner)
     setAnchor();
     // FIXME: Rework the 'anchor' concept.
     if (isVisualMode())
-        m_marks['<'] = m_tc.position();
+        setMark('<', m_tc.position());
     moveToWordBoundary(true, true, true);
     m_movetype = MoveInclusive;
 }
@@ -4412,6 +4462,18 @@ void FakeVimHandler::Private::selectQuotedStringTextObject(bool inner, int type)
     Q_UNUSED(type);
 }
 
+int FakeVimHandler::Private::mark(int code) const
+{
+    // FIXME: distinguish local and global marks.
+    //qDebug() << "MARK: " << code << m_marks.value(code, -1) << m_marks;
+    return m_marks.value(code, -1);
+}
+
+void FakeVimHandler::Private::setMark(int code, int position)
+{
+    // FIXME: distinguish local and global marks.
+    m_marks[code] = position;
+}
 
 ///////////////////////////////////////////////////////////////////////
 //