fakevim: Improve Ex command handling

Multi-line commands (lines starting with backslash).

Subcommands separated by bar character (|).

Task-number: QTCREATORBUG-7376
Change-Id: I947b10ee5043824278c6ba71e8ebb19dc5787328
Reviewed-by: hjk <qthjk@ovi.com>
This commit is contained in:
Lukas Holecek
2012-09-29 19:09:08 +02:00
committed by hjk
parent da31e05af0
commit 6268f943d0
4 changed files with 98 additions and 28 deletions

View File

@@ -700,6 +700,24 @@ void FakeVimPlugin::test_vim_undo_redo()
KEYS("u", "abc" N " " X "def" N "ghi"); KEYS("u", "abc" N " " X "def" N "ghi");
} }
void FakeVimPlugin::test_advanced_commands()
{
// TODO: Fix undo/redo position for substitute command.
TestData data;
setup(&data);
// subcommands
data.setText("abc" N " xxx" N "def");
COMMAND("%s/xxx/ZZZ/g|%s/ZZZ/OOO/g", "abc" N " OOO" N "def");
// undo/redo all subcommands
COMMAND(":undo", "abc" N " xxx" N "def");
COMMAND(":redo", "abc" N " OOO" N "def");
// redundant characters
COMMAND("::: %s/\\S\\S\\S/ZZZ/g | :::: %s/ZZZ/XXX/g ", "XXX" N " XXX" N "XXX");
}
void FakeVimPlugin::test_map() void FakeVimPlugin::test_map()
{ {
TestData data; TestData data;

View File

@@ -477,13 +477,32 @@ bool ExCommand::matches(const QString &min, const QString &full) const
void ExCommand::setContentsFromLine(const QString &line) void ExCommand::setContentsFromLine(const QString &line)
{ {
cmd = line.section(' ', 0, 0); // split command to subcommands
args = line.mid(cmd.size() + 1).trimmed(); subCommands = line.split('|');
while (cmd.startsWith(QLatin1Char(':'))) }
cmd.remove(0, 1);
hasBang = cmd.endsWith('!'); bool ExCommand::nextSubcommand()
if (hasBang) {
cmd.chop(1); cmd.clear();
while (cmd.isEmpty() && !subCommands.isEmpty()) {
cmd = subCommands.takeFirst().trimmed();
cmd.remove(QRegExp("^:+\\s*")); // remove leading colons
hasBang = cmd.endsWith('!');
if (hasBang)
cmd.chop(1);
// command arguments
args = cmd.section(QRegExp("\\s+"), 1);
if (!args.isEmpty())
cmd = cmd.left(cmd.size() - args.size()).trimmed();
}
return !cmd.isEmpty();
}
QString ExCommand::printCommand() const
{
return subCommands.isEmpty() ? cmd : cmd + "|" + subCommands.join("|");
} }
QDebug operator<<(QDebug ts, const ExCommand &cmd) QDebug operator<<(QDebug ts, const ExCommand &cmd)
@@ -1489,7 +1508,7 @@ public:
QTextCursor m_lastSelectionCursor; QTextCursor m_lastSelectionCursor;
VisualMode m_lastSelectionMode; VisualMode m_lastSelectionMode;
bool handleExCommandHelper(const ExCommand &cmd); // Returns success. bool handleExCommandHelper(ExCommand &cmd); // Returns success.
bool handleExPluginCommand(const ExCommand &cmd); // Handled by plugin? bool handleExPluginCommand(const ExCommand &cmd); // Handled by plugin?
bool handleExBangCommand(const ExCommand &cmd); bool handleExBangCommand(const ExCommand &cmd);
bool handleExDeleteCommand(const ExCommand &cmd); bool handleExDeleteCommand(const ExCommand &cmd);
@@ -4443,25 +4462,39 @@ bool FakeVimHandler::Private::handleExSourceCommand(const ExCommand &cmd)
} }
bool inFunction = false; bool inFunction = false;
while (!file.atEnd()) { QByteArray line;
QByteArray line = file.readLine(); while (!file.atEnd() || !line.isEmpty()) {
line = line.trimmed(); QByteArray nextline = !file.atEnd() ? file.readLine() : QByteArray();
// remove comment
int i = nextline.lastIndexOf('"');
if (i != -1)
nextline = nextline.remove(i, nextline.size() - i);
nextline = nextline.trimmed();
// multi-line command?
if (nextline.startsWith('\\')) {
line += nextline.mid(1);
continue;
}
if (line.startsWith("function")) { if (line.startsWith("function")) {
//qDebug() << "IGNORING FUNCTION" << line; //qDebug() << "IGNORING FUNCTION" << line;
inFunction = true; inFunction = true;
} else if (inFunction && line.startsWith("endfunction")) { } else if (inFunction && line.startsWith("endfunction")) {
inFunction = false; inFunction = false;
} else if (line.startsWith("function")) {
//qDebug() << "IGNORING FUNCTION" << line;
inFunction = true;
} else if (line.startsWith('"')) {
// A comment.
} else if (!line.isEmpty() && !inFunction) { } else if (!line.isEmpty() && !inFunction) {
//qDebug() << "EXECUTING: " << line; //qDebug() << "EXECUTING: " << line;
ExCommand cmd; ExCommand cmd;
cmd.setContentsFromLine(QString::fromLocal8Bit(line)); cmd.setContentsFromLine(QString::fromLocal8Bit(line));
handleExCommandHelper(cmd); while (cmd.nextSubcommand()) {
if (!handleExCommandHelper(cmd))
break;
}
} }
line = nextline;
} }
file.close(); file.close();
return true; return true;
@@ -4488,9 +4521,31 @@ void FakeVimHandler::Private::handleExCommand(const QString &line0)
return; return;
} }
ExCommand cmd;
cmd.setContentsFromLine(line);
//qDebug() << "CMD: " << cmd;
beginEditBlock();
while (cmd.nextSubcommand()) {
if (!handleExCommandHelper(cmd)) {
showMessage(MessageError,
tr("Not an editor command: %1").arg(cmd.printCommand()));
break;
}
}
endEditBlock();
enterCommandMode();
}
bool FakeVimHandler::Private::handleExCommandHelper(ExCommand &cmd)
{
// parse range first
QString &line = cmd.cmd;
// FIXME: that seems to be different for %w and %s // FIXME: that seems to be different for %w and %s
if (line.startsWith(QLatin1Char('%'))) if (line.startsWith(QLatin1Char('%')))
line = "1,$" + line.mid(1); line.replace(0, 1, "1,$");
const int beginLine = readLineCode(line); const int beginLine = readLineCode(line);
int endLine = -1; int endLine = -1;
@@ -4500,23 +4555,13 @@ void FakeVimHandler::Private::handleExCommand(const QString &line0)
} }
if (beginLine != -1 && endLine == -1) if (beginLine != -1 && endLine == -1)
endLine = beginLine; endLine = beginLine;
ExCommand cmd;
cmd.setContentsFromLine(line);
if (beginLine != -1) { if (beginLine != -1) {
const int beginPos = firstPositionInLine(beginLine); const int beginPos = firstPositionInLine(beginLine);
const int endPos = lastPositionInLine(endLine); const int endPos = lastPositionInLine(endLine);
cmd.range = Range(beginPos, endPos, RangeLineMode); cmd.range = Range(beginPos, endPos, RangeLineMode);
cmd.count = beginLine; cmd.count = beginLine;
} }
//qDebug() << "CMD: " << cmd;
if (!handleExCommandHelper(cmd))
showMessage(MessageError, tr("Not an editor command: %1").arg(cmd.cmd));
enterCommandMode();
}
bool FakeVimHandler::Private::handleExCommandHelper(const ExCommand &cmd)
{
return handleExPluginCommand(cmd) return handleExPluginCommand(cmd)
|| handleExGotoCommand(cmd) || handleExGotoCommand(cmd)
|| handleExBangCommand(cmd) || handleExBangCommand(cmd)

View File

@@ -70,7 +70,13 @@ struct ExCommand
bool matches(const QString &min, const QString &full) const; bool matches(const QString &min, const QString &full) const;
void setContentsFromLine(const QString &line); void setContentsFromLine(const QString &line);
// set cmd to next subcommand and return false only if no subcommand is left
bool nextSubcommand();
QString printCommand() const;
QString cmd; QString cmd;
QStringList subCommands;
bool hasBang; bool hasBang;
QString args; QString args;
Range range; Range range;

View File

@@ -73,6 +73,7 @@ private slots:
void test_vim_marks(); void test_vim_marks();
void test_vim_copy_paste(); void test_vim_copy_paste();
void test_vim_undo_redo(); void test_vim_undo_redo();
void test_advanced_commands();
void test_map(); void test_map();
#endif #endif
}; };