Commit c7850c3f authored by hjk's avatar hjk
Browse files

fakevim: improve some basic tab/space/indentation handling

parent 66db60e0
......@@ -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"));
......
......@@ -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
......@@ -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;
};
......
......@@ -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
......
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