forked from qt-creator/qt-creator
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:
@@ -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;
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user