fakevim: Added move and yank Ex commands

Change-Id: I4138a2035e338b665d91704b7c53117c4d924472
Reviewed-by: hjk <qthjk@ovi.com>
This commit is contained in:
Lukas Holecek
2012-10-23 16:35:13 +02:00
committed by hjk
parent bddec831d8
commit 8994bb2d4a
3 changed files with 173 additions and 49 deletions

View File

@@ -1321,6 +1321,49 @@ void FakeVimPlugin::test_vim_substitute()
COMMAND("%s/\\( \\S \\)*//g", "abc" N "def" N X "ghi"); COMMAND("%s/\\( \\S \\)*//g", "abc" N "def" N X "ghi");
} }
void FakeVimPlugin::test_vim_yank()
{
TestData data;
setup(&data);
data.setText("abc" N "def");
COMMAND("y x", X "abc" N "def");
KEYS("\"xp", "abc" N X "abc" N "def");
COMMAND("u", X "abc" N "def");
COMMAND("redo", X "abc" N "abc" N "def");
KEYS("uw", "abc" N X "def");
COMMAND("1y y", "abc" N X "def");
KEYS("\"yP", "abc" N X "abc" N "def");
COMMAND("u", "abc" N X "def");
COMMAND("-1,$y x", "abc" N X "def");
KEYS("\"xP", "abc" N X "abc" N "def" N "def");
COMMAND("u", "abc" N X "def");
COMMAND("$-1y", "abc" N X "def");
KEYS("P", "abc" N X "abc" N "def");
COMMAND("u", "abc" N X "def");
}
void FakeVimPlugin::test_vim_move()
{
TestData data;
setup(&data);
data.setText("abc" N "def" N "ghi" N "jkl");
COMMAND("m +1", "def" N X "abc" N "ghi" N "jkl");
COMMAND("u", X "abc" N "def" N "ghi" N "jkl");
COMMAND("redo", X "def" N "abc" N "ghi" N "jkl");
COMMAND("m -2", X "def" N "abc" N "ghi" N "jkl");
COMMAND("2m0", X "abc" N "def" N "ghi" N "jkl");
COMMAND("m $-2", "def" N X "abc" N "ghi" N "jkl");
KEYS("`'", X "def" N "abc" N "ghi" N "jkl");
KEYS("Vj:m+2<cr>", "ghi" N "def" N X "abc" N "jkl");
KEYS("u", X "def" N "abc" N "ghi" N "jkl");
}
void FakeVimPlugin::test_advanced_commands() void FakeVimPlugin::test_advanced_commands()
{ {
TestData data; TestData data;

View File

@@ -708,14 +708,14 @@ public:
bool operator==(const Input &a) const bool operator==(const Input &a) const
{ {
return m_key == a.m_key && m_modifiers == a.m_modifiers && m_text == a.m_text; return m_key == a.m_key && m_modifiers == a.m_modifiers;
} }
bool operator!=(const Input &a) const { return !operator==(a); } bool operator!=(const Input &a) const { return !operator==(a); }
bool operator<(const Input &a) const bool operator<(const Input &a) const
{ {
return m_key < a.m_key || m_modifiers < a.m_modifiers || m_text < a.m_text; return m_key < a.m_key || m_modifiers < a.m_modifiers;
} }
QString text() const { return m_text; } QString text() const { return m_text; }
@@ -1284,7 +1284,7 @@ public:
// The following use all zero-based counting. // The following use all zero-based counting.
int cursorLineOnScreen() const; int cursorLineOnScreen() const;
int cursorLine() const; int cursorLine() const;
int cursorBlockNumber() const; int cursorBlockNumber() const; // "." address
int physicalCursorColumn() const; // as stored in the data int physicalCursorColumn() const; // as stored in the data
int logicalCursorColumn() const; // as visible on screen int logicalCursorColumn() const; // as visible on screen
int physicalToLogicalColumn(int physical, const QString &text) const; int physicalToLogicalColumn(int physical, const QString &text) const;
@@ -1583,6 +1583,8 @@ public:
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);
bool handleExYankCommand(const ExCommand &cmd);
bool handleExMoveCommand(const ExCommand &cmd);
bool handleExGotoCommand(const ExCommand &cmd); bool handleExGotoCommand(const ExCommand &cmd);
bool handleExHistoryCommand(const ExCommand &cmd); bool handleExHistoryCommand(const ExCommand &cmd);
bool handleExRegisterCommand(const ExCommand &cmd); bool handleExRegisterCommand(const ExCommand &cmd);
@@ -4019,22 +4021,17 @@ int FakeVimHandler::Private::readLineCode(QString &cmd)
//qDebug() << "CMD: " << cmd; //qDebug() << "CMD: " << cmd;
if (cmd.isEmpty()) if (cmd.isEmpty())
return -1; return -1;
QChar c = cmd.at(0);
cmd = cmd.mid(1); int result = -1;
if (c == '.') { const QChar &c = cmd[0];
if (cmd.isEmpty()) if (c == '.') { // current line
return cursorBlockNumber(); result = cursorBlockNumber();
QChar c1 = cmd.at(0); cmd.remove(0, 1);
if (c1 == '+' || c1 == '-') { } else if (c == '$') { // last line
// Repeat for things like .+4 result = document()->blockCount() - 1;
cmd = cmd.mid(1); cmd.remove(0, 1);
return cursorBlockNumber() + readLineCode(cmd); } else if (c == '\'') { // mark
} cmd.remove(0, 1);
return cursorBlockNumber();
}
if (c == '$')
return document()->blockCount() - 1;
if (c == '\'' && !cmd.isEmpty()) {
if (cmd.isEmpty()) { if (cmd.isEmpty()) {
showMessage(MessageError, msgMarkNotSet(QString())); showMessage(MessageError, msgMarkNotSet(QString()));
return -1; return -1;
@@ -4042,35 +4039,42 @@ int FakeVimHandler::Private::readLineCode(QString &cmd)
CursorPosition m = mark(cmd.at(0).unicode()); CursorPosition m = mark(cmd.at(0).unicode());
if (!m.isValid()) { if (!m.isValid()) {
showMessage(MessageError, msgMarkNotSet(cmd.at(0))); showMessage(MessageError, msgMarkNotSet(cmd.at(0)));
cmd = cmd.mid(1);
return -1; return -1;
} }
cmd = cmd.mid(1); cmd.remove(0, 1);
return m.line; result = m.line;
} else if (c.isDigit()) { // line with given number
result = 0;
} else if (c == '-' || c == '+') { // add or subtract from current line number
result = cursorBlockNumber();
} else {
return -1;
} }
if (c == '-') { // FIXME: /.../ ?...? \/ \? \&
int n = readLineCode(cmd);
return cursorBlockNumber() - (n == -1 ? 1 : n); // basic arithmetic ("-3+5" or "++" means "+2" etc.)
} int n = 0;
if (c == '+') { bool add = true;
int n = readLineCode(cmd); int i = 0;
return cursorBlockNumber() + (n == -1 ? 1 : n); for (; i < cmd.size(); ++i) {
} const QChar &c = cmd[i];
if (c.isDigit()) { if (c == '-' || c == '+') {
int n = c.unicode() - '0'; if (n != 0)
while (!cmd.isEmpty()) { result = result + (add ? n - 1 : -(n - 1));
c = cmd.at(0); add = c == '+';
if (!c.isDigit()) result = result + (add ? 1 : -1);
n = 0;
} else if (c.isDigit()) {
n = n * 10 + c.digitValue();
} else if (!c.isSpace()) {
break; break;
cmd = cmd.mid(1);
n = n * 10 + (c.unicode() - '0');
} }
//qDebug() << "N: " << n;
return n - 1;
} }
// Parsing failed. if (n != 0)
cmd = c + cmd; result = result + (add ? n - 1 : -(n - 1));
return -1; cmd.remove(0, i);
return result;
} }
void FakeVimHandler::Private::setCurrentRange(const Range &range) void FakeVimHandler::Private::setCurrentRange(const Range &range)
@@ -4085,6 +4089,7 @@ Range FakeVimHandler::Private::rangeFromCurrentLine() const
QTextBlock block = cursor().block(); QTextBlock block = cursor().block();
range.beginPos = block.position(); range.beginPos = block.position();
range.endPos = range.beginPos + block.length() - 1; range.endPos = range.beginPos + block.length() - 1;
range.rangemode = RangeLineMode;
return range; return range;
} }
@@ -4410,7 +4415,7 @@ bool FakeVimHandler::Private::handleExDeleteCommand(const ExCommand &cmd)
if (!cmd.matches("d", "delete")) if (!cmd.matches("d", "delete"))
return false; return false;
Range range = cmd.range.endPos == 0 ? rangeFromCurrentLine() : cmd.range; Range range = cmd.range.endPos <= 0 ? rangeFromCurrentLine() : cmd.range;
setCurrentRange(range); setCurrentRange(range);
QString reg = cmd.args; QString reg = cmd.args;
QString text = selectText(range); QString text = selectText(range);
@@ -4422,6 +4427,69 @@ bool FakeVimHandler::Private::handleExDeleteCommand(const ExCommand &cmd)
return true; return true;
} }
bool FakeVimHandler::Private::handleExYankCommand(const ExCommand &cmd)
{
// :[range]y[ank] [x]
if (!cmd.matches("y", "yank"))
return false;
Range range = cmd.range.endPos <= 0 ? rangeFromCurrentLine() : cmd.range;
const int r = cmd.args.isEmpty() ? m_register : cmd.args.at(0).unicode();
yankText(range, r);
return true;
}
bool FakeVimHandler::Private::handleExMoveCommand(const ExCommand &cmd)
{
// :[range]m[ove] {address}
QRegExp re("^m(?=ove)?([\\d+-$%./'\\\\?].*|$)"); // address can follow immediately
if (re.indexIn(cmd.cmd) == -1)
return false;
QString lineCode = re.cap(1) + cmd.args;
Range range = cmd.range.endPos <= 0 ? rangeFromCurrentLine() : cmd.range;
const int startLine = document()->findBlock(range.beginPos).blockNumber();
const int endLine = document()->findBlock(range.endPos).blockNumber();
const int lines = endLine - startLine + 1;
const int line = lineCode == "0" ? -1 : readLineCode(lineCode);
if (line >= startLine && line < endLine) {
showMessage(MessageError, FakeVimHandler::tr("Move lines into themselves"));
return true;
}
setUndoPosition();
recordJump();
setCurrentRange(range);
QString text = selectText(range);
removeText(currentRange());
bool insertAtEnd = line == document()->blockCount();
const int targetLine = (line < startLine) ? line : line - lines;
QTextBlock block = document()->findBlockByNumber(insertAtEnd ? targetLine : targetLine + 1);
int pos = block.position();
setAnchorAndPosition(pos, pos);
if (insertAtEnd) {
moveToEndOfLine();
insertText(QString('\n'));
}
insertText(text);
if (insertAtEnd)
cursor().deleteChar();
moveUp(1);
if (hasConfig(ConfigStartOfLine))
moveToFirstNonBlankOnLine();
if (lines > 2)
showMessage(MessageInfo, FakeVimHandler::tr("%1 lines moved").arg(lines));
return true;
}
bool FakeVimHandler::Private::handleExWriteCommand(const ExCommand &cmd) bool FakeVimHandler::Private::handleExWriteCommand(const ExCommand &cmd)
{ {
// :w, :x, :wq, ... // :w, :x, :wq, ...
@@ -4703,7 +4771,7 @@ bool FakeVimHandler::Private::handleExCommandHelper(ExCommand &cmd)
if (line.startsWith(QLatin1Char('%'))) if (line.startsWith(QLatin1Char('%')))
line.replace(0, 1, "1,$"); line.replace(0, 1, "1,$");
const int beginLine = readLineCode(line); int beginLine = readLineCode(line);
int endLine = -1; int endLine = -1;
if (line.startsWith(',')) { if (line.startsWith(',')) {
line = line.mid(1); line = line.mid(1);
@@ -4724,6 +4792,8 @@ bool FakeVimHandler::Private::handleExCommandHelper(ExCommand &cmd)
|| handleExHistoryCommand(cmd) || handleExHistoryCommand(cmd)
|| handleExRegisterCommand(cmd) || handleExRegisterCommand(cmd)
|| handleExDeleteCommand(cmd) || handleExDeleteCommand(cmd)
|| handleExYankCommand(cmd)
|| handleExMoveCommand(cmd)
|| handleExMapCommand(cmd) || handleExMapCommand(cmd)
|| handleExNohlsearchCommand(cmd) || handleExNohlsearchCommand(cmd)
|| handleExNormalCommand(cmd) || handleExNormalCommand(cmd)
@@ -5236,7 +5306,7 @@ int FakeVimHandler::Private::cursorLine() const
int FakeVimHandler::Private::cursorBlockNumber() const int FakeVimHandler::Private::cursorBlockNumber() const
{ {
return cursor().block().blockNumber(); return document()->findBlock(qMin(anchor(), position())).blockNumber();
} }
int FakeVimHandler::Private::physicalCursorColumn() const int FakeVimHandler::Private::physicalCursorColumn() const
@@ -5423,6 +5493,11 @@ QString FakeVimHandler::Private::selectText(const Range &range) const
void FakeVimHandler::Private::yankText(const Range &range, int reg) void FakeVimHandler::Private::yankText(const Range &range, int reg)
{ {
setRegister(reg, selectText(range), range.rangemode); setRegister(reg, selectText(range), range.rangemode);
const int lines = document()->findBlock(range.endPos).blockNumber()
- document()->findBlock(range.beginPos).blockNumber() + 1;
if (lines > 2)
showMessage(MessageInfo, FakeVimHandler::tr("%1 lines yanked").arg(lines));
} }
void FakeVimHandler::Private::transformText(const Range &range, void FakeVimHandler::Private::transformText(const Range &range,
@@ -6381,13 +6456,17 @@ void FakeVimHandler::Private::setRegister(int reg, const QString &contents, Rang
bool copyToSelection; bool copyToSelection;
getRegisterType(reg, &copyToClipboard, &copyToSelection); getRegisterType(reg, &copyToClipboard, &copyToSelection);
QString contents2 = contents;
if (mode == RangeLineMode && !contents2.endsWith('\n'))
contents2.append('\n');
if (copyToClipboard || copyToSelection) { if (copyToClipboard || copyToSelection) {
if (copyToClipboard) if (copyToClipboard)
setClipboardData(contents, mode, QClipboard::Clipboard); setClipboardData(contents2, mode, QClipboard::Clipboard);
if (copyToSelection) if (copyToSelection)
setClipboardData(contents, mode, QClipboard::Selection); setClipboardData(contents2, mode, QClipboard::Selection);
} else { } else {
g.registers[reg].contents = contents; g.registers[reg].contents = contents2;
g.registers[reg].rangemode = mode; g.registers[reg].rangemode = mode;
} }
} }

View File

@@ -81,6 +81,8 @@ private slots:
void test_vim_code_autoindent(); void test_vim_code_autoindent();
void test_vim_code_folding(); void test_vim_code_folding();
void test_vim_substitute(); void test_vim_substitute();
void test_vim_yank();
void test_vim_move();
void test_advanced_commands(); void test_advanced_commands();
void test_map(); void test_map();