diff --git a/src/plugins/fakevim/fakevimactions.cpp b/src/plugins/fakevim/fakevimactions.cpp
index 272c2d10fefda776bfaf91dd061e4ad7dddc1387..25adb4af720081070be9b3c4a1bb90a991f1e9ad 100644
--- a/src/plugins/fakevim/fakevimactions.cpp
+++ b/src/plugins/fakevim/fakevimactions.cpp
@@ -119,9 +119,11 @@ FakeVimSettings *theFakeVimSettings()
     item->setText(QCoreApplication::translate("FakeVim::Internal", "Toggle vim-style editing"));
     item->setSettingsKey(group, QLatin1String("UseFakeVim"));
     item->setCheckable(true);
+    item->setValue(false);
     instance->insertItem(ConfigUseFakeVim, item);
 
     item = new SavedAction(instance);
+    item->setValue(false);
     item->setDefaultValue(false);
     item->setSettingsKey(group, QLatin1String("StartOfLine"));
     item->setCheckable(true);
@@ -134,11 +136,13 @@ FakeVimSettings *theFakeVimSettings()
 
     item = new SavedAction(instance);
     item->setDefaultValue(false);
+    item->setValue(false);
     item->setSettingsKey(group, QLatin1String("SmartTab"));
     instance->insertItem(ConfigSmartTab, item, QLatin1String("smarttab"), QLatin1String("sta"));
 
     item = new SavedAction(instance);
     item->setDefaultValue(true);
+    item->setValue(true);
     item->setSettingsKey(group, QLatin1String("HlSearch"));
     item->setCheckable(true);
     instance->insertItem(ConfigHlSearch, item, QLatin1String("hlsearch"), QLatin1String("hls"));
@@ -150,18 +154,22 @@ FakeVimSettings *theFakeVimSettings()
 
     item = new SavedAction(instance);
     item->setDefaultValue(false);
+    item->setValue(false);
     item->setSettingsKey(group, QLatin1String("ExpandTab"));
     item->setCheckable(true);
     instance->insertItem(ConfigExpandTab, item, QLatin1String("expandtab"), QLatin1String("et"));
 
     item = new SavedAction(instance);
     item->setDefaultValue(false);
+    item->setValue(false);
     item->setSettingsKey(group, QLatin1String("AutoIndent"));
+    item->setValue(false);
     item->setCheckable(true);
     instance->insertItem(ConfigAutoIndent, item, QLatin1String("autoindent"), QLatin1String("ai"));
 
     item = new SavedAction(instance);
     item->setDefaultValue(true);
+    item->setValue(true);
     item->setSettingsKey(group, QLatin1String("IncSearch"));
     item->setCheckable(true);
     instance->insertItem(ConfigIncSearch, item, QLatin1String("incsearch"), QLatin1String("is"));
diff --git a/src/plugins/fakevim/fakevimhandler.cpp b/src/plugins/fakevim/fakevimhandler.cpp
index 89ead723ad35c43e800aa8bbe5bd3027ecc0561d..e82db31a94f194e7841b99c8aad275766edb5d9d 100755
--- a/src/plugins/fakevim/fakevimhandler.cpp
+++ b/src/plugins/fakevim/fakevimhandler.cpp
@@ -77,6 +77,7 @@
 #include <QtGui/QTextEdit>
 
 #include <climits>
+#include <ctype.h>
 
 //#define DEBUG_KEY  1
 #if DEBUG_KEY
@@ -187,6 +188,13 @@ enum EventResult
     EventPassedToCore
 };
 
+struct Indentation
+{
+    Indentation(int p, int l) : physical(p), logical(l) {}
+    int physical; // number of characters
+    int logical;
+};
+
 struct CursorPosition
 {
     // for jump history
@@ -294,13 +302,14 @@ public:
     QString lineContents(int line) const; // 1 based line
     void setLineContents(int line, const QString &contents) const; // 1 based line
 
-    // all zero-based counting
-    int cursorLineOnScreen() const;
     int linesOnScreen() const;
     int columnsOnScreen() const;
+    int linesInDocument() const;
+
+    // all zero-based counting
+    int cursorLineOnScreen() const;
     int cursorLineInDocument() const;
     int cursorColumnInDocument() const;
-    int linesInDocument() const;
     int firstVisibleLineInDocument() const;
     void scrollToLineInDocument(int line);
     void scrollUp(int count);
@@ -367,6 +376,7 @@ public:
     // stand-alone test application to handle the command)
     void passUnknownExCommand(const QString &cmd);
 
+
 public:
     QTextEdit *m_textedit;
     QPlainTextEdit *m_plaintextedit;
@@ -465,6 +475,8 @@ public:
     int m_cursorWidth;
 
     // auto-indent
+    QString tabExpand(int len) const;
+    Indentation indentation(const QString &line) const;
     void insertAutomaticIndentation(bool goingDown);
     bool removeAutomaticIndentation(); // true if something removed
     // number of autoindented characters
@@ -1691,10 +1703,24 @@ EventResult FakeVimHandler::Private::handleInsertMode(int key, int,
         insertAutomaticIndentation(true);
         setTargetColumn();
     } else if (key == Key_Backspace || key == control('h')) {
-        if (!removeAutomaticIndentation())
-            if (!m_lastInsertion.isEmpty() || hasConfig(ConfigBackspace, "start")) {
-                m_tc.deletePreviousChar();
-                m_lastInsertion.chop(1);
+        if (!removeAutomaticIndentation()
+            && (!m_lastInsertion.isEmpty()
+                || hasConfig(ConfigBackspace, "start")))
+            {
+                int line = cursorLineInDocument() + 1;
+                int col = cursorColumnInDocument();
+                QString data = lineContents(line);
+                Indentation ind = indentation(data);
+                if (col <= ind.logical) {
+                    int ts = config(ConfigTabStop).toInt();
+                    int newcol = col - 1 - (col - 1) % ts;
+                    data = tabExpand(newcol) + data.mid(col);
+                    setLineContents(line, data);
+                    m_lastInsertion.clear(); // FIXME
+                } else {
+                    m_tc.deletePreviousChar();
+                    m_lastInsertion.chop(1);
+                }
                 setTargetColumn();
             }
     } else if (key == Key_Delete) {
@@ -1709,7 +1735,9 @@ EventResult FakeVimHandler::Private::handleInsertMode(int key, int,
         moveUp(count() * (linesOnScreen() - 2));
         m_lastInsertion.clear();
     } else if (key == Key_Tab && hasConfig(ConfigExpandTab)) {
-        QString str = QString(theFakeVimSetting(ConfigTabStop)->value().toInt(), ' ');
+        int ts = config(ConfigTabStop).toInt();
+        int col = cursorColumnInDocument();
+        QString str = QString(ts - col % ts, ' ');
         m_lastInsertion.append(str);
         m_tc.insertText(str);
         setTargetColumn();
@@ -1901,7 +1929,8 @@ static bool isSubstitution(const QString &cmd0, QStringList *result)
     QString cmd;
     if (cmd0.startsWith("substitute"))
         cmd = cmd0.mid(10);
-    else if (cmd0.startsWith('s'))
+    else if (cmd0.startsWith('s') && cmd0.size() > 1
+            && !isalpha(cmd0.at(1).unicode()))
         cmd = cmd0.mid(1);
     else
         return false;
@@ -1964,8 +1993,6 @@ void FakeVimHandler::Private::handleExCommand(const QString &cmd0)
     static QRegExp reNormal("^norm(al)?( (.*))?$");
     static QRegExp reSet("^set?( (.*))?$");
     static QRegExp reWrite("^[wx]q?a?!?( (.*))?$");
-    //static QRegExp reSubstitute("^s(.)(.*)\\1(.*)(\\1([gi]*))?$");
-    //reSubstitute.setMinimal(true);
     QStringList arguments;
 
     enterCommandMode();
@@ -2006,7 +2033,8 @@ void FakeVimHandler::Private::handleExCommand(const QString &cmd0)
         QFile file1(fileName);
         bool exists = file1.exists();
         if (exists && !forced && !noArgs) {
-            showRedMessage(FakeVimHandler::tr("File '%1' exists (add ! to override)").arg(fileName));
+            showRedMessage(FakeVimHandler::tr
+                ("File '%1' exists (add ! to override)").arg(fileName));
         } else if (file1.open(QIODevice::ReadWrite)) {
             file1.close();
             QTextCursor tc = m_tc;
@@ -2026,7 +2054,8 @@ void FakeVimHandler::Private::handleExCommand(const QString &cmd0)
                     QTextStream ts(&file2);
                     ts << contents;
                 } else {
-                    showRedMessage(FakeVimHandler::tr("Cannot open file '%1' for writing").arg(fileName));
+                    showRedMessage(FakeVimHandler::tr
+                       ("Cannot open file '%1' for writing").arg(fileName));
                 }
             }
             // check result by reading back
@@ -2041,9 +2070,10 @@ void FakeVimHandler::Private::handleExCommand(const QString &cmd0)
             else if (quit)
                 passUnknownExCommand(forced ? "q!" : "q");
         } else {
-            showRedMessage(FakeVimHandler::tr("Cannot open file '%1' for reading").arg(fileName));
+            showRedMessage(FakeVimHandler::tr
+                ("Cannot open file '%1' for reading").arg(fileName));
         }
-    } else if (cmd.startsWith("r ")) { // :r
+    } else if (cmd.startsWith(QLatin1String("r "))) { // :r
         m_currentFileName = cmd.mid(2);
         QFile file(m_currentFileName);
         file.open(QIODevice::ReadOnly);
@@ -2889,13 +2919,42 @@ void FakeVimHandler::Private::recordNewUndo()
     //beginEditBlock();
 }
 
+Indentation FakeVimHandler::Private::indentation(const QString &line) const
+{
+    int ts = config(ConfigTabStop).toInt();
+    int physical = 0;
+    int logical = 0;
+    int n = line.size();
+    while (physical < n) {
+        QChar c = line.at(physical);
+        if (c == QLatin1Char(' '))
+            ++logical;
+        else if (c == QLatin1Char('\t'))
+            logical += ts - logical % ts;
+        else
+            break;
+        ++physical;
+    }
+    return Indentation(physical, logical);
+}
+
+QString FakeVimHandler::Private::tabExpand(int n) const
+{
+    int ts = config(ConfigTabStop).toInt();
+    if (hasConfig(ConfigExpandTab) || ts < 1)
+        return QString(n, QLatin1Char(' '));
+    return QString(n / ts, QLatin1Char('\t'))
+         + QString(n % ts, QLatin1Char(' '));
+}
+
 void FakeVimHandler::Private::insertAutomaticIndentation(bool goingDown)
 {
     if (!hasConfig(ConfigAutoIndent))
         return;
     QTextBlock block = goingDown ? m_tc.block().previous() : m_tc.block().next();
     QString text = block.text();
-    int pos = 0, n = text.size();
+    int pos = 0;
+    int n = text.size();
     while (pos < n && text.at(pos).isSpace())
         ++pos;
     text.truncate(pos);
@@ -2934,6 +2993,7 @@ void FakeVimHandler::Private::replay(const QString &command, int n)
     m_inReplay = false;
 }
 
+
 ///////////////////////////////////////////////////////////////////////
 //
 // FakeVimHandler
@@ -3013,10 +3073,30 @@ void FakeVimHandler::showRedMessage(const QString &msg)
    d->showRedMessage(msg);
 }
 
