diff --git a/src/plugins/fakevim/fakevimhandler.cpp b/src/plugins/fakevim/fakevimhandler.cpp index d0a5fc9b6c22deb9b6af1c8ee40197f9574bb03c..d86d72b0a23155f3da76794f92153483860061af 100644 --- a/src/plugins/fakevim/fakevimhandler.cpp +++ b/src/plugins/fakevim/fakevimhandler.cpp @@ -200,11 +200,11 @@ enum EventResult EventPassedToCore }; -struct Indentation +struct Column { - Indentation(int p, int l) : physical(p), logical(l) {} - int physical; // number of characters - int logical; + Column(int p, int l) : physical(p), logical(l) {} + int physical; // number of characters in the data + int logical; // column on screen }; struct CursorPosition @@ -336,7 +336,9 @@ public: // all zero-based counting int cursorLineOnScreen() const; int cursorLineInDocument() const; - int cursorColumnInDocument() const; + int physicalCursorColumnInDocument() const; // as stored in the data + int logicalCursorColumnInDocument() const; // as visible on screen + Column cursorColumnInDocument() const; // as visible on screen int firstVisibleLineInDocument() const; void scrollToLineInDocument(int line); void scrollUp(int count); @@ -530,7 +532,7 @@ public: // auto-indent QString tabExpand(int len) const; - Indentation indentation(const QString &line) const; + Column indentation(const QString &line) const; void insertAutomaticIndentation(bool goingDown); bool removeAutomaticIndentation(); // true if something removed // number of autoindented characters @@ -647,7 +649,7 @@ EventResult FakeVimHandler::Private::handleEvent(QKeyEvent *ev) if (m_mode == InsertMode) { int dist = m_tc.position() - m_oldPosition; // Try to compensate for code completion - if (dist > 0 && dist <= cursorColumnInDocument()) { + if (dist > 0 && dist <= physicalCursorColumnInDocument()) { Range range(m_oldPosition, m_tc.position()); m_lastInsertion.append(text(range)); } @@ -1107,7 +1109,7 @@ void FakeVimHandler::Private::updateMiniBuffer() int linesInDoc = linesInDocument(); int l = cursorLineInDocument(); QString status; - const QString pos = QString::fromLatin1("%1,%2").arg(l + 1).arg(cursorColumnInDocument() + 1); + const QString pos = QString::fromLatin1("%1,%2").arg(l + 1).arg(physicalCursorColumnInDocument() + 1); // FIXME: physical "-" logical if (linesInDoc != 0) { status = FakeVimHandler::tr("%1%2%").arg(pos, -10).arg(l * 100 / linesInDoc, 4); @@ -2029,13 +2031,15 @@ EventResult FakeVimHandler::Private::handleInsertMode(int key, int, m_justAutoIndented = 0; if (!m_lastInsertion.isEmpty() || hasConfig(ConfigBackspace, "start")) { const int line = cursorLineInDocument() + 1; - const int col = cursorColumnInDocument(); - const QString data = lineContents(line); - const Indentation ind = indentation(data); - if (col <= ind.logical && col && startsWithWhitespace(data, col)) { + const Column col = cursorColumnInDocument(); + QString data = lineContents(line); + const Column ind = indentation(data); + if (col.logical <= ind.logical && col.logical + && startsWithWhitespace(data, col.physical)) { const int ts = config(ConfigTabStop).toInt(); - const int newcol = col - 1 - (col - 1) % ts; - setLineContents(line, tabExpand(newcol).append(data.midRef(col))); + const int newcol = col.logical - 1 - (col.logical - 1) % ts; + data.remove(0, col.physical); + setLineContents(line, tabExpand(newcol).append(data)); m_lastInsertion.clear(); // FIXME } else { m_tc.deletePreviousChar(); @@ -2058,7 +2062,7 @@ EventResult FakeVimHandler::Private::handleInsertMode(int key, int, } else if (key == Key_Tab && hasConfig(ConfigExpandTab)) { m_justAutoIndented = 0; const int ts = config(ConfigTabStop).toInt(); - const int col = cursorColumnInDocument(); + const int col = physicalCursorColumnInDocument(); QString str = QString(ts - col % ts, ' '); m_lastInsertion.append(str); m_tc.insertText(str); @@ -2962,19 +2966,45 @@ int FakeVimHandler::Private::cursorLineInDocument() const return m_tc.block().blockNumber(); } -int FakeVimHandler::Private::cursorColumnInDocument() const +int FakeVimHandler::Private::physicalCursorColumnInDocument() const { return m_tc.position() - m_tc.block().position(); } +int FakeVimHandler::Private::logicalCursorColumnInDocument() const +{ + const int ncols = physicalCursorColumnInDocument(); + const QString line = m_tc.block().text(); + const int ts = config(ConfigTabStop).toInt(); + int physical = 0; + int logical = 0; + while (physical < ncols) { + QChar c = line.at(physical); + if (c == QLatin1Char(' ')) + ++logical; + else if (c == QLatin1Char('\t')) + logical += ts - logical % ts; + else + break; + ++physical; + } + return logical; +} + +Column FakeVimHandler::Private::cursorColumnInDocument() const +{ + return Column(physicalCursorColumnInDocument(), logicalCursorColumnInDocument()); +} + int FakeVimHandler::Private::linesInDocument() const { if (m_tc.isNull()) return 0; const QTextDocument *doc = m_tc.document(); const int count = doc->blockCount(); - // Qt inserts an empty line if the last character is a '\n', but that's not how vi does it - return doc->lastBlock().length()<=1 ? count-1 : count; + // Qt inserts an empty line if the last character is a '\n', + // but that's not how vi does it. + return doc->lastBlock().length() <= 1 ? count - 1 : count; } void FakeVimHandler::Private::scrollToLineInDocument(int line) @@ -3440,7 +3470,7 @@ void FakeVimHandler::Private::recordNewUndo() //beginEditBlock(); } -Indentation FakeVimHandler::Private::indentation(const QString &line) const +Column FakeVimHandler::Private::indentation(const QString &line) const { int ts = config(ConfigTabStop).toInt(); int physical = 0; @@ -3456,7 +3486,7 @@ Indentation FakeVimHandler::Private::indentation(const QString &line) const break; ++physical; } - return Indentation(physical, logical); + return Column(physical, logical); } QString FakeVimHandler::Private::tabExpand(int n) const @@ -3625,13 +3655,13 @@ QWidget *FakeVimHandler::widget() // Test only int FakeVimHandler::physicalIndentation(const QString &line) const { - Indentation ind = d->indentation(line); + Column ind = d->indentation(line); return ind.physical; } int FakeVimHandler::logicalIndentation(const QString &line) const { - Indentation ind = d->indentation(line); + Column ind = d->indentation(line); return ind.logical; }