Commit 2e09a8f4 authored by hjk's avatar hjk
Browse files

fakevim: fix up/down movement in the presence of real tabs

parent d3cea8a4
...@@ -630,19 +630,21 @@ public: ...@@ -630,19 +630,21 @@ public:
// The following use all zero-based counting. // The following use all zero-based counting.
int cursorLineOnScreen() const; int cursorLineOnScreen() const;
int cursorLineInDocument() const; int cursorLine() const;
int physicalCursorColumnInDocument() const; // as stored in the data int physicalCursorColumn() const; // as stored in the data
int logicalCursorColumnInDocument() const; // as visible on screen int logicalCursorColumn() const; // as visible on screen
Column cursorColumnInDocument() const; // as visible on screen int physicalToLogicalColumn(int physical, const QString &text) const;
int firstVisibleLineInDocument() const; int logicalToPhysicalColumn(int logical, const QString &text) const;
void scrollToLineInDocument(int line); Column cursorColumn() const; // as visible on screen
int firstVisibleLine() const;
void scrollToLine(int line);
void scrollUp(int count); void scrollUp(int count);
void scrollDown(int count) { scrollUp(-count); } void scrollDown(int count) { scrollUp(-count); }
CursorPosition cursorPosition() const CursorPosition cursorPosition() const
{ return CursorPosition(position(), firstVisibleLineInDocument()); } { return CursorPosition(position(), firstVisibleLine()); }
void setCursorPosition(const CursorPosition &p) void setCursorPosition(const CursorPosition &p)
{ setPosition(p.position); scrollToLineInDocument(p.scrollLine); } { setPosition(p.position); scrollToLine(p.scrollLine); }
// Helper functions for indenting/ // Helper functions for indenting/
bool isElectricCharacter(QChar c) const; bool isElectricCharacter(QChar c) const;
...@@ -654,7 +656,7 @@ public: ...@@ -654,7 +656,7 @@ public:
void moveToFirstNonBlankOnLine(); void moveToFirstNonBlankOnLine();
void moveToTargetColumn(); void moveToTargetColumn();
void setTargetColumn() { void setTargetColumn() {
m_targetColumn = leftDist(); m_targetColumn = logicalCursorColumn();
m_visualTargetColumn = m_targetColumn; m_visualTargetColumn = m_targetColumn;
//qDebug() << "TARGET: " << m_targetColumn; //qDebug() << "TARGET: " << m_targetColumn;
} }
...@@ -1009,7 +1011,7 @@ EventResult FakeVimHandler::Private::handleEvent(QKeyEvent *ev) ...@@ -1009,7 +1011,7 @@ EventResult FakeVimHandler::Private::handleEvent(QKeyEvent *ev)
if (m_mode == InsertMode) { if (m_mode == InsertMode) {
int dist = m_tc.position() - m_oldPosition; int dist = m_tc.position() - m_oldPosition;
// Try to compensate for code completion // Try to compensate for code completion
if (dist > 0 && dist <= physicalCursorColumnInDocument()) { if (dist > 0 && dist <= physicalCursorColumn()) {
Range range(m_oldPosition, m_tc.position()); Range range(m_oldPosition, m_tc.position());
m_lastInsertion.append(selectText(range)); m_lastInsertion.append(selectText(range));
} }
...@@ -1564,10 +1566,10 @@ void FakeVimHandler::Private::updateMiniBuffer() ...@@ -1564,10 +1566,10 @@ void FakeVimHandler::Private::updateMiniBuffer()
emit q->commandBufferChanged(msg); emit q->commandBufferChanged(msg);
int linesInDoc = linesInDocument(); int linesInDoc = linesInDocument();
int l = cursorLineInDocument(); int l = cursorLine();
QString status; QString status;
const QString pos = QString::fromLatin1("%1,%2") const QString pos = QString::fromLatin1("%1,%2")
.arg(l + 1).arg(physicalCursorColumnInDocument() + 1); .arg(l + 1).arg(physicalCursorColumn() + 1);
// FIXME: physical "-" logical // FIXME: physical "-" logical
if (linesInDoc != 0) { if (linesInDoc != 0) {
status = FakeVimHandler::tr("%1%2%").arg(pos, -10).arg(l * 100 / linesInDoc, 4); status = FakeVimHandler::tr("%1%2%").arg(pos, -10).arg(l * 100 / linesInDoc, 4);
...@@ -1770,7 +1772,7 @@ EventResult FakeVimHandler::Private::handleCommandMode(const Input &input) ...@@ -1770,7 +1772,7 @@ EventResult FakeVimHandler::Private::handleCommandMode(const Input &input)
setDotCommand("%1==", count()); setDotCommand("%1==", count());
finishMovement(); finishMovement();
} else if (m_submode == ZSubMode) { } else if (m_submode == ZSubMode) {
//qDebug() << "Z_MODE " << cursorLineInDocument() << linesOnScreen(); //qDebug() << "Z_MODE " << cursorLine() << linesOnScreen();
if (input.isReturn() || input.is('t')) { if (input.isReturn() || input.is('t')) {
// Cursor line to top of window. // Cursor line to top of window.
if (!m_mvcount.isEmpty()) if (!m_mvcount.isEmpty())
...@@ -2078,7 +2080,7 @@ EventResult FakeVimHandler::Private::handleCommandMode(const Input &input) ...@@ -2078,7 +2080,7 @@ EventResult FakeVimHandler::Private::handleCommandMode(const Input &input)
// FIXME: this should use the "scroll" option, and "count" // FIXME: this should use the "scroll" option, and "count"
moveDown(linesOnScreen() / 2); moveDown(linesOnScreen() / 2);
handleStartOfLine(); handleStartOfLine();
scrollToLineInDocument(cursorLineInDocument() - sline); scrollToLine(cursorLine() - sline);
finishMovement(); finishMovement();
} else if (input.is('e') || input.isShift(Key_Right)) { } else if (input.is('e') || input.isShift(Key_Right)) {
m_movetype = MoveInclusive; m_movetype = MoveInclusive;
...@@ -2300,7 +2302,7 @@ EventResult FakeVimHandler::Private::handleCommandMode(const Input &input) ...@@ -2300,7 +2302,7 @@ EventResult FakeVimHandler::Private::handleCommandMode(const Input &input)
enterInsertMode(); enterInsertMode();
} else if (input.is('S')) { } else if (input.is('S')) {
if (!isVisualMode()) { if (!isVisualMode()) {
const int line = cursorLineInDocument() + 1; const int line = cursorLine() + 1;
setAnchor(firstPositionInLine(line)); setAnchor(firstPositionInLine(line));
setPosition(lastPositionInLine(line + count() - 1)); setPosition(lastPositionInLine(line + count() - 1));
} }
...@@ -2334,7 +2336,7 @@ EventResult FakeVimHandler::Private::handleCommandMode(const Input &input) ...@@ -2334,7 +2336,7 @@ EventResult FakeVimHandler::Private::handleCommandMode(const Input &input)
// FIXME: this should use the "scroll" option, and "count" // FIXME: this should use the "scroll" option, and "count"
moveUp(linesOnScreen() / 2); moveUp(linesOnScreen() / 2);
handleStartOfLine(); handleStartOfLine();
scrollToLineInDocument(cursorLineInDocument() - sline); scrollToLine(cursorLine() - sline);
finishMovement(); finishMovement();
} else if (input.is('v')) { } else if (input.is('v')) {
enterVisualMode(VisualCharMode); enterVisualMode(VisualCharMode);
...@@ -2472,12 +2474,12 @@ EventResult FakeVimHandler::Private::handleCommandMode(const Input &input) ...@@ -2472,12 +2474,12 @@ EventResult FakeVimHandler::Private::handleCommandMode(const Input &input)
finishMovement(); finishMovement();
} else if (input.isKey(Key_PageDown) || input.isControl('f')) { } else if (input.isKey(Key_PageDown) || input.isControl('f')) {
moveDown(count() * (linesOnScreen() - 2) - cursorLineOnScreen()); moveDown(count() * (linesOnScreen() - 2) - cursorLineOnScreen());
scrollToLineInDocument(cursorLineInDocument()); scrollToLine(cursorLine());
handleStartOfLine(); handleStartOfLine();
finishMovement(); finishMovement();
} else if (input.isKey(Key_PageUp) || input.isControl('b')) { } else if (input.isKey(Key_PageUp) || input.isControl('b')) {
moveUp(count() * (linesOnScreen() - 2) + cursorLineOnScreen()); moveUp(count() * (linesOnScreen() - 2) + cursorLineOnScreen());
scrollToLineInDocument(cursorLineInDocument() + linesOnScreen() - 2); scrollToLine(cursorLine() + linesOnScreen() - 2);
handleStartOfLine(); handleStartOfLine();
finishMovement(); finishMovement();
} else if (input.isKey(Key_Delete)) { } else if (input.isKey(Key_Delete)) {
...@@ -2615,8 +2617,8 @@ EventResult FakeVimHandler::Private::handleInsertMode(const Input &input) ...@@ -2615,8 +2617,8 @@ EventResult FakeVimHandler::Private::handleInsertMode(const Input &input)
joinPreviousEditBlock(); joinPreviousEditBlock();
m_justAutoIndented = 0; m_justAutoIndented = 0;
if (!m_lastInsertion.isEmpty() || hasConfig(ConfigBackspace, "start")) { if (!m_lastInsertion.isEmpty() || hasConfig(ConfigBackspace, "start")) {
const int line = cursorLineInDocument() + 1; const int line = cursorLine() + 1;
const Column col = cursorColumnInDocument(); const Column col = cursorColumn();
QString data = lineContents(line); QString data = lineContents(line);
const Column ind = indentation(data); const Column ind = indentation(data);
if (col.logical <= ind.logical && col.logical if (col.logical <= ind.logical && col.logical
...@@ -2650,7 +2652,7 @@ EventResult FakeVimHandler::Private::handleInsertMode(const Input &input) ...@@ -2650,7 +2652,7 @@ EventResult FakeVimHandler::Private::handleInsertMode(const Input &input)
} else if (input.isKey(Key_Tab) && hasConfig(ConfigExpandTab)) { } else if (input.isKey(Key_Tab) && hasConfig(ConfigExpandTab)) {
m_justAutoIndented = 0; m_justAutoIndented = 0;
const int ts = config(ConfigTabStop).toInt(); const int ts = config(ConfigTabStop).toInt();
const int col = logicalCursorColumnInDocument(); const int col = logicalCursorColumn();
QString str = QString(ts - col % ts, ' '); QString str = QString(ts - col % ts, ' ');
m_lastInsertion.append(str); m_lastInsertion.append(str);
insertText(str); insertText(str);
...@@ -2659,7 +2661,7 @@ EventResult FakeVimHandler::Private::handleInsertMode(const Input &input) ...@@ -2659,7 +2661,7 @@ EventResult FakeVimHandler::Private::handleInsertMode(const Input &input)
// remove one level of indentation from the current line // remove one level of indentation from the current line
int shift = config(ConfigShiftWidth).toInt(); int shift = config(ConfigShiftWidth).toInt();
int tab = config(ConfigTabStop).toInt(); int tab = config(ConfigTabStop).toInt();
int line = cursorLineInDocument() + 1; int line = cursorLine() + 1;
int pos = firstPositionInLine(line); int pos = firstPositionInLine(line);
QString text = lineContents(line); QString text = lineContents(line);
int amount = 0; int amount = 0;
...@@ -2840,14 +2842,14 @@ int FakeVimHandler::Private::readLineCode(QString &cmd) ...@@ -2840,14 +2842,14 @@ int FakeVimHandler::Private::readLineCode(QString &cmd)
cmd = cmd.mid(1); cmd = cmd.mid(1);
if (c == '.') { if (c == '.') {
if (cmd.isEmpty()) if (cmd.isEmpty())
return cursorLineInDocument() + 1; return cursorLine() + 1;
QChar c1 = cmd.at(0); QChar c1 = cmd.at(0);
if (c1 == '+' || c1 == '-') { if (c1 == '+' || c1 == '-') {
// Repeat for things like .+4 // Repeat for things like .+4
cmd = cmd.mid(1); cmd = cmd.mid(1);
return cursorLineInDocument() + readLineCode(cmd); return cursorLine() + readLineCode(cmd);
} }
return cursorLineInDocument() + 1; return cursorLine() + 1;
} }
if (c == '$') if (c == '$')
return linesInDocument(); return linesInDocument();
...@@ -2867,11 +2869,11 @@ int FakeVimHandler::Private::readLineCode(QString &cmd) ...@@ -2867,11 +2869,11 @@ int FakeVimHandler::Private::readLineCode(QString &cmd)
} }
if (c == '-') { if (c == '-') {
int n = readLineCode(cmd); int n = readLineCode(cmd);
return cursorLineInDocument() + 1 - (n == -1 ? 1 : n); return cursorLine() + 1 - (n == -1 ? 1 : n);
} }
if (c == '+') { if (c == '+') {
int n = readLineCode(cmd); int n = readLineCode(cmd);
return cursorLineInDocument() + 1 + (n == -1 ? 1 : n); return cursorLine() + 1 + (n == -1 ? 1 : n);
} }
if (c == '\'' && !cmd.isEmpty()) { if (c == '\'' && !cmd.isEmpty()) {
int pos = mark(cmd.at(0).unicode()); int pos = mark(cmd.at(0).unicode());
...@@ -3470,7 +3472,7 @@ void FakeVimHandler::Private::search(const SearchData &sd) ...@@ -3470,7 +3472,7 @@ void FakeVimHandler::Private::search(const SearchData &sd)
QString needle = sd.needle; QString needle = sd.needle;
vimPatternToQtPattern(&needle, &flags); vimPatternToQtPattern(&needle, &flags);
const int oldLine = cursorLineInDocument() - cursorLineOnScreen(); const int oldLine = cursorLine() - cursorLineOnScreen();
int startPos = position(); int startPos = position();
if (sd.mustMove) if (sd.mustMove)
...@@ -3504,8 +3506,8 @@ void FakeVimHandler::Private::search(const SearchData &sd) ...@@ -3504,8 +3506,8 @@ void FakeVimHandler::Private::search(const SearchData &sd)
EDITOR(setTextCursor(m_tc)); EDITOR(setTextCursor(m_tc));
// Making this unconditional feels better, but is not "vim like". // Making this unconditional feels better, but is not "vim like".
if (oldLine != cursorLineInDocument() - cursorLineOnScreen()) if (oldLine != cursorLine() - cursorLineOnScreen())
scrollToLineInDocument(cursorLineInDocument() - linesOnScreen() / 2); scrollToLine(cursorLine() - linesOnScreen() / 2);
if (incSearch && sd.highlightCursor) { if (incSearch && sd.highlightCursor) {
m_searchCursor = m_tc; m_searchCursor = m_tc;
...@@ -3669,14 +3671,19 @@ void FakeVimHandler::Private::shiftRegionLeft(int repeat) ...@@ -3669,14 +3671,19 @@ void FakeVimHandler::Private::shiftRegionLeft(int repeat)
void FakeVimHandler::Private::moveToTargetColumn() void FakeVimHandler::Private::moveToTargetColumn()
{ {
const QTextBlock &block = m_tc.block(); const QTextBlock &block = m_tc.block();
int col = m_tc.position() - block.position(); //Column column = cursorColumn();
if (col == m_targetColumn && m_targetColumn < block.length() - 2) //int logical = logical
int maxcol = block.length() - 2;
if (m_targetColumn == -1) {
m_tc.setPosition(block.position() + qMax(0, maxcol), MoveAnchor);
return; return;
//qDebug() << "CORRECTING COLUMN FROM: " << col << "TO" << m_targetColumn; }
if (m_targetColumn == -1 || m_targetColumn >= block.length() - 2) int physical = logicalToPhysicalColumn(m_targetColumn, block.text());
m_tc.setPosition(block.position() + qMax(0, block.length() - 2), MoveAnchor); //qDebug() << "CORRECTING COLUMN FROM: " << logical << "TO" << m_targetColumn;
if (physical >= maxcol)
m_tc.setPosition(block.position() + qMax(0, maxcol), MoveAnchor);
else else
m_tc.setPosition(block.position() + m_targetColumn, MoveAnchor); m_tc.setPosition(block.position() + physical, MoveAnchor);
} }
/* if simple is given: /* if simple is given:
...@@ -3878,39 +3885,62 @@ int FakeVimHandler::Private::columnsOnScreen() const ...@@ -3878,39 +3885,62 @@ int FakeVimHandler::Private::columnsOnScreen() const
return EDITOR(width()) / rect.width(); return EDITOR(width()) / rect.width();
} }
int FakeVimHandler::Private::cursorLineInDocument() const int FakeVimHandler::Private::cursorLine() const
{ {
return m_tc.block().blockNumber(); return m_tc.block().blockNumber();
} }
int FakeVimHandler::Private::physicalCursorColumnInDocument() const int FakeVimHandler::Private::physicalCursorColumn() const
{ {
return m_tc.position() - m_tc.block().position(); return m_tc.position() - m_tc.block().position();
} }
int FakeVimHandler::Private::logicalCursorColumnInDocument() const int FakeVimHandler::Private::physicalToLogicalColumn
(const int physical, const QString &line) const
{ {
const int ncols = physicalCursorColumnInDocument();
const QString line = m_tc.block().text();
const int ts = config(ConfigTabStop).toInt(); const int ts = config(ConfigTabStop).toInt();
int physical = 0; int p = 0;
int logical = 0; int logical = 0;
while (physical < ncols) { while (p < physical) {
QChar c = line.at(physical); QChar c = line.at(p);
if (c == QLatin1Char(' ')) //if (c == QLatin1Char(' '))
++logical; // ++logical;
else if (c == QLatin1Char('\t')) //else
if (c == QLatin1Char('\t'))
logical += ts - logical % ts; logical += ts - logical % ts;
else else
break; ++logical;
++physical; //break;
++p;
} }
return logical; return logical;
} }
Column FakeVimHandler::Private::cursorColumnInDocument() const int FakeVimHandler::Private::logicalToPhysicalColumn
(const int logical, const QString &line) const
{
const int ts = config(ConfigTabStop).toInt();
int physical = 0;
for (int l = 0; l < logical && physical < line.size(); ++physical) {
QChar c = line.at(physical);
if (c == QLatin1Char('\t'))
l += ts - l % ts;
else
++l;
}
return physical;
}
int FakeVimHandler::Private::logicalCursorColumn() const
{
const int physical = physicalCursorColumn();
const QString line = m_tc.block().text();
return physicalToLogicalColumn(physical, line);
}
Column FakeVimHandler::Private::cursorColumn() const
{ {
return Column(physicalCursorColumnInDocument(), logicalCursorColumnInDocument()); return Column(physicalCursorColumn(), logicalCursorColumn());
} }
int FakeVimHandler::Private::linesInDocument() const int FakeVimHandler::Private::linesInDocument() const
...@@ -3924,30 +3954,30 @@ int FakeVimHandler::Private::linesInDocument() const ...@@ -3924,30 +3954,30 @@ int FakeVimHandler::Private::linesInDocument() const
return doc->lastBlock().length() <= 1 ? count - 1 : count; return doc->lastBlock().length() <= 1 ? count - 1 : count;
} }
void FakeVimHandler::Private::scrollToLineInDocument(int line) void FakeVimHandler::Private::scrollToLine(int line)
{ {
// FIXME: works only for QPlainTextEdit // FIXME: works only for QPlainTextEdit
QScrollBar *scrollBar = EDITOR(verticalScrollBar()); QScrollBar *scrollBar = EDITOR(verticalScrollBar());
//qDebug() << "SCROLL: " << scrollBar->value() << line; //qDebug() << "SCROLL: " << scrollBar->value() << line;
scrollBar->setValue(line); scrollBar->setValue(line);
//QTC_ASSERT(firstVisibleLineInDocument() == line, /**/); //QTC_ASSERT(firstVisibleLine() == line, /**/);
} }
int FakeVimHandler::Private::firstVisibleLineInDocument() const int FakeVimHandler::Private::firstVisibleLine() const
{ {
QScrollBar *scrollBar = EDITOR(verticalScrollBar()); QScrollBar *scrollBar = EDITOR(verticalScrollBar());
if (0 && scrollBar->value() != cursorLineInDocument() - cursorLineOnScreen()) { if (0 && scrollBar->value() != cursorLine() - cursorLineOnScreen()) {
qDebug() << "SCROLLBAR: " << scrollBar->value() qDebug() << "SCROLLBAR: " << scrollBar->value()
<< "CURSORLINE IN DOC" << cursorLineInDocument() << "CURSORLINE IN DOC" << cursorLine()
<< "CURSORLINE ON SCREEN" << cursorLineOnScreen(); << "CURSORLINE ON SCREEN" << cursorLineOnScreen();
} }
//return scrollBar->value(); //return scrollBar->value();
return cursorLineInDocument() - cursorLineOnScreen(); return cursorLine() - cursorLineOnScreen();
} }
void FakeVimHandler::Private::scrollUp(int count) void FakeVimHandler::Private::scrollUp(int count)
{ {
scrollToLineInDocument(cursorLineInDocument() - cursorLineOnScreen() - count); scrollToLine(cursorLine() - cursorLineOnScreen() - count);
} }
int FakeVimHandler::Private::lastPositionInDocument() const int FakeVimHandler::Private::lastPositionInDocument() const
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment