fakevim: improve some basic tab/space/indentation handling

This commit is contained in:
hjk
2009-12-11 13:24:53 +01:00
parent 66db60e0fe
commit c7850c3f98
4 changed files with 188 additions and 17 deletions

View File

@@ -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