+
 QWidget *FakeVimHandler::widget()
 {
     return d->editor();
 }
 
+// Test only
+int FakeVimHandler::physicalIndentation(const QString &line) const
+{
+    Indentation ind = d->indentation(line);
+    return ind.physical;
+}
+
+int FakeVimHandler::logicalIndentation(const QString &line) const
+{
+    Indentation ind = d->indentation(line);
+    return ind.logical;
+}
+
+QString FakeVimHandler::tabExpand(int n) const
+{
+    return d->tabExpand(n);
+}
+
+
 } // namespace Internal
 } // namespace FakeVim
diff --git a/src/plugins/fakevim/fakevimhandler.h b/src/plugins/fakevim/fakevimhandler.h
index 66e5dc18f191d7398eca6ea13d3e408bb383a962..3abfa276895fa43f46ca1b62f67cf3a88bd357e7 100644
--- a/src/plugins/fakevim/fakevimhandler.h
+++ b/src/plugins/fakevim/fakevimhandler.h
@@ -63,6 +63,11 @@ public slots:
     void setupWidget();
     void restoreWidget();
 
+    // Test only
+    int physicalIndentation(const QString &line) const;
+    int logicalIndentation(const QString &line) const;
+    QString tabExpand(int n) const;
+
 signals:
     void commandBufferChanged(const QString &msg);
     void statusDataChanged(const QString &msg);
@@ -84,7 +89,7 @@ public:
 
 private:
     bool eventFilter(QObject *ob, QEvent *ev);
-    friend class Private;
+
     Private *d;
 };
 
diff --git a/tests/auto/fakevim/main.cpp b/tests/auto/fakevim/main.cpp
index 5c692fc5eaf169bf6e40b793fdcf1b78f9efcc9f..755a95c0d00a9e90b93e0a94aadaf5a986ba254f 100644
--- a/tests/auto/fakevim/main.cpp
+++ b/tests/auto/fakevim/main.cpp
@@ -55,6 +55,9 @@ public slots:
     void changeExtraInformation(const QString &info) { m_infoMessage = info; }
     
 private slots:
+    // functional tests
+    void indentation();
+
     // command mode
     void command_Cxx_down_dot();
     void command_Gyyp();
@@ -260,6 +263,81 @@ QString tst_FakeVim::insertCursor(const QString &needle0)
 }
 
 
+//////////////////////////////////////////////////////////////////////////
+//
+// Command mode
+//
+//////////////////////////////////////////////////////////////////////////
+
+void tst_FakeVim::indentation()
+{
+    setup();
+    sendEx("set expandtab");
+    sendEx("set tabstop=4");
+    sendEx("set shiftwidth=4");
+    QCOMPARE(m_handler->physicalIndentation("      \t\t\tx"), 6 + 3);
+    QCOMPARE(m_handler->logicalIndentation ("      \t\t\tx"), 4 + 3 * 4);
+    QCOMPARE(m_handler->physicalIndentation("     \t\t\tx"), 5 + 3);
+    QCOMPARE(m_handler->logicalIndentation ("     \t\t\tx"), 4 + 3 * 4);
+
+    QCOMPARE(m_handler->tabExpand(3), QLatin1String("   "));
+    QCOMPARE(m_handler->tabExpand(4), QLatin1String("    "));
+    QCOMPARE(m_handler->tabExpand(5), QLatin1String("     "));
+    QCOMPARE(m_handler->tabExpand(6), QLatin1String("      "));
+    QCOMPARE(m_handler->tabExpand(7), QLatin1String("       "));
+    QCOMPARE(m_handler->tabExpand(8), QLatin1String("        "));
+    QCOMPARE(m_handler->tabExpand(9), QLatin1String("         "));
+
+    sendEx("set expandtab");
+    sendEx("set tabstop=8");
+    sendEx("set shiftwidth=4");
+    QCOMPARE(m_handler->physicalIndentation("      \t\t\tx"), 6 + 3);
+    QCOMPARE(m_handler->logicalIndentation ("      \t\t\tx"), 0 + 3 * 8);
+    QCOMPARE(m_handler->physicalIndentation("     \t\t\tx"), 5 + 3);
+    QCOMPARE(m_handler->logicalIndentation ("     \t\t\tx"), 0 + 3 * 8);
+
+    QCOMPARE(m_handler->tabExpand(3), QLatin1String("   "));
+    QCOMPARE(m_handler->tabExpand(4), QLatin1String("    "));
+    QCOMPARE(m_handler->tabExpand(5), QLatin1String("     "));
+    QCOMPARE(m_handler->tabExpand(6), QLatin1String("      "));
+    QCOMPARE(m_handler->tabExpand(7), QLatin1String("       "));
+    QCOMPARE(m_handler->tabExpand(8), QLatin1String("        "));
+    QCOMPARE(m_handler->tabExpand(9), QLatin1String("         "));
+
+    sendEx("set noexpandtab");
+    sendEx("set tabstop=4");
+    sendEx("set shiftwidth=4");
+    QCOMPARE(m_handler->physicalIndentation("      \t\t\tx"), 6 + 3);
+    QCOMPARE(m_handler->logicalIndentation ("      \t\t\tx"), 4 + 3 * 4);
+    QCOMPARE(m_handler->physicalIndentation("     \t\t\tx"), 5 + 3);
+    QCOMPARE(m_handler->logicalIndentation ("     \t\t\tx"), 4 + 3 * 4);
+
+    QCOMPARE(m_handler->tabExpand(3), QLatin1String("   "));
+    QCOMPARE(m_handler->tabExpand(4), QLatin1String("\t"));
+    QCOMPARE(m_handler->tabExpand(5), QLatin1String("\t "));
+    QCOMPARE(m_handler->tabExpand(6), QLatin1String("\t  "));
+    QCOMPARE(m_handler->tabExpand(7), QLatin1String("\t   "));
+    QCOMPARE(m_handler->tabExpand(8), QLatin1String("\t\t"));
+    QCOMPARE(m_handler->tabExpand(9), QLatin1String("\t\t "));
+
+    sendEx("set noexpandtab");
+    sendEx("set tabstop=8");
+    sendEx("set shiftwidth=4");
+    QCOMPARE(m_handler->physicalIndentation("      \t\t\tx"), 6 + 3);
+    QCOMPARE(m_handler->logicalIndentation ("      \t\t\tx"), 0 + 3 * 8);
+    QCOMPARE(m_handler->physicalIndentation("     \t\t\tx"), 5 + 3);
+    QCOMPARE(m_handler->logicalIndentation ("     \t\t\tx"), 0 + 3 * 8);
+
+    QCOMPARE(m_handler->tabExpand(3), QLatin1String("   "));
+    QCOMPARE(m_handler->tabExpand(4), QLatin1String("    "));
+    QCOMPARE(m_handler->tabExpand(5), QLatin1String("     "));
+    QCOMPARE(m_handler->tabExpand(6), QLatin1String("      "));
+    QCOMPARE(m_handler->tabExpand(7), QLatin1String("       "));
+    QCOMPARE(m_handler->tabExpand(8), QLatin1String("\t"));
+    QCOMPARE(m_handler->tabExpand(9), QLatin1String("\t "));
+}
+
+
 //////////////////////////////////////////////////////////////////////////
 //
 // Command mode