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