Files
qt-creator/src/plugins/fakevim/fakevim_test.cpp
hluk 1bea9b98fb FakeVim: Option 'passcharacters' (not in Vim)
Option to pass some key presses in insert mode to editor widget
(replaces 'passnewline'). This allows to rename symbols in insert mode,
complete parenthesis blocks, expand comments etc.

Macro expansion and code-completion works with dot command.

Task-number:QTCREATORBUG-4828
Change-Id: I5ff43818d4f7f183cd6f4ed8cc3a4586469ab65d
Reviewed-by: hjk <hjk121@nokiamail.com>
2013-04-04 13:50:08 +02:00

2951 lines
93 KiB
C++

/**************************************************************************
**
** Copyright (C) 2013 Lukas Holecek <hluk@email.cz>
** Contact: http://www.qt-project.org/legal
**
** This file is part of Qt Creator.
**
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia. For licensing terms and
** conditions see http://qt.digia.com/licensing. For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file. Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights. These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
****************************************************************************/
/*!
* Tests for FakeVim plugin.
* All test are based on Vim behaviour.
*/
#include "fakevimplugin.h"
#include "fakevimhandler.h"
#include <coreplugin/editormanager/editormanager.h>
#include <texteditor/basetexteditor.h>
#include <QtTest>
#include <QTextEdit>
#include <QTextDocument>
#include <QTextBlock>
//TESTED_COMPONENT=src/plugins/fakevim
/*!
* Tests after this macro will be skipped and warning printed.
* Uncomment it to test a feature -- if tests succeeds it should be removed from the test.
*/
#if QT_VERSION < QT_VERSION_CHECK(5, 0, 0)
# define NOT_IMPLEMENTED QSKIP("Not fully implemented!", SkipSingle);
#else
# define NOT_IMPLEMENTED QSKIP("Not fully implemented!");
#endif
// Text cursor representation in comparisons.
#define X "|"
// More distinct line separator in code.
#define N "\n"
// Document line start and end string in error text.
#define LINE_START "\t\t<"
#define LINE_END ">\n"
QString _(const char *c) { return QLatin1String(c); }
QString _(const QByteArray &c) { return QLatin1String(c); }
QString _(const QString &c) { return c; }
// Format of message after comparison fails (used by KEYS, COMMAND).
static const QString helpFormat = _(
"\n\tBefore command [%1]:\n" \
LINE_START "%2" LINE_END \
"\n\tAfter the command:\n" \
LINE_START "%3" LINE_END \
"\n\tShould be:\n" \
LINE_START "%4" LINE_END);
// Compare document contents with a expectedText.
// Also check cursor position if the expectedText contains | chracter.
#define COMPARE(beforeText, beforePosition, afterText, afterPosition, expectedText, cmd) \
do { \
QByteArray before(beforeText); \
QByteArray actual(afterText); \
QByteArray expected = expectedText; \
data.oldPosition = beforePosition; \
data.oldText = before; \
if (expected.contains(X)) {\
before = textWithCursor(before, beforePosition); \
actual = textWithCursor(actual, afterPosition); \
} \
QString help = helpFormat \
.arg(_(cmd)) \
.arg(_(before.replace('\n', LINE_END LINE_START))) \
.arg(_(actual.replace('\n', LINE_END LINE_START))) \
.arg(_(expected.replace('\n', LINE_END LINE_START))); \
QVERIFY2(actual == expected, help.toLatin1().constData()); \
} while (false)
// Send keys and check if the expected result is same as document contents.
// Escape is always prepended to keys so that previous command is cancelled.
#define KEYS(keys, expected) \
do { \
QByteArray beforeText(data.text()); \
int beforePosition = data.position(); \
data.doKeys("<ESC>"); \
data.doKeys(keys); \
COMPARE(beforeText, beforePosition, data.text(), data.position(), (expected), (keys)); \
} while (false)
// Run Ex command and check if the expected result is same as document contents.
#define COMMAND(cmd, expected) \
do { \
QByteArray beforeText(data.text()); \
int beforePosition = data.position(); \
data.doCommand(cmd); \
COMPARE(beforeText, beforePosition, data.text(), data.position(), (expected), (":" cmd)); \
} while (false)
// Test undo, redo and repeat of last single command. This doesn't test cursor position.
// Set afterEnd to true if cursor position after undo and redo differs at the end of line
// (e.g. undoing 'A' operation moves cursor at the end of line and redo moves it one char right).
#define INTEGRITY(afterEnd) \
do { \
data.doKeys("<ESC>"); \
const int newPosition = data.position(); \
const int oldPosition = data.oldPosition; \
const QByteArray redo = data.text(); \
KEYS("u", data.oldText); \
const QTextCursor tc = data.cursor(); \
const int pos = tc.position(); \
const int col = tc.positionInBlock() \
+ ((afterEnd && tc.positionInBlock() + 2 == tc.block().length()) ? 1 : 0); \
const int line = tc.block().blockNumber(); \
const QTextDocument *doc = data.editor()->document(); \
KEYS("<c-r>", textWithCursor(redo, doc->findBlockByNumber(line), col)); \
KEYS("u", textWithCursor(data.oldText, pos)); \
data.setPosition(oldPosition); \
KEYS(".", textWithCursor(redo, newPosition)); \
} while (false)
using namespace FakeVim::Internal;
using namespace TextEditor;
static QByteArray textWithCursor(const QByteArray &text, int position)
{
return (position == -1) ? text : (text.left(position) + X + text.mid(position));
}
static QByteArray textWithCursor(const QByteArray &text, const QTextBlock &block, int column)
{
const int pos = block.position() + qMin(column, qMax(0, block.length() - 2));
return text.left(pos) + X + text.mid(pos);
}
const QByteArray testLines =
/* 0 1 2 3 4 */
/* 0123456789012345678901234567890123457890 */
"\n"
"#include <QtCore>\n"
"#include <QtGui>\n"
"\n"
"int main(int argc, char *argv[])\n"
"{\n"
" QApplication app(argc, argv);\n"
"\n"
" return app.exec();\n"
"}\n";
const QList<QByteArray> l = testLines.split('\n');
static QByteArray bajoin(const QList<QByteArray> &balist)
{
QByteArray res;
for (int i = 0; i < balist.size(); ++i) {
if (i)
res += '\n';
res += balist.at(i);
}
return res;
}
// Insert cursor char at pos, negative counts from back.
static QByteArray cursor(int line, int column)
{
const int col = column >= 0 ? column : l[line].size() + column;
QList<QByteArray> res = l.mid(0, line) << textWithCursor(l[line], col);
res.append(l.mid(line + 1));
return bajoin(res);
}
static QByteArray lmid(int i, int n = -1) { return bajoin(l.mid(i, n)); }
// Data for tests containing BaseTextEditorWidget and FakeVimHAndler.
struct FakeVimPlugin::TestData
{
FakeVimHandler *handler;
QWidget *edit;
QString title;
int oldPosition;
QByteArray oldText;
BaseTextEditorWidget *editor() const { return qobject_cast<BaseTextEditorWidget *>(edit); }
QTextCursor cursor() const { return editor()->textCursor(); }
int position() const
{
return cursor().position();
}
void setPosition(int position)
{
handler->setTextCursorPosition(position);
}
QByteArray text() const { return editor()->toPlainText().toUtf8(); }
void doCommand(const QString &cmd) { handler->handleCommand(cmd); }
void doCommand(const char *cmd) { doCommand(_(cmd)); }
void doKeys(const QString &keys) { handler->handleInput(keys); }
void doKeys(const char *keys) { doKeys(_(keys)); }
void setText(const char *text)
{
doKeys("<ESC>");
QByteArray str = text;
int i = str.indexOf(X);
if (i != -1)
str.remove(i, 1);
else
i = 0;
editor()->document()->setPlainText(_(str));
setPosition(i);
QCOMPARE(position(), i);
}
// Simulate text completion by inserting text directly to editor widget (bypassing FakeVim).
void completeText(const char *text)
{
QTextCursor tc = editor()->textCursor();
tc.insertText(_(text));
editor()->setTextCursor(tc);
}
// Simulate external position change.
void jump(const char *textWithCursorPosition)
{
int pos = QString(_(textWithCursorPosition)).indexOf(_(X));
QTextCursor tc = editor()->textCursor();
tc.setPosition(pos);
editor()->setTextCursor(tc);
QCOMPARE(QByteArray(textWithCursorPosition), textWithCursor(text(), position()));
}
int lines() const
{
QTextDocument *doc = editor()->document();
Q_ASSERT(doc != 0);
return doc->lineCount();
}
// Enter command mode and go to start.
void reset()
{
handler->handleInput(_("<ESC><ESC>gg0"));
}
};
void FakeVimPlugin::setup(TestData *data)
{
setupTest(&data->title, &data->handler, &data->edit);
data->reset();
data->doCommand("set nopasskeys | set nopasscontrolkey");
}
void FakeVimPlugin::cleanup()
{
Core::EditorManager::instance()->closeAllEditors(false);
}
void FakeVimPlugin::test_vim_indentation()
{
TestData data;
setup(&data);
data.doCommand("set expandtab");
data.doCommand("set tabstop=4");
data.doCommand("set shiftwidth=4");
QCOMPARE(data.handler->physicalIndentation(_(" \t\t\tx")), 6 + 3);
QCOMPARE(data.handler->logicalIndentation (_(" \t\t\tx")), 4 + 3 * 4);
QCOMPARE(data.handler->physicalIndentation(_(" \t\t\tx")), 5 + 3);
QCOMPARE(data.handler->logicalIndentation (_(" \t\t\tx")), 4 + 3 * 4);
QCOMPARE(data.handler->tabExpand(3), _(" "));
QCOMPARE(data.handler->tabExpand(4), _(" "));
QCOMPARE(data.handler->tabExpand(5), _(" "));
QCOMPARE(data.handler->tabExpand(6), _(" "));
QCOMPARE(data.handler->tabExpand(7), _(" "));
QCOMPARE(data.handler->tabExpand(8), _(" "));
QCOMPARE(data.handler->tabExpand(9), _(" "));
data.doCommand("set expandtab");
data.doCommand("set tabstop=8");
data.doCommand("set shiftwidth=4");
QCOMPARE(data.handler->physicalIndentation(_(" \t\t\tx")), 6 + 3);
QCOMPARE(data.handler->logicalIndentation (_(" \t\t\tx")), 0 + 3 * 8);
QCOMPARE(data.handler->physicalIndentation(_(" \t\t\tx")), 5 + 3);
QCOMPARE(data.handler->logicalIndentation (_(" \t\t\tx")), 0 + 3 * 8);
QCOMPARE(data.handler->tabExpand(3), _(" "));
QCOMPARE(data.handler->tabExpand(4), _(" "));
QCOMPARE(data.handler->tabExpand(5), _(" "));
QCOMPARE(data.handler->tabExpand(6), _(" "));
QCOMPARE(data.handler->tabExpand(7), _(" "));
QCOMPARE(data.handler->tabExpand(8), _(" "));
QCOMPARE(data.handler->tabExpand(9), _(" "));
data.doCommand("set noexpandtab");
data.doCommand("set tabstop=4");
data.doCommand("set shiftwidth=4");
QCOMPARE(data.handler->physicalIndentation(_(" \t\t\tx")), 6 + 3);
QCOMPARE(data.handler->logicalIndentation (_(" \t\t\tx")), 4 + 3 * 4);
QCOMPARE(data.handler->physicalIndentation(_(" \t\t\tx")), 5 + 3);
QCOMPARE(data.handler->logicalIndentation (_(" \t\t\tx")), 4 + 3 * 4);
QCOMPARE(data.handler->tabExpand(3), _(" "));
QCOMPARE(data.handler->tabExpand(4), _("\t"));
QCOMPARE(data.handler->tabExpand(5), _("\t "));
QCOMPARE(data.handler->tabExpand(6), _("\t "));
QCOMPARE(data.handler->tabExpand(7), _("\t "));
QCOMPARE(data.handler->tabExpand(8), _("\t\t"));
QCOMPARE(data.handler->tabExpand(9), _("\t\t "));
data.doCommand("set noexpandtab");
data.doCommand("set tabstop=8");
data.doCommand("set shiftwidth=4");
QCOMPARE(data.handler->physicalIndentation(_(" \t\t\tx")), 6 + 3);
QCOMPARE(data.handler->logicalIndentation (_(" \t\t\tx")), 0 + 3 * 8);
QCOMPARE(data.handler->physicalIndentation(_(" \t\t\tx")), 5 + 3);
QCOMPARE(data.handler->logicalIndentation (_(" \t\t\tx")), 0 + 3 * 8);
QCOMPARE(data.handler->tabExpand(3), _(" "));
QCOMPARE(data.handler->tabExpand(4), _(" "));
QCOMPARE(data.handler->tabExpand(5), _(" "));
QCOMPARE(data.handler->tabExpand(6), _(" "));
QCOMPARE(data.handler->tabExpand(7), _(" "));
QCOMPARE(data.handler->tabExpand(8), _("\t"));
QCOMPARE(data.handler->tabExpand(9), _("\t "));
}
void FakeVimPlugin::test_vim_movement()
{
TestData data;
setup(&data);
// vertical movement
data.setText("123" N "456" N "789" N "abc");
KEYS("", X "123" N "456" N "789" N "abc");
KEYS("j", "123" N X "456" N "789" N "abc");
KEYS("G", "123" N "456" N "789" N X "abc");
KEYS("k", "123" N "456" N X "789" N "abc");
KEYS("2k", X "123" N "456" N "789" N "abc");
KEYS("k", X "123" N "456" N "789" N "abc");
KEYS("jj", "123" N "456" N X "789" N "abc");
KEYS("gg", X "123" N "456" N "789" N "abc");
// horizontal movement
data.setText(" " X "x" "x" "x" "x");
KEYS("", " " X "x" "x" "x" "x");
KEYS("h", X " " "x" "x" "x" "x");
KEYS("l", " " X "x" "x" "x" "x");
KEYS("3l", " " "x" "x" "x" X "x");
KEYS("2h", " " "x" X "x" "x" "x");
KEYS("$", " " "x" "x" "x" X "x");
KEYS("^", " " X "x" "x" "x" "x");
KEYS("0", X " " "x" "x" "x" "x");
// skip words
data.setText("123 " "456" "." "789 " "abc");
KEYS("b", X "123 " "456" "." "789 " "abc");
KEYS("w", "123 " X "456" "." "789 " "abc");
KEYS("2w", "123 " "456" "." X "789 " "abc");
KEYS("3w", "123 " "456" "." "789 " "ab" X "c");
KEYS("3b", "123 " "456" X "." "789 " "abc");
data.setText("123 " "456.789 " "abc " "def");
KEYS("B", X "123 " "456.789 " "abc " "def");
KEYS("W", "123 " X "456.789 " "abc " "def");
KEYS("2W", "123 " "456.789 " "abc " X "def");
KEYS("B", "123 " "456.789 " X "abc " "def");
KEYS("2B", X "123 " "456.789 " "abc " "def");
KEYS("4W", "123 " "456.789 " "abc " "de" X "f");
data.setText("123" N "45." "6" N "" N " " N "789");
KEYS("3w", "123" N "45." X "6" N "" N " " N "789");
// From Vim help (motion.txt): An empty line is also considered to be a word.
KEYS("w", "123" N "45." "6" N X "" N " " N "789");
KEYS("w", "123" N "45." "6" N "" N " " N X "789");
KEYS("b", "123" N "45." "6" N X "" N " " N "789");
KEYS("4b", X "123" N "45." "6" N "" N " " N "789");
KEYS("3e", "123" N "45" X "." "6" N "" N " " N "789");
KEYS("e", "123" N "45" "." X "6" N "" N " " N "789");
// Command "e" does not stop on empty lines ("ge" does).
KEYS("e", "123" N "45" "." "6" N "" N " " N "78" X "9");
KEYS("ge", "123" N "45" "." "6" N X "" N " " N "789");
KEYS("2ge", "123" N "45" X "." "6" N "" N " " N "789");
// do not move behind end of line in normal mode
data.setText("abc def" N "ghi");
KEYS("$h", "abc d" X "ef" N "ghi");
data.setText("abc def" N "ghi");
KEYS("4e", "abc def" N "gh" X "i");
data.setText("abc def" N "ghi");
KEYS("$i", "abc de" X "f" N "ghi");
// move behind end of line in insert mode
data.setText("abc def" N "ghi");
KEYS("i<end>", "abc def" X N "ghi");
data.setText("abc def" N "ghi");
KEYS("A", "abc def" X N "ghi");
data.setText("abc def" N "ghi");
KEYS("$a", "abc def" X N "ghi");
data.setText("abc" N "def ghi");
KEYS("i<end><down>", "abc" N "def ghi" X);
data.setText("abc" N "def ghi");
KEYS("<end>i<down>", "abc" N "de" X "f ghi");
data.setText("abc" N "def ghi");
KEYS("<end>a<down>", "abc" N "def" X " ghi");
// paragraph movement
data.setText("abc" N N "def");
KEYS("}", "abc" N X N "def");
KEYS("}", "abc" N N "de" X "f");
KEYS("{", "abc" N X N "def");
KEYS("{", X "abc" N N "def");
data.setText("abc" N N N N "def");
KEYS("}", "abc" N X N N N "def");
KEYS("}", "abc" N N N N "de" X "f");
KEYS("3{", "abc" N N N N "de" X "f");
KEYS("{", "abc" N N N X N "def");
KEYS("{", X "abc" N N N N "def");
KEYS("3}", X "abc" N N N N "def");
data.setText("abc def");
KEYS("}", "abc de" X "f");
KEYS("{", X "abc def");
}
void FakeVimPlugin::test_vim_insert()
{
TestData data;
setup(&data);
// basic insert text
data.setText("ab" X "c" N "def");
KEYS("i 123", "ab 123" X "c" N "def");
INTEGRITY(false);
data.setText("ab" X "c" N "def");
KEYS("a 123", "abc 123" X N "def");
INTEGRITY(true);
data.setText("ab" X "c" N "def");
KEYS("I 123", " 123" X "abc" N "def");
INTEGRITY(false);
data.setText("abc" N "def");
KEYS("A 123", "abc 123" X N "def");
INTEGRITY(true);
data.setText("abc" N "def");
KEYS("o 123", "abc" N " 123" X N "def");
INTEGRITY(false);
data.setText("abc" N "def");
KEYS("O 123", " 123" X N "abc" N "def");
INTEGRITY(false);
// insert text [count] times
data.setText("ab" X "c" N "def");
KEYS("3i 123<esc>", "ab 123 123 12" X "3c" N "def");
INTEGRITY(false);
data.setText("ab" X "c" N "def");
KEYS("3a 123<esc>", "abc 123 123 12" X "3" N "def");
INTEGRITY(true);
data.setText("ab" X "c" N "def");
KEYS("3I 123<esc>", " 123 123 12" X "3abc" N "def");
INTEGRITY(false);
data.setText("abc" N "def");
KEYS("3A 123<esc>", "abc 123 123 12" X "3" N "def");
INTEGRITY(true);
data.setText("abc" N "def");
KEYS("3o 123<esc>", "abc" N " 123" N " 123" N " 12" X "3" N "def");
INTEGRITY(false);
data.setText("abc" N "def");
KEYS("3O 123<esc>", " 123" N " 123" N " 12" X "3" N "abc" N "def");
INTEGRITY(false);
// <C-O>
data.setText("abc" N "d" X "ef");
KEYS("i<c-o>xX", "abc" N "dX" X "f");
KEYS("i<c-o><end>", "abc" N "dXf" X);
data.setText("ab" X "c" N "def");
KEYS("i<c-o>rX", "ab" X "X" N "def");
data.setText("abc" N "def");
KEYS("A<c-o>x", "ab" X N "def");
data.setText("abc" N "de" X "f");
KEYS("i<c-o>0x", "abc" N "x" X "def");
data.setText("abc" N "de" X "f");
KEYS("i<c-o>ggx", "x" X "abc" N "def");
// <INSERT> to toggle between insert and replace mode
data.setText("abc" N "def");
KEYS("<insert>XYZ<insert>xyz<esc>", "XYZxy" X "z" N "def");
KEYS("<insert><insert>" "<c-o>0<c-o>j" "XY<insert>Z", "XYZxyz" N "XYZ" X "f");
// dot command for insert
data.setText("abc" N "def");
KEYS("ix<insert>X<insert>y<esc>", "xX" X "ybc" N "def");
KEYS("0j.", "xXybc" N "xX" X "yef");
data.setText("abc" N "def");
KEYS("<insert>x<insert>X<right>Y<esc>", "xXb" X "Y" N "def");
KEYS("0j.", "xXbY" N X "Yef");
data.setText("abc" N "def");
KEYS("<insert>x<insert>X<left><left><down><esc>", "xXbc" N X "def");
KEYS(".", "xXbc" N "x" X "Xef");
data.setText("abc" N "def");
KEYS("2oXYZ<esc>.", "abc" N "XYZ" N "XYZ" N "XYZ" N "XY" X "Z" N "def");
// delete in insert mode is part of dot command
data.setText("abc" N "def");
KEYS("iX<delete>Y", "XY" X "bc" N "def");
KEYS("0j.", "XYbc" N "X" X "Yef");
data.setText("abc" N "def");
KEYS("2iX<delete>Y<esc>", "XYX" X "Yc" N "def");
KEYS("0j.", "XYXYc" N "XYX" X "Yf");
data.setText("abc" N "def");
KEYS("i<delete>XY", "XY" X "bc" N "def");
KEYS("0j.", "XYbc" N "X" X "Yef");
data.setText("ab" X "c" N "def");
KEYS("i<bs>XY", "aXY" X "c" N "def");
KEYS("j.", "aXYc" N "dX" X "Yf");
// insert in visual block mode
data.setText("abc" N "d" X "ef" N "jkl" N "mno" N "pqr");
KEYS("<c-v>2j" "2I" "XYZ<esc>", "abc" N "d" X "XYZXYZef" N "jXYZXYZkl" N "mXYZXYZno" N "pqr");
INTEGRITY(false);
data.setText("abc" N "d" X "ef" N "jkl" N "mno" N "pqr");
KEYS("<c-v>2j" "2A" "XYZ<esc>", "abc" N "d" X "eXYZXYZf" N "jkXYZXYZl" N "mnXYZXYZo" N "pqr");
INTEGRITY(false);
data.setText("abc" N "de" X "f" N "" N "jkl" N "mno");
KEYS("<c-v>2jh" "2I" "XYZ<esc>", "abc" N "d" X "XYZXYZef" N "" N "jXYZXYZkl" N "mno");
INTEGRITY(false);
// repeat insert with special characters
data.setText("ab" X "c" N "def");
KEYS("2i<lt>down><esc>", "ab<down><down" X ">c" N "def");
INTEGRITY(false);
data.setText(" ab" X "c" N " def");
KEYS("2I<lt>end><esc>", " <end><end" X ">abc" N " def");
KEYS("u", " " X "abc" N " def");
KEYS(".", " <end><end" X ">abc" N " def");
}
void FakeVimPlugin::test_vim_fFtT()
{
TestData data;
setup(&data);
data.setText("123()456" N "a(b(c)d)e");
KEYS("t(", "12" X "3()456" N "a(b(c)d)e");
KEYS("lt(", "123" X "()456" N "a(b(c)d)e");
KEYS("0j2t(", "123()456" N "a(" X "b(c)d)e");
KEYS("l2T(", "123()456" N "a(b" X "(c)d)e");
KEYS("l2T(", "123()456" N "a(" X "b(c)d)e");
KEYS("T(", "123()456" N "a(" X "b(c)d)e");
KEYS("ggf(", "123" X "()456" N "a(b(c)d)e");
KEYS("lf(", "123(" X ")456" N "a(b(c)d)e");
KEYS("0j2f(", "123()456" N "a(b" X "(c)d)e");
KEYS("2F(", "123()456" N "a(b" X "(c)d)e");
KEYS("l2F(", "123()456" N "a" X "(b(c)d)e");
KEYS("F(", "123()456" N "a" X "(b(c)d)e");
}
void FakeVimPlugin::test_vim_transform_numbers()
{
TestData data;
setup(&data);
data.setText("8");
KEYS("<c-a>", X "9");
INTEGRITY(false);
KEYS("<c-x>", X "8");
INTEGRITY(false);
KEYS("<c-a>", X "9");
KEYS("<c-a>", "1" X "0");
KEYS("<c-a>", "1" X "1");
KEYS("5<c-a>", "1" X "6");
INTEGRITY(false);
KEYS("10<c-a>", "2" X "6");
KEYS("h100<c-a>", "12" X "6");
KEYS("100<c-x>", "2" X "6");
INTEGRITY(false);
KEYS("10<c-x>", "1" X "6");
KEYS("5<c-x>", "1" X "1");
KEYS("5<c-x>", X "6");
KEYS("6<c-x>", X "0");
KEYS("<c-x>", "-" X "1");
KEYS("h10<c-x>", "-1" X "1");
KEYS("h100<c-x>", "-11" X "1");
KEYS("h889<c-x>", "-100" X "0");
// increase nearest number
data.setText("x-x+x: 1 2 3 -4 5");
KEYS("8<c-a>", "x-x+x: " X "9 2 3 -4 5");
KEYS("l8<c-a>", "x-x+x: 9 1" X "0 3 -4 5");
KEYS("l8<c-a>", "x-x+x: 9 10 1" X "1 -4 5");
KEYS("l16<c-a>", "x-x+x: 9 10 11 1" X "2 5");
KEYS("w18<c-x>", "x-x+x: 9 10 11 12 -1" X "3");
KEYS("hh13<c-a>", "x-x+x: 9 10 11 12 " X "0");
KEYS("B12<c-x>", "x-x+x: 9 10 11 " X "0 0");
KEYS("B11<c-x>", "x-x+x: 9 10 " X "0 0 0");
KEYS("B10<c-x>", "x-x+x: 9 " X "0 0 0 0");
KEYS("B9<c-x>", "x-x+x: " X "0 0 0 0 0");
KEYS("B9<c-x>", "x-x+x: -" X "9 0 0 0 0");
data.setText("-" X "- 1 --");
KEYS("<c-x>", "-- " X "0 --");
KEYS("u", "-" X "- 1 --");
KEYS("<c-r>", "-" X "- 0 --");
KEYS("<c-x><c-x>", "-- -" X "2 --");
KEYS("2<c-a><c-a>", "-- " X "1 --");
KEYS("<c-a>2<c-a>", "-- " X "4 --");
KEYS(".", "-- " X "6 --");
KEYS("u", "-- " X "4 --");
KEYS("<c-r>", "-- " X "6 --");
// hexadecimal and octal numbers
data.setText("0x0 0x1 -1 07 08");
KEYS("3<c-a>", "0x" X "3 0x1 -1 07 08");
KEYS("7<c-a>", "0x" X "a 0x1 -1 07 08");
KEYS("9<c-a>", "0x1" X "3 0x1 -1 07 08");
// if last letter in hexadecimal number is capital then all letters are capital
KEYS("ifA<esc>", "0x1f" X "A3 0x1 -1 07 08");
KEYS("9<c-a>", "0x1FA" X "C 0x1 -1 07 08");
KEYS("w1022<c-a>", "0x1FAC 0x3f" X "f -1 07 08");
KEYS("w.", "0x1FAC 0x3ff 102" X "1 07 08");
// octal number
KEYS("w.", "0x1FAC 0x3ff 1021 0200" X "5 08");
// non-octal number with leading zeroes
KEYS("w.", "0x1FAC 0x3ff 1021 02005 103" X "0");
// preserve width of hexadecimal and octal numbers
data.setText("0x0001");
KEYS("<c-a>", "0x000" X "2");
KEYS("10<c-a>", "0x000" X "c");
KEYS(".", "0x001" X "6");
KEYS("999<c-a>", "0x03f" X "d");
KEYS("99999<c-a>", "0x18a9" X "c");
data.setText("0001");
KEYS("<c-a>", "000" X "2");
KEYS("10<c-a>", "001" X "4");
KEYS("999<c-a>", "0176" X "3");
data.setText("0x0100");
KEYS("<c-x>", "0x00f" X "f");
data.setText("0100");
KEYS("<c-x>", "007" X "7");
}
void FakeVimPlugin::test_vim_delete()
{
TestData data;
setup(&data);
data.setText("123" N "456");
KEYS("x", "23" N "456");
INTEGRITY(false);
KEYS("dd", "456");
INTEGRITY(false);
KEYS("2x", "6");
INTEGRITY(false);
KEYS("dd", "");
INTEGRITY(false);
data.setText("void main()");
KEYS("dt(", "()");
INTEGRITY(false);
data.setText("void main()");
KEYS("df(", ")");
INTEGRITY(false);
data.setText("void " X "main()");
KEYS("D", "void ");
INTEGRITY(false);
KEYS("ggd$", "");
data.setText("abc def ghi");
KEYS("2dw", X "ghi");
INTEGRITY(false);
data.setText("abc def ghi");
KEYS("d2w", X "ghi");
INTEGRITY(false);
data.setText("abc " N " def" N " ghi" N "jkl");
KEYS("3dw", X "jkl");
data.setText("abc " N " def" N " ghi" N "jkl");
KEYS("d3w", X "jkl");
// delete empty line
data.setText("a" N X "" N " b");
KEYS("dd", "a" N " " X "b");
// delete on an empty line
data.setText("a" N X "" N " b");
KEYS("d$", "a" N X "" N " b");
INTEGRITY(false);
// delete in empty document
data.setText("");
KEYS("dd", X);
// delete to start of line
data.setText(" abc" N " de" X "f" N " ghi");
KEYS("d0", " abc" N X "f" N " ghi");
INTEGRITY(false);
data.setText(" abc" N " de" X "f" N " ghi");
KEYS("d^", " abc" N " " X "f" N " ghi");
INTEGRITY(false);
// delete to mark
data.setText("abc " X "def ghi");
KEYS("ma" "3l" "d`a", "abc " X " ghi");
KEYS("u" "gg" "d`a", X "def ghi");
// delete lines
data.setText(" abc" N " de" X "f" N " ghi" N " jkl");
KEYS("dj", " abc" N " " X "jkl");
INTEGRITY(false);
data.setText(" abc" N " def" N " gh" X "i" N " jkl");
KEYS("dk", " abc" N " " X "jkl");
INTEGRITY(false);
// delete with copy to a register
data.setText("abc" N "def");
KEYS("\"xd$", X "" N "def");
KEYS("\"xp", "ab" X "c" N "def");
KEYS("2\"xp", "abcabcab" X "c" N "def");
}
void FakeVimPlugin::test_vim_delete_inner_word()
{
TestData data;
setup(&data);
data.setText("abc def ghi");
KEYS("wlldiw", "abc " X " ghi");
data.setText("abc def ghi jkl");
KEYS("3diw", X " ghi jkl");
INTEGRITY(false);
data.setText("abc " X " def");
KEYS("diw", "abc" X "def");
INTEGRITY(false);
KEYS("diw", "");
data.setText("abc " N " def");
KEYS("3diw", X "def");
data.setText("abc " N " def" N " ghi");
KEYS("4diw", " " X "ghi");
data.setText("ab" X "c " N " def" N " ghi");
KEYS("4diw", " " X "ghi");
data.setText("a b" X "c " N " def" N " ghi");
KEYS("4diw", "a" X " " N " ghi");
data.setText("abc def" N "ghi");
KEYS("2diw", X "def" N "ghi");
data.setText("abc def" N "ghi");
KEYS("3diw", X "" N "ghi");
data.setText("x" N X "" N "" N " ");
KEYS("diw", "x" N X "" N "" N " ");
data.setText("x" N X "" N "" N " ");
KEYS("2diw", "x" N " " X " ");
data.setText("x" N X "" N "" N "" N "" N " ");
KEYS("3diw", "x" N " " X " ");
data.setText("x" N X "" N "" N "" N "" N "" N " ");
KEYS("3diw", "x" N X "" N " ");
data.setText("x" N X "" N "" N "" N "" N "" N "" N " ");
KEYS("4diw", "x" N X "" N " ");
// delete single-character-word
data.setText("a " X "b c");
KEYS("diw", "a " X " c");
}
void FakeVimPlugin::test_vim_delete_a_word()
{
TestData data;
setup(&data);
data.setText("abc def ghi");
KEYS("wlldaw", "abc " X "ghi");
data.setText("abc def ghi jkl");
KEYS("wll2daw", "abc " X "jkl");
data.setText("abc" X " def ghi");
KEYS("daw", "abc" X " ghi");
INTEGRITY(false);
KEYS("daw", "ab" X "c");
INTEGRITY(false);
KEYS("daw", "");
data.setText(X " ghi jkl");
KEYS("daw", X " jkl");
KEYS("ldaw", X " ");
data.setText("abc def ghi jkl");
KEYS("3daw", X "jkl");
INTEGRITY(false);
// remove trailing spaces
data.setText("abc " N " def" N " ghi" N "jkl");
KEYS("3daw", X "jkl");
data.setText("abc " N " def" N " ghi" N "jkl");
KEYS("3daw", X "jkl");
data.setText("abc def" N "ghi");
KEYS("2daw", X "" N "ghi");
data.setText("x" N X "" N "" N " ");
KEYS("daw", "x" N " " X " ");
data.setText("x" N X "" N "" N "" N "" N " ");
KEYS("2daw", "x" N " " X " ");
data.setText("x" N X "" N "" N "" N "" N "" N " ");
KEYS("2daw", "x" N X "" N " ");
data.setText("x" N X "" N "" N "" N "" N "" N "" N " ");
KEYS("3daw", "x" N " " X " ");
// delete single-character-word
data.setText("a," X "b,c");
KEYS("daw", "a," X ",c");
// delete a word with visual selection
data.setText(X "a" N "" N "b");
KEYS("vawd", X "" N "" N "b");
data.setText(X "a" N "" N "b");
KEYS("Vawd", X "" N "" N "b");
data.setText("abc def g" X "hi");
KEYS("vawd", "abc de" X "f");
KEYS("u", "abc def" X " ghi");
// backward visual selection
data.setText("abc def g" X "hi");
KEYS("vhawd", "abc " X "i");
data.setText("abc def gh" X "i");
KEYS("vhawd", "abc de" X "f");
data.setText("abc def gh" X "i");
KEYS("vh2awd", "ab" X "c");
}
void FakeVimPlugin::test_vim_change_a_word()
{
TestData data;
setup(&data);
data.setText("abc " X "def ghi");
KEYS("caw#", "abc #" X "ghi");
INTEGRITY(false);
data.setText("abc d" X "ef ghi");
KEYS("caw#", "abc #" X "ghi");
data.setText("abc de" X "f ghi");
KEYS("caw#", "abc #" X "ghi");
data.setText("abc de" X "f ghi jkl");
KEYS("2caw#", "abc #" X "jkl");
INTEGRITY(false);
data.setText("abc" X " def ghi jkl");
KEYS("2caw#", "abc#" X " jkl");
data.setText("abc " X " def ghi jkl");
KEYS("2caw#", "abc#" X " jkl");
data.setText(" abc " N " def" N " ghi" N " jkl");
KEYS("3caw#", "#" X N " jkl");
// change single-character-word
data.setText("a " X "b c");
KEYS("ciwX<esc>", "a " X "X c");
KEYS("cawZ<esc>", "a " X "Zc");
}
void FakeVimPlugin::test_vim_change_replace()
{
TestData data;
setup(&data);
// preserve lines in replace mode
data.setText("abc" N "def");
KEYS("llvjhrX", "ab" X "X" N "XXf");
// change empty line
data.setText("a" N X "" N " b");
KEYS("ccABC", "a" N "ABC" X N " b");
INTEGRITY(false);
// change on empty line
data.setText("a" N X "" N " b");
KEYS("c$ABC<esc>", "a" N "AB" X "C" N " b");
INTEGRITY(false);
KEYS("u", "a" N X "" N " b");
KEYS("rA", "a" N X "" N " b");
// change in empty document
data.setText("");
KEYS("ccABC", "ABC" X);
KEYS("u", "");
KEYS("SABC", "ABC" X);
KEYS("u", "");
KEYS("sABC", "ABC" X);
KEYS("u", "");
KEYS("rA", "" X);
// indentation with change
data.doCommand("set expandtab");
data.doCommand("set shiftwidth=2");
data.setText("int main()" N
"{" N
" " X " return 0;" N
"}" N
"");
KEYS("cc" "int i = 0;",
"int main()" N
"{" N
" int i = 0;" X N
"}" N
"");
INTEGRITY(false);
KEYS("uS" "int i = 0;" N "int j = 1;",
"int main()" N
"{" N
" int i = 0;" N
" int j = 1;" X N
"}" N
"");
// change to start of line
data.setText(" abc" N " de" X "f" N " ghi");
KEYS("c0123<ESC>", " abc" N "12" X "3f" N " ghi");
INTEGRITY(false);
data.setText(" abc" N " de" X "f" N " ghi");
KEYS("c^123<ESC>", " abc" N " 12" X "3f" N " ghi");
INTEGRITY(false);
// change to mark
data.setText("abc " X "def ghi");
KEYS("ma" "3l" "c`a123<ESC>", "abc 12" X "3 ghi");
KEYS("u" "gg" "c`a123<ESC>", "12" X "3def ghi");
// change lines
data.setText(" abc" N " de" X "f" N " ghi" N " jkl");
KEYS("cj123<ESC>", " abc" N " 12" X "3" N " jkl");
INTEGRITY(false);
data.setText(" abc" N " def" N " gh" X "i" N " jkl");
KEYS("ck123<ESC>", " abc" N " 12" X "3" N " jkl");
INTEGRITY(false);
data.setText("abc" N X "def");
KEYS("sXYZ", "abc" N "XYZ" X "ef");
INTEGRITY(false);
data.setText("abc" N X "def");
KEYS("2sXYZ<ESC>", "abc" N "XY" X "Zf");
INTEGRITY(false);
data.setText("abc" N X "def");
KEYS("6sXYZ<ESC>", "abc" N "XY" X "Z");
INTEGRITY(false);
// insert in visual block mode
data.setText("abc" N "d" X "ef" N "jkl" N "mno" N "pqr");
KEYS("<c-v>2j" "2s" "XYZ<esc>", "abc" N "d" X "XYZf" N "jXYZl" N "mXYZo" N "pqr");
INTEGRITY(false);
data.setText("abc" N "de" X "f" N "" N "jkl" N "mno");
KEYS("<c-v>2jh" "2s" "XYZ<esc>", "abc" N "d" X "XYZ" N "" N "jXYZ" N "mno");
INTEGRITY(false);
// change with copy to a register
data.setText("abc" N "def");
KEYS("\"xCxyz<esc>", "xy" X "z" N "def");
KEYS("\"xp", "xyzab" X "c" N "def");
KEYS("2\"xp", "xyzabcabcab" X "c" N "def");
}
void FakeVimPlugin::test_vim_block_selection()
{
TestData data;
setup(&data);
data.setText("int main(int /* (unused) */, char *argv[]);");
KEYS("f(", "int main" X "(int /* (unused) */, char *argv[]);");
KEYS("da(", "int main" X ";");
INTEGRITY(false);
data.setText("int main(int /* (unused) */, char *argv[]);");
KEYS("f(", "int main" X "(int /* (unused) */, char *argv[]);");
KEYS("di(", "int main(" X ");");
INTEGRITY(false);
data.setText("int main(int /* (unused) */, char *argv[]);");
KEYS("2f)", "int main(int /* (unused) */, char *argv[]" X ");");
KEYS("da(", "int main" X ";");
data.setText("int main(int /* (unused) */, char *argv[]);");
KEYS("2f)", "int main(int /* (unused) */, char *argv[]" X ");");
KEYS("di(", "int main(" X ");");
data.setText("{ { { } } }");
KEYS("2f{l", "{ { {" X " } } }");
KEYS("da{", "{ { " X " } }");
KEYS("da{", "{ " X " }");
INTEGRITY(false);
data.setText("{ { { } } }");
KEYS("2f{l", "{ { {" X " } } }");
KEYS("2da{", "{ " X " }");
INTEGRITY(false);
data.setText("{" N " { " N " } " N "}");
KEYS("di{", "{" N "}");
data.setText("(" X "())");
KEYS("di(", "((" X "))");
data.setText("\"\"");
KEYS("di\"", "\"" X "\"");
// visual selection
data.setText("(abc()" X "(def))");
KEYS("vi(d", "(abc()(" X "))");
KEYS("u", "(abc()(" X "def))");
KEYS("<c-r>", "(abc()(" X "))");
KEYS("va(d", "(abc()" X ")");
KEYS("u", "(abc()" X "())");
KEYS("<c-r>", "(abc()" X ")");
data.setText("\"abc" X "\"\"def\"");
KEYS("vi\"d", "\"" X "\"\"def\"");
// repeat change inner
data.setText("(abc)" N "def" N "(ghi)");
KEYS("ci(xyz<esc>", "(xy" X "z)" N "def" N "(ghi)");
KEYS("j.", "(xyz)" N "de" X "f" N "(ghi)");
KEYS("j.", "(xyz)" N "def" N "(xy" X "z)");
// quoted string
data.setText("\"abc" X "\"\"def\"");
KEYS("di\"", "\"" X "\"\"def\"");
KEYS("u", "\"" X "abc\"\"def\"");
KEYS("<c-r>", "\"" X "\"\"def\"");
NOT_IMPLEMENTED
// quoted string with escaped character
data.setText("\"abc\"");
KEYS("di\"", "\"abc\"\"" X "\"");
KEYS("u", "\"abc\"\"" X "def\"");
}
void FakeVimPlugin::test_vim_repeat()
{
TestData data;
setup(&data);
// delete line
data.setText("abc" N "def" N "ghi");
KEYS("dd", X "def" N "ghi");
KEYS(".", X "ghi");
INTEGRITY(false);
// delete to next word
data.setText("abc def ghi jkl");
KEYS("dw", X "def ghi jkl");
KEYS("w.", "def " X "jkl");
KEYS("gg.", X "jkl");
// change in word
data.setText("WORD text");
KEYS("ciwWORD<esc>", "WOR" X "D text");
KEYS("w.", "WORD WOR" X "D");
/* QTCREATORBUG-7248 */
data.setText("test tex" X "t");
KEYS("vbcWORD<esc>", "test " "WOR" X "D");
KEYS("bb.", "WOR" X "D WORD");
// delete selected range
data.setText("abc def ghi jkl");
KEYS("viwd", X " def ghi jkl");
KEYS(".", X "f ghi jkl");
KEYS(".", X "hi jkl");
// delete two lines
data.setText("abc" N "def" N "ghi" N "jkl" N "mno");
KEYS("Vjx", X "ghi" N "jkl" N "mno");
KEYS(".", X "mno");
// delete three lines
data.setText("abc" N "def" N "ghi" N "jkl" N "mno" N "pqr" N "stu");
KEYS("d2j", X "jkl" N "mno" N "pqr" N "stu");
KEYS(".", X "stu");
// replace block selection
data.setText("abcd" N "d" X "efg" N "ghij" N "jklm");
KEYS("<c-v>jlrX", "abcd" N "d" X "XXg" N "gXXj" N "jklm");
KEYS("gg.", "XXcd" N "XXXg" N "gXXj" N "jklm");
}
void FakeVimPlugin::test_vim_search()
{
TestData data;
setup(&data);
data.setText("abc" N "def" N "ghi");
KEYS("/ghi<CR>", "abc" N "def" N X "ghi");
KEYS("gg/\\w\\{3}<CR>", "abc" N X "def" N "ghi");
KEYS("n", "abc" N "def" N X "ghi");
KEYS("N", "abc" N X "def" N "ghi");
KEYS("N", X "abc" N "def" N "ghi");
// return to search-start position on escape or not found
KEYS("/def<ESC>", X "abc" N "def" N "ghi");
KEYS("/x", X "abc" N "def" N "ghi");
KEYS("/x<CR>", X "abc" N "def" N "ghi");
KEYS("/x<ESC>", X "abc" N "def" N "ghi");
KEYS("/ghX", X "abc" N "def" N "ghi");
KEYS("?def<ESC>", X "abc" N "def" N "ghi");
KEYS("?x", X "abc" N "def" N "ghi");
KEYS("?x<CR>", X "abc" N "def" N "ghi");
KEYS("?x<ESC>", X "abc" N "def" N "ghi");
// set wrapscan (search wraps at end of file)
data.doCommand("set ws");
// search [count] times
data.setText("abc" N "def" N "ghi");
KEYS("/\\w\\{3}<CR>", "abc" N X "def" N "ghi");
KEYS("2n", X "abc" N "def" N "ghi");
KEYS("2N", "abc" N X "def" N "ghi");
KEYS("2/\\w\\{3}<CR>", X "abc" N "def" N "ghi");
data.setText("abc" N "def" N "abc" N "ghi abc jkl");
KEYS("*", "abc" N "def" N X "abc" N "ghi abc jkl");
KEYS("*", "abc" N "def" N "abc" N "ghi " X "abc jkl");
KEYS("2*", "abc" N "def" N X "abc" N "ghi abc jkl");
KEYS("#", X "abc" N "def" N "abc" N "ghi abc jkl");
KEYS("#", "abc" N "def" N "abc" N "ghi " X "abc jkl");
KEYS("#", "abc" N "def" N X "abc" N "ghi abc jkl");
KEYS("2#", "abc" N "def" N "abc" N "ghi " X "abc jkl");
data.doCommand("set nows");
data.setText("abc" N "def" N "abc" N "ghi abc jkl");
KEYS("*", "abc" N "def" N X "abc" N "ghi abc jkl");
KEYS("*", "abc" N "def" N "abc" N "ghi " X "abc jkl");
KEYS("*", "abc" N "def" N "abc" N "ghi " X "abc jkl");
KEYS("#", "abc" N "def" N X "abc" N "ghi abc jkl");
KEYS("#", X "abc" N "def" N "abc" N "ghi abc jkl");
KEYS("#", X "abc" N "def" N "abc" N "ghi abc jkl");
data.setText("abc" N "def" N "ab" X "c" N "ghi abc jkl");
KEYS("#", X "abc" N "def" N "abc" N "ghi abc jkl");
// search with g* and g#
data.doCommand("set nows");
data.setText("bc" N "abc" N "abcd" N "bc" N "b");
KEYS("g*", "bc" N "a" X "bc" N "abcd" N "bc" N "b");
KEYS("n", "bc" N "abc" N "a" X "bcd" N "bc" N "b");
KEYS("n", "bc" N "abc" N "abcd" N X "bc" N "b");
KEYS("n", "bc" N "abc" N "abcd" N X "bc" N "b");
KEYS("g#", "bc" N "abc" N "a" X "bcd" N "bc" N "b");
KEYS("n", "bc" N "a" X "bc" N "abcd" N "bc" N "b");
KEYS("N", "bc" N "abc" N "a" X "bcd" N "bc" N "b");
KEYS("3n", "bc" N "abc" N "a" X "bcd" N "bc" N "b");
KEYS("2n", X "bc" N "abc" N "abcd" N "bc" N "b");
/* QTCREATORBUG-7251 */
data.setText("abc abc abc abc");
KEYS("$?abc<CR>", "abc abc abc " X "abc");
KEYS("2?abc<CR>", "abc " X "abc abc abc");
KEYS("n", X "abc abc abc abc");
KEYS("N", "abc " X "abc abc abc");
// search is greedy
data.doCommand("set ws");
data.setText("abc" N "def" N "abc" N "ghi abc jkl");
KEYS("/[a-z]*<CR>", "abc" N X "def" N "abc" N "ghi abc jkl");
KEYS("2n", "abc" N "def" N "abc" N X "ghi abc jkl");
KEYS("3n", "abc" N "def" N "abc" N "ghi abc" X " jkl");
KEYS("3N", "abc" N "def" N "abc" N X "ghi abc jkl");
KEYS("2N", "abc" N X "def" N "abc" N "ghi abc jkl");
data.setText("a.b.c" N "" N "d.e.f");
KEYS("/[a-z]*<CR>", "a" X ".b.c" N "" N "d.e.f");
KEYS("n", "a." X "b.c" N "" N "d.e.f");
KEYS("2n", "a.b." X "c" N "" N "d.e.f");
KEYS("n", "a.b.c" N X "" N "d.e.f");
KEYS("n", "a.b.c" N "" N X "d.e.f");
KEYS("2N", "a.b." X "c" N "" N "d.e.f");
KEYS("2n", "a.b.c" N "" N X "d.e.f");
// find same stuff forward and backward,
// i.e. '<ab>c' forward but not 'a<bc>' backward
data.setText("abc" N "def" N "ghi");
KEYS("/\\w\\{2}<CR>", "abc" N X "def" N "ghi");
KEYS("n", "abc" N "def" N X "ghi");
KEYS("N", "abc" N X "def" N "ghi");
KEYS("N", X "abc" N "def" N "ghi");
KEYS("2n2N", X "abc" N "def" N "ghi");
}
void FakeVimPlugin::test_vim_indent()
{
TestData data;
setup(&data);
data.doCommand("set expandtab");
data.doCommand("set shiftwidth=4");
data.setText(
"abc" N
"def" N
"ghi" N
"jkl" N
"mno");
KEYS("j3>>",
"abc" N
" " X "def" N
" ghi" N
" jkl" N
"mno");
KEYS("j2>>",
"abc" N
" def" N
" " X "ghi" N
" jkl" N
"mno");
KEYS("2<<",
"abc" N
" def" N
" " X "ghi" N
" jkl" N
"mno");
INTEGRITY(false);
KEYS("k3<<",
"abc" N
X "def" N
"ghi" N
"jkl" N
"mno");
data.setText(
"abc" N
"def" N
"ghi" N
"jkl" N
"mno");
KEYS("jj>j",
"abc" N
"def" N
" " X "ghi" N
" jkl" N
"mno");
data.setText("abc");
KEYS(">>", " " X "abc");
INTEGRITY(false);
data.setText("abc");
data.doCommand("set shiftwidth=2");
KEYS(">>", " " X "abc");
data.setText("abc");
data.doCommand("set noexpandtab");
data.doCommand("set tabstop=2");
data.doCommand("set shiftwidth=7");
// shiftwidth = TABS * tabstop + SPACES
// 7 = 3 * 2 + 1
KEYS(">>", "\t\t\t abc");
data.doCommand("set tabstop=3");
data.doCommand("set shiftwidth=7");
data.setText("abc");
KEYS(">>", "\t\t abc");
INTEGRITY(false);
}
void FakeVimPlugin::test_vim_marks()
{
TestData data;
setup(&data);
data.setText(" abc" N " def" N " ghi");
data.doKeys("ma");
data.doKeys("ma");
data.doKeys("jmb");
data.doKeys("j^mc");
KEYS("'a", " " X "abc" N " " "def" N " " "ghi");
KEYS("`a", X " " "abc" N " " "def" N " " "ghi");
KEYS("`b", " " "abc" N X " " "def" N " " "ghi");
KEYS("'b", " " "abc" N " " X "def" N " " "ghi");
KEYS("`c", " " "abc" N " " "def" N " " X "ghi");
KEYS("'c", " " "abc" N " " "def" N " " X "ghi");
KEYS("`b", " " "abc" N X " " "def" N " " "ghi");
KEYS("'c", " " "abc" N " " "def" N " " X "ghi");
KEYS("`'", " " "abc" N X " " "def" N " " "ghi");
KEYS("`a", X " " "abc" N " " "def" N " " "ghi");
KEYS("''", " " "abc" N " " X "def" N " " "ghi");
KEYS("`'", X " " "abc" N " " "def" N " " "ghi");
KEYS("`'", " " "abc" N " " X "def" N " " "ghi");
// new mark isn't lost on undo
data.setText( "abc" N "d" X "ef" N "ghi");
KEYS("x" "mx" "gg", X "abc" N "df" N "ghi");
KEYS("ugg" "`x", "abc" N "d" X "ef" N "ghi");
// previous value of mark is restored on undo/redo
data.setText( "abc" N "d" X "ef" N "ghi");
KEYS("mx" "x" "ggl", "a" X "bc" N "df" N "ghi");
KEYS("mx" "uG" "`x", "abc" N "d" X "ef" N "ghi");
KEYS("<c-r>G" "`x", "a" X "bc" N "df" N "ghi");
KEYS("uG" "`x", "abc" N "d" X "ef" N "ghi");
KEYS("<c-r>G" "`x", "a" X "bc" N "df" N "ghi");
}
void FakeVimPlugin::test_vim_jumps()
{
TestData data;
setup(&data);
// last position
data.setText(" abc" N " def" N " ghi");
KEYS("G", " abc" N " def" N " " X "ghi");
KEYS("`'", X " abc" N " def" N " ghi");
KEYS("`'", " abc" N " def" N " " X "ghi");
KEYS("''", " " X "abc" N " def" N " ghi");
KEYS("<C-O>", " abc" N " def" N " " X "ghi");
KEYS("<C-I>", " " X "abc" N " def" N " ghi");
KEYS("lgUlhj", " aBc" N " " X "def" N " ghi");
KEYS("`.", " a" X "Bc" N " def" N " ghi");
KEYS("`'", " aBc" N " " X "def" N " ghi");
KEYS("'.", " " X "aBc" N " def" N " ghi");
KEYS("G", " aBc" N " def" N " " X "ghi");
KEYS("u", " a" X "bc" N " def" N " ghi");
KEYS("`'", " abc" N " def" N " " X "ghi");
KEYS("<c-r>", " a" X "Bc" N " def" N " ghi");
KEYS("jd$", " aBc" N " " X "d" N " ghi");
KEYS("''", " aBc" N " d" N " " X "ghi");
KEYS("`'", " aBc" N " " X "d" N " ghi");
KEYS("u", " aBc" N " d" X "ef" N " ghi");
KEYS("''", " aBc" N " " X "def" N " ghi");
KEYS("`'", " aBc" N " d" X "ef" N " ghi");
// record external position changes
data.setText("abc" N "def" N "g" X "hi");
data.jump("abc" N "de" X "f" N "ghi");
KEYS("<C-O>", "abc" N "def" N "g" X "hi");
KEYS("<C-I>", "abc" N "de" X "f" N "ghi");
data.jump("ab" X "c" N "def" N "ghi");
KEYS("<C-O>", "abc" N "de" X "f" N "ghi");
KEYS("<C-O>", "abc" N "def" N "g" X "hi");
}
void FakeVimPlugin::test_vim_current_column()
{
// Check if column is correct after command and vertical cursor movement.
TestData data;
setup(&data);
// always at end of line after <end>
data.setText(" abc" N " def 123" N "" N " ghi");
KEYS("<end><down>", " abc" N " def 12" X "3" N "" N " ghi");
KEYS("<down><down>", " abc" N " def 123" N "" N " gh" X "i");
KEYS("<up>", " abc" N " def 123" N X "" N " ghi");
KEYS("<up>", " abc" N " def 12" X "3" N "" N " ghi");
// ... in insert
KEYS("i<end><up>", " abc" X N " def 123" N "" N " ghi");
KEYS("<down>i<end><up><down>", " abc" N " def 123" X N "" N " ghi");
// vertical movement doesn't reset column
data.setText(" abc" N " def 1" X "23" N "" N " ghi");
KEYS("<up>", " ab" X "c" N " def 123" N "" N " ghi");
KEYS("<down>", " abc" N " def 1" X "23" N "" N " ghi");
KEYS("<down><down>", " abc" N " def 123" N "" N " gh" X "i");
KEYS("<up><up>", " abc" N " def 1" X "23" N "" N " ghi");
KEYS("^jj", " abc" N " def 123" N "" N " " X "ghi");
KEYS("kk", " abc" N " " X "def 123" N "" N " ghi");
// yiw, yaw
data.setText(" abc" N " def" N " ghi");
KEYS("e<down>", " abc" N " de" X "f" N " ghi");
KEYS("b<down>", " abc" N " def" N " " X "ghi");
KEYS("ll<up>", " abc" N " de" X "f" N " ghi");
KEYS("<down>yiw<up>", " abc" N " " X "def" N " ghi");
KEYS("llyaw<up>", " " X "abc" N " def" N " ghi");
// insert
data.setText(" abc" N " def" N " ghi");
KEYS("lljj", " abc" N " def" N " " X "ghi");
KEYS("i123<up>", " abc" N " def" X N " 123ghi");
KEYS("a456<up><down>", " abc" N " def456" X N " 123ghi");
data.setText(" abc" N X " def 123" N "" N " ghi");
KEYS("A<down><down>", " abc" N " def 123" N "" N " ghi" X);
KEYS("A<up><up>", " abc" N " def" X " 123" N "" N " ghi");
KEYS("A<down><down><up><up>", " abc" N " def 123" X N "" N " ghi");
data.setText(" abc" N X " def 123" N "" N " ghi");
KEYS("I<down><down>", " abc" N " def 123" N "" N " " X "ghi");
// change
data.setText(" abc" N " d" X "ef" N " ghi");
KEYS("cc<up>", " " X "abc" N " " N " ghi");
data.setText(" abc" N " d" X "ef" N " ghi");
KEYS("cc<up>x<down><down>", " xabc" N " " N " g" X "hi");
}
void FakeVimPlugin::test_vim_copy_paste()
{
TestData data;
setup(&data);
data.setText("123" N "456");
KEYS("llyy2P", X "123" N "123" N "123" N "456");
data.setText("123" N "456");
KEYS("yyp", "123" N X "123" N "456");
KEYS("2p", "123" N "123" N X "123" N "123" N "456");
INTEGRITY(false);
data.setText("123 456");
KEYS("yw2P", "123 123" X " 123 456");
KEYS("2p", "123 123 123 123" X " 123 456");
data.setText("123" N "456");
KEYS("2yyp", "123" N X "123" N "456" N "456");
data.setText("123" N "456");
KEYS("2yyP", X "123" N "456" N "123" N "456");
data.setText("123" N "456" N "789");
KEYS("ddp", "456" N X "123" N "789");
// block-select middle column, copy and paste twice
data.setText("123" N "456");
KEYS("l<C-v>j\"xy2\"xp", "12" X "223" N "45556");
data.setText("123" N "456" N "789");
KEYS("wyiw" "wviwp", "123" N "456" N "45" X "6");
// QTCREATORBUG-8148
data.setText("abc");
KEYS("yyp", "abc" N X "abc");
KEYS("4p", "abc" N "abc" N X "abc" N "abc" N "abc" N "abc");
// cursor position after yank
data.setText("ab" X "c" N "def");
KEYS("Vjy", X "abc" N "def");
data.setText("ab" X "c" N "def");
KEYS("<c-v>jhhy", X "abc" N "def");
data.setText("ab" X "c" N "def");
KEYS("yj", "ab" X "c" N "def");
data.setText("abc" N "de" X "f");
KEYS("yk", "ab" X "c" N "def");
// copy empty line
data.setText(X "a" N "" N "b");
KEYS("Vjy", X "a" N "" N "b");
KEYS("p", "a" N X "a" N "" N "" N "b");
// registers
data.setText(X "abc" N "def" N "ghi");
KEYS("\"xyy", X "abc" N "def" N "ghi");
KEYS("\"xp", "abc" N X "abc" N "def" N "ghi");
KEYS("j\"yyy", "abc" N "abc" N X "def" N "ghi");
KEYS("gg\"yP", X "def" N "abc" N "abc" N "def" N "ghi");
KEYS("\"xP", X "abc" N "def" N "abc" N "abc" N "def" N "ghi");
}
void FakeVimPlugin::test_vim_undo_redo()
{
TestData data;
setup(&data);
data.setText("abc def" N "xyz" N "123");
KEYS("ddu", X "abc def" N "xyz" N "123");
COMMAND("redo", X "xyz" N "123");
COMMAND("undo", X "abc def" N "xyz" N "123");
COMMAND("redo", X "xyz" N "123");
KEYS("dd", X "123");
KEYS("3x", X "");
KEYS("uuu", X "abc def" N "xyz" N "123");
KEYS("<C-r>", X "xyz" N "123");
KEYS("2<C-r>", X "");
KEYS("3u", X "abc def" N "xyz" N "123");
KEYS("wved", "abc" X " " N "xyz" N "123");
KEYS("2w", "abc " N "xyz" N X "123");
KEYS("u", "abc " X "def" N "xyz" N "123");
KEYS("<C-r>", "abc" X " " N "xyz" N "123");
KEYS("10ugg", X "abc def" N "xyz" N "123");
KEYS("A xxx<ESC>", "abc def xx" X "x" N "xyz" N "123");
KEYS("A yyy<ESC>", "abc def xxx yy" X "y" N "xyz" N "123");
KEYS("u", "abc def xx" X "x" N "xyz" N "123");
KEYS("u", "abc de" X "f" N "xyz" N "123");
KEYS("<C-r>", "abc def" X " xxx" N "xyz" N "123");
KEYS("<C-r>", "abc def xxx" X " yyy" N "xyz" N "123");
KEYS("izzz<ESC>", "abc def xxxzz" X "z yyy" N "xyz" N "123");
KEYS("<C-r>", "abc def xxxzz" X "z yyy" N "xyz" N "123");
KEYS("u", "abc def xxx" X " yyy" N "xyz" N "123");
data.setText("abc" N X "def");
KEYS("oxyz<ESC>", "abc" N "def" N "xy" X "z");
KEYS("u", "abc" N X "def");
// undo paste lines
data.setText("abc" N);
KEYS("yy2p", "abc" N X "abc" N "abc" N);
KEYS("yy3p", "abc" N "abc" N X "abc" N "abc" N "abc" N "abc" N);
KEYS("u", "abc" N X "abc" N "abc" N);
KEYS("u", X "abc" N);
KEYS("<C-r>", X "abc" N "abc" N "abc" N);
KEYS("<C-r>", "abc" N X "abc" N "abc" N "abc" N "abc" N "abc" N);
KEYS("u", "abc" N X "abc" N "abc" N);
KEYS("u", X "abc" N);
// undo paste block
data.setText("abc" N "def" N "ghi");
KEYS("<C-v>jyp", "a" X "abc" N "ddef" N "ghi");
KEYS("2p", "aa" X "aabc" N "ddddef" N "ghi");
KEYS("3p", "aaa" X "aaaabc" N "dddddddef" N "ghi");
KEYS("u", "aa" X "aabc" N "ddddef" N "ghi");
KEYS("u", "a" X "abc" N "ddef" N "ghi");
// undo indent
data.doCommand("set expandtab");
data.doCommand("set shiftwidth=4");
data.setText("abc" N "def");
KEYS(">>", " " X "abc" N "def");
KEYS(">>", " " X "abc" N "def");
KEYS("<<", " " X "abc" N "def");
KEYS("<<", X "abc" N "def");
KEYS("u", " " X "abc" N "def");
KEYS("u", " " X "abc" N "def");
KEYS("u", " " X "abc" N "def");
KEYS("u", X "abc" N "def");
KEYS("<C-r>", X " abc" N "def");
KEYS("<C-r>", " " X " abc" N "def");
KEYS("<C-r>", " ab" X "c" N "def");
KEYS("<C-r>", "ab" X "c" N "def");
KEYS("<C-r>", "ab" X "c" N "def");
data.setText("abc" N "def");
KEYS("2>>", " " X "abc" N " def");
KEYS("u", X "abc" N "def");
KEYS("<c-r>", X " abc" N " def");
KEYS("u", X "abc" N "def");
KEYS(">j", " " X "abc" N " def");
KEYS("u", X "abc" N "def");
KEYS("<c-r>", X " abc" N " def");
// undo replace line
data.setText("abc" N " def" N "ghi");
KEYS("jlllSxyz<ESC>", "abc" N "xyz" N "ghi");
KEYS("u", "abc" N " " X "def" N "ghi");
}
void FakeVimPlugin::test_vim_letter_case()
{
TestData data;
setup(&data);
// set command ~ not to behave as g~
data.doCommand("set notildeop");
// upper- and lower-case
data.setText("abc DEF");
KEYS("~", "A" X "bc DEF");
INTEGRITY(false);
KEYS("4~", "ABC d" X "EF");
INTEGRITY(false);
data.setText("abc DEF" N "ghi");
KEYS("l9~", "aBC de" X "f" N "ghi");
KEYS(".", "aBC de" X "F" N "ghi");
KEYS("h.", "aBC dE" X "f" N "ghi");
// set command ~ to behave as g~
data.doCommand("set tildeop");
data.setText("abc DEF" N "ghi JKL");
KEYS("ll~j", "ABC def" N "GHI jkl");
data.setText("abc DEF");
KEYS("lv3l~", "a" X "BC dEF");
KEYS("v4lU", "a" X "BC DEF");
KEYS("v4$u", "a" X "bc def");
KEYS("v4$gU", "a" X "BC DEF");
KEYS("gu$", "a" X "bc def");
KEYS("lg~~", X "ABC DEF");
KEYS(".", X "abc def");
KEYS("gUiw", X "ABC def");
data.setText(" ab" X "c" N "def");
KEYS("2gUU", " " X "ABC" N "DEF");
KEYS("u", " " X "abc" N "def");
KEYS("<c-r>", " " X "ABC" N "DEF");
}
void FakeVimPlugin::test_vim_code_autoindent()
{
TestData data;
setup(&data);
data.doCommand("set nopassnewline");
data.doCommand("set expandtab");
data.doCommand("set shiftwidth=3");
data.setText("int main()" N
X "{" N
"}" N
"");
KEYS("o" "return 0;",
"int main()" N
"{" N
" return 0;" X N
"}" N
"");
INTEGRITY(false);
KEYS("O" "int i = 0;",
"int main()" N
"{" N
" int i = 0;" X N
" return 0;" N
"}" N
"");
INTEGRITY(false);
KEYS("ddO" "int i = 0;" N "int j = 0;",
"int main()" N
"{" N
" int i = 0;" N
" int j = 0;" X N
" return 0;" N
"}" N
"");
KEYS("^i" "int x = 1;" N,
"int main()" N
"{" N
" int i = 0;" N
" int x = 1;" N
" " X "int j = 0;" N
" return 0;" N
"}" N
"");
KEYS("c2k" "if (true) {" N ";" N "}",
"int main()" N
"{" N
" if (true) {" N
" ;" N
" }" X N
" return 0;" N
"}" N
"");
KEYS("jci{" "return 1;",
"int main()" N
"{" N
" return 1;" X N
"}" N
"");
KEYS("di{",
"int main()" N
"{" N
X "}" N
"");
INTEGRITY(false);
// autoindent
data.doCommand("set nosmartindent");
data.setText("abc" N "def");
KEYS("3o 123<esc>", "abc" N " 123" N " 123" N " 12" X "3" N "def");
INTEGRITY(false);
data.setText("abc" N "def");
KEYS("3O 123<esc>", " 123" N " 123" N " 12" X "3" N "abc" N "def");
INTEGRITY(false);
data.doCommand("set smartindent");
}
void FakeVimPlugin::test_vim_code_folding()
{
TestData data;
setup(&data);
data.setText("int main()" N "{" N " return 0;" N "}" N "");
// fold/unfold function block
data.doKeys("zc");
QCOMPARE(data.lines(), 2);
data.doKeys("zo");
QCOMPARE(data.lines(), 5);
data.doKeys("za");
QCOMPARE(data.lines(), 2);
// delete whole block
KEYS("dd", "");
// undo/redo
KEYS("u", "int main()" N "{" N " return 0;" N "}" N "");
KEYS("<c-r>", "");
// change block
KEYS("uggzo", X "int main()" N "{" N " return 0;" N "}" N "");
KEYS("ccvoid f()<esc>", "void f(" X ")" N "{" N " return 0;" N "}" N "");
KEYS("uzc.", "void f(" X ")" N "");
// open/close folds recursively
data.setText("int main()" N
"{" N
" if (true) {" N
" return 0;" N
" } else {" N
" // comment" N
" " X "return 2" N
" }" N
"}" N
"");
int lines = data.lines();
// close else block
data.doKeys("zc");
QCOMPARE(data.lines(), lines - 3);
// close function block
data.doKeys("zc");
QCOMPARE(data.lines(), lines - 8);
// jumping to a line opens all its parent folds
data.doKeys("6gg");
QCOMPARE(data.lines(), lines);
// close recursively
data.doKeys("zC");
QCOMPARE(data.lines(), lines - 8);
data.doKeys("za");
QCOMPARE(data.lines(), lines - 3);
data.doKeys("6gg");
QCOMPARE(data.lines(), lines);
data.doKeys("zA");
QCOMPARE(data.lines(), lines - 8);
data.doKeys("za");
QCOMPARE(data.lines(), lines - 3);
// close all folds
data.doKeys("zM");
QCOMPARE(data.lines(), lines - 8);
data.doKeys("zo");
QCOMPARE(data.lines(), lines - 4);
data.doKeys("zM");
QCOMPARE(data.lines(), lines - 8);
// open all folds
data.doKeys("zR");
QCOMPARE(data.lines(), lines);
// delete folded lined if deleting to the end of the first folding line
data.doKeys("zMgg");
QCOMPARE(data.lines(), lines - 8);
KEYS("wwd$", "int main" N "");
// undo
KEYS("u", "int main" X "()" N
"{" N
" if (true) {" N
" return 0;" N
" } else {" N
" // comment" N
" return 2" N
" }" N
"}" N
"");
NOT_IMPLEMENTED
// Opening folds recursively isn't supported (previous position in fold isn't restored).
}
void FakeVimPlugin::test_vim_code_completion()
{
// Test completion by simply bypassing FakeVim and inserting text directly in editor widget.
TestData data;
setup(&data);
data.setText(
"int test1Var;" N
"int test2Var;" N
"int main() {" N
" " X ";" N
"}" N
"");
data.doKeys("i" "te");
data.completeText("st");
data.doKeys("1");
data.completeText("Var");
data.doKeys(" = 0");
KEYS("",
"int test1Var;" N
"int test2Var;" N
"int main() {" N
" test1Var = " X "0;" N
"}" N
"");
data.doKeys("o" "te");
data.completeText("st");
data.doKeys("2");
data.completeText("Var");
data.doKeys(" = 1;");
KEYS("",
"int test1Var;" N
"int test2Var;" N
"int main() {" N
" test1Var = 0;" N
" test2Var = 1" X ";" N
"}" N
"");
// repeat text insertion with completion
KEYS(".",
"int test1Var;" N
"int test2Var;" N
"int main() {" N
" test1Var = 0;" N
" test2Var = 1;" N
" test2Var = 1" X ";" N
"}" N
"");
}
void FakeVimPlugin::test_vim_substitute()
{
TestData data;
setup(&data);
data.setText("abcabc");
COMMAND("s/abc/123/", X "123abc");
COMMAND("u", X "abcabc");
COMMAND("s/abc/123/g", X "123123");
COMMAND("u", X "abcabc");
data.setText("abc" N "def");
COMMAND("%s/^/ -- /", " -- abc" N " " X "-- def");
COMMAND("u", X "abc" N "def");
data.setText(" abc" N " def");
COMMAND("%s/$/./", " abc." N " " X "def.");
data.setText("abc" N "def");
COMMAND("%s/.*/(&)", "(abc)" N X "(def)");
COMMAND("u", X "abc" N "def");
COMMAND("%s/.*/X/g", "X" N X "X");
data.setText("abc" N "" N "def");
COMMAND("%s/^\\|$/--", "--abc" N "--" N X "--def");
COMMAND("u", X "abc" N "" N "def");
COMMAND("%s/^\\|$/--/g", "--abc--" N "--" N X "--def--");
// captures
data.setText("abc def ghi");
COMMAND("s/\\w\\+/'&'/g", X "'abc' 'def' 'ghi'");
COMMAND("u", X "abc def ghi");
COMMAND("s/\\w\\+/'\\&'/g", X "'&' '&' '&'");
COMMAND("u", X "abc def ghi");
COMMAND("s/\\(\\w\\{3}\\)/(\\1)/g", X "(abc) (def) (ghi)");
COMMAND("u", X "abc def ghi");
COMMAND("s/\\(\\w\\{3}\\) \\(\\w\\{3\\}\\)/\\2 \\1 \\\\1/g", X "def abc \\1 ghi");
// case-insensitive
data.setText("abc ABC abc");
COMMAND("s/ABC/123/gi", X "123 123 123");
// replace on a line
data.setText("abc" N "def" N "ghi");
COMMAND("2s/^/ + /", "abc" N " " X "+ def" N "ghi");
COMMAND("1s/^/ * /", " " X "* abc" N " + def" N "ghi");
COMMAND("$s/^/ - /", " * abc" N " + def" N " " X "- ghi");
// replace on lines
data.setText("abc" N "def" N "ghi");
COMMAND("2,$s/^/ + /", "abc" N " + def" N " " X "+ ghi");
COMMAND("1,2s/^/ * /", " * abc" N " " X "* + def" N " + ghi");
COMMAND("3,3s/^/ - /", " * abc" N " * + def" N " " X "- + ghi");
COMMAND("%s/\\( \\S \\)*//g", "abc" N "def" N X "ghi");
// last substitution
data.setText("abc" N "def" N "ghi");
COMMAND("%s/DEF/+&/i", "abc" N X "+def" N "ghi");
COMMAND("&&", "abc" N X "++def" N "ghi");
COMMAND("&", "abc" N X "++def" N "ghi");
COMMAND("&&", "abc" N X "++def" N "ghi");
COMMAND("&i", "abc" N X "+++def" N "ghi");
COMMAND("s", "abc" N X "+++def" N "ghi");
COMMAND("&&i", "abc" N X "++++def" N "ghi");
// search for last substitute pattern
data.setText("abc" N "def" N "ghi");
COMMAND("%s/def/def", "abc" N X "def" N "ghi");
KEYS("gg", X "abc" N "def" N "ghi");
COMMAND("\\&", "abc" N X "def" N "ghi");
// substitute last selection
data.setText("abc" N "def" N "ghi" N "jkl");
KEYS("jVj:s/^/*<CR>", "abc" N "*def" N X "*ghi" N "jkl");
COMMAND("'<,'>s/^/*", "abc" N "**def" N X "**ghi" N "jkl");
KEYS("ugv:s/^/+<CR>", "abc" N "+*def" N X "+*ghi" N "jkl");
}
void FakeVimPlugin::test_vim_ex_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");
data.setText("abc" N "def");
KEYS("\"xy$", X "abc" N "def");
KEYS("\"xP", "ab" X "cabc" N "def");
}
void FakeVimPlugin::test_vim_ex_delete()
{
TestData data;
setup(&data);
data.setText("abc" N X "def" N "ghi" N "jkl");
COMMAND("d", "abc" N X "ghi" N "jkl");
COMMAND("1,2d", X "jkl");
COMMAND("u", X "abc" N "ghi" N "jkl");
COMMAND("u", "abc" N X "def" N "ghi" N "jkl");
KEYS("p", "abc" N "def" N X "abc" N "ghi" N "ghi" N "jkl");
COMMAND("set ws|" "/abc/,/ghi/d|" "set nows", X "ghi" N "jkl");
COMMAND("u", X "abc" N "def" N "abc" N "ghi" N "ghi" N "jkl");
COMMAND("2,/abc/d3", "abc" N "def" N X "jkl");
COMMAND("u", "abc" N "def" N X "abc" N "ghi" N "ghi" N "jkl");
COMMAND("5,.+1d", "abc" N "def" N "abc" N X "jkl");
}
void FakeVimPlugin::test_vim_ex_change()
{
TestData data;
setup(&data);
data.setText("abc" N X "def" N "ghi" N "jkl");
KEYS(":c<CR>xxx<ESC>0", "abc" N X "xxx" N "ghi" N "jkl");
KEYS(":-1,+1c<CR>XXX<ESC>0", X "XXX" N "jkl");
}
void FakeVimPlugin::test_vim_ex_shift()
{
TestData data;
setup(&data);
data.doCommand("set expandtab");
data.doCommand("set shiftwidth=2");
data.setText("abc" N X "def" N "ghi" N "jkl");
COMMAND(">", "abc" N " " X "def" N "ghi" N "jkl");
COMMAND(">>", "abc" N " " X "def" N "ghi" N "jkl");
COMMAND("<", "abc" N " " X "def" N "ghi" N "jkl");
COMMAND("<<", "abc" N X "def" N "ghi" N "jkl");
}
void FakeVimPlugin::test_vim_ex_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");
// move visual selection with indentation
data.doCommand("set expandtab");
data.doCommand("set shiftwidth=2");
data.doCommand("vnoremap <C-S-J> :m'>+<CR>gv=");
data.doCommand("vnoremap <C-S-K> :m-2<CR>gv=");
data.setText(
"int x;" N
"int y;" N
"int main() {" N
" if (true) {" N
" }" N
"}" N
"");
KEYS("Vj<C-S-J>",
"int main() {" N
" int x;" N
" int y;" N
" if (true) {" N
" }" N
"}" N
"");
KEYS("gv<C-S-J>",
"int main() {" N
" if (true) {" N
" int x;" N
" int y;" N
" }" N
"}" N
"");
KEYS("gv<C-S-K>",
"int main() {" N
" int x;" N
" int y;" N
" if (true) {" N
" }" N
"}" N
"");
data.doCommand("vunmap <C-S-K>");
data.doCommand("vunmap <C-S-J>");
}
void FakeVimPlugin::test_vim_ex_join()
{
TestData data;
setup(&data);
data.setText(" abc" N X " def" N " ghi" N " jkl");
COMMAND("j", " abc" N " " X "def ghi" N " jkl");
COMMAND("u", " abc" N X " def" N " ghi" N " jkl");
COMMAND("1j3", " " X "abc def ghi" N " jkl");
COMMAND("u", X " abc" N " def" N " ghi" N " jkl");
}
void FakeVimPlugin::test_advanced_commands()
{
TestData data;
setup(&data);
// subcommands
data.setText("abc" N " xxx" N " xxx" N "def");
COMMAND("%s/xxx/ZZZ/g|%s/ZZZ/OOO/g", "abc" N " OOO" N " " X "OOO" N "def");
// undo/redo all subcommands
COMMAND(":undo", "abc" N X " xxx" N " xxx" N "def");
COMMAND(":redo", "abc" N X " OOO" N " OOO" N "def");
// redundant characters
COMMAND(" ::: %s/\\S\\S\\S/ZZZ/g |"
" :: : : %s/ZZZ/XXX/g ", "XXX" N " XXX" N " XXX" N X "XXX");
// bar character in regular expression is not command separator
data.setText("abc");
COMMAND("%s/a\\|b\\||/X/g|%s/[^X]/Y/g", "XXY");
}
void FakeVimPlugin::test_map()
{
TestData data;
setup(&data);
data.setText("abc def");
data.doCommand("map C i<space>x<space><esc>");
data.doCommand("map c iXXX");
data.doCommand("imap c YYY<space>");
KEYS("C", " x" X " abc def");
data.doCommand("map C <nop>");
KEYS("C", " x" X " abc def");
data.doCommand("map C i<bs><esc><right>");
KEYS("C", " " X " abc def");
KEYS("ccc<esc>", " XXXYYY YYY" X " abc def");
// unmap
KEYS(":unmap c<cr>ccc<esc>", "YYY" X " ");
KEYS(":iunmap c<cr>ccc<esc>", X "c");
data.doCommand("unmap C");
data.setText("abc def");
data.doCommand("imap x (((<space><right><right>)))<esc>");
KEYS("x", X "bc def");
KEYS("ix", "((( bc))" X ") def");
data.doCommand("iunmap x");
data.setText("abc def");
data.doCommand("map <c-right> 3l");
KEYS("<C-Right>", "abc" X " def");
KEYS("<C-Right>", "abc de" X "f");
// map vs. noremap
data.setText("abc def");
data.doCommand("map x 3l");
data.doCommand("map X x");
KEYS("X", "abc" X " def");
data.doCommand("noremap X x");
KEYS("X", "abc" X "def");
data.doCommand("unmap X");
data.doCommand("unmap x");
// limit number of recursions in mappings
data.doCommand("map X Y");
data.doCommand("map Y Z");
data.doCommand("map Z X");
KEYS("X", "abc" X "def");
data.doCommand("map Z i<space><esc>");
KEYS("X", "abc" X " def");
data.doCommand("unmap X");
data.doCommand("unmap Y");
data.doCommand("unmap Z");
// imcomplete mapping
data.setText("abc");
data.doCommand("map Xa ia<esc>");
data.doCommand("map Xb ib<esc>");
data.doCommand("map X ic<esc>");
KEYS("Xa", X "aabc");
KEYS("Xb", X "baabc");
KEYS("Xic<esc>", X "ccbaabc");
// unmap
data.doCommand("unmap Xa");
KEYS("Xa<esc>", X "cccbaabc");
data.doCommand("unmap Xb");
KEYS("Xb", X "ccccbaabc");
data.doCommand("unmap X");
KEYS("Xb", X "ccccbaabc");
KEYS("X<esc>", X "ccccbaabc");
// recursive mapping
data.setText("abc");
data.doCommand("map X Y");
data.doCommand("map XXX i1<esc>");
data.doCommand("map Y i2<esc>");
data.doCommand("map YZ i3<esc>");
data.doCommand("map _ i <esc>");
KEYS("_XXX_", X " 1 abc");
KEYS("XX_0", X " 22 1 abc");
KEYS("XXXXZ_0", X " 31 22 1 abc");
KEYS("XXXXX_0", X " 221 31 22 1 abc");
KEYS("XXZ", X "32 221 31 22 1 abc");
data.doCommand("unmap X");
data.doCommand("unmap XXX");
data.doCommand("unmap Y");
data.doCommand("unmap YZ");
data.doCommand("unmap _");
// shift modifier
data.setText("abc");
data.doCommand("map x i1<esc>");
data.doCommand("map X i2<esc>");
KEYS("x", X "1abc");
KEYS("X", X "21abc");
data.doCommand("map <S-X> i3<esc>");
KEYS("X", X "321abc");
data.doCommand("map X i4<esc>");
KEYS("X", X "4321abc");
KEYS("x", X "14321abc");
data.doCommand("unmap x");
data.doCommand("unmap X");
// undo/redo mapped input
data.setText("abc def ghi");
data.doCommand("map X dwea xyz<esc>3l");
KEYS("X", "def xyz g" X "hi");
KEYS("u", X "abc def ghi");
KEYS("<C-r>", X "def xyz ghi");
data.doCommand("unmap X");
data.setText("abc" N " def" N " ghi");
data.doCommand("map X jdd");
KEYS("X", "abc" N " " X "ghi");
KEYS("u", "abc" N X " def" N " ghi");
KEYS("<c-r>", "abc" N X " ghi");
data.doCommand("unmap X");
data.setText("abc" N "def" N "ghi");
data.doCommand("map X jAxxx<cr>yyy<esc>");
KEYS("X", "abc" N "defxxx" N "yy" X "y" N "ghi");
KEYS("u", "abc" N "de" X "f" N "ghi");
KEYS("<c-r>", "abc" N "def" X "xxx" N "yyy" N "ghi");
data.doCommand("unmap X");
/* QTCREATORBUG-7913 */
data.setText("");
data.doCommand("noremap l k|noremap k j|noremap j h");
KEYS("ikkk<esc>", "kk" X "k");
KEYS("rj", "kk" X "j");
data.doCommand("unmap l|unmap k|unmap j");
// bad mapping
data.setText(X "abc" N "def");
data.doCommand("map X Zxx");
KEYS("X", X "abc" N "def");
// cancelled mapping
data.doCommand("map X fxxx");
KEYS("X", X "abc" N "def");
data.doCommand("map X ciXxx");
KEYS("X", X "abc" N "def");
data.doCommand("map Y Xxx");
KEYS("Y", X "abc" N "def");
data.doCommand("unmap X|unmap Y");
// correct mapping after bad one
data.setText("abc" N "def");
data.doCommand("map X Y");
data.doCommand("map Y X");
data.doCommand("map Xx xxx");
KEYS("Xr2", X "2bc" N "def");
data.doCommand("unmap X|unmap x|unmap Y");
// <C-o>
data.setText("abc def");
data.doCommand("imap X <c-o>:%s/def/xxx/<cr>");
KEYS("iX", "abc xxx");
data.doCommand("iunmap X");
// Test mappings in UTF-8 encoding.
data.setText("abc" N "def");
data.doKeys(QString::fromUtf8(":no \xc5\xaf xiX<cr>"));
KEYS("oxyz<esc>", "abc" N "xy" X "z" N "def");
KEYS(QString::fromUtf8("\xc5\xaf<esc>"), "abc" N "x" X "Xy" N "def");
/* QTCREATORBUG-8774 */
data.setText("abc" N "def");
data.doCommand(QString::fromUtf8("no \xc3\xb8 l|no l k|no k j|no j h"));
KEYS(QString::fromUtf8("\xc3\xb8"), "a" X "bc" N "def");
// Don't handle mapping in sub-modes that are not followed by movement command.
data.setText("abc" N "def");
data.doCommand("map <SPACE> A<cr>xy z<esc><left><left>");
KEYS("<space>", "abc" N "x" X "y z" N "def");
KEYS("r<space>", "abc" N "x" X " z" N "def");
KEYS("f<space>", "abc" N "x " X " z" N "def");
KEYS("t<space>", "abc" N "x " X " z" N "def");
data.doCommand("unmap <SPACE>");
}
void FakeVimPlugin::test_vim_command_cc()
{
TestData data;
setup(&data);
data.setText( "|123" N "456" N "789" N "abc");
KEYS("cc456<ESC>", "45|6" N "456" N "789" N "abc");
KEYS("ccabc<Esc>", "ab|c" N "456" N "789" N "abc");
KEYS(".", "ab|c" N "456" N "789" N "abc");
KEYS("j", "abc" N "45|6" N "789" N "abc");
KEYS(".", "abc" N "ab|c" N "789" N "abc");
KEYS("kkk", "ab|c" N "abc" N "789" N "abc");
KEYS("3ccxyz<Esc>", "xy|z" N "abc");
}
void FakeVimPlugin::test_vim_command_cw()
{
TestData data;
setup(&data);
data.setText(X "123 456");
KEYS("cwx<Esc>", X "x 456");
}
void FakeVimPlugin::test_vim_command_cj()
{
TestData data;
setup(&data);
data.setText(testLines);
KEYS("j$", cursor(1, -1));
KEYS("cj<Esc>", l[0]+"\n|" + '\n' + lmid(3));
KEYS("P", lmid(0,1)+'\n' + '|'+lmid(1,2)+'\n' + '\n' + lmid(3));
KEYS("u", l[0]+"\n|" + '\n' + lmid(3));
data.setText(testLines);
KEYS("j$", cursor(1, -1));
KEYS("cjabc<Esc>", l[0]+"\nab|c\n" + lmid(3));
KEYS("u", cursor(2, 0));
KEYS("gg", cursor(0, 0));
KEYS(".", "ab|c\n" + lmid(2));
}
void FakeVimPlugin::test_vim_command_ck()
{
TestData data;
setup(&data);
data.setText(testLines);
KEYS("j$", cursor(1, -1));
KEYS("ck<Esc>", "|\n" + lmid(2));
KEYS("P", '|' + lmid(0,2)+'\n' + '\n' + lmid(2));
}
void FakeVimPlugin::test_vim_command_c_dollar()
{
TestData data;
setup(&data);
data.setText(testLines);
KEYS("j", cursor(1, 0));
KEYS("$", cursor(1, -1));
KEYS("c$<Esc>", l[0]+'\n' + l[1].left(l[1].length()-2)+'|'+l[1][l[1].length()-2]+'\n' + lmid(2));
KEYS("c$<Esc>", l[0]+'\n' + l[1].left(l[1].length()-3)+'|'+l[1][l[1].length()-3]+'\n' + lmid(2));
KEYS("0c$abc<Esc>", l[0]+'\n' + "ab|c\n" + lmid(2));
KEYS("0c$abc<Esc>", l[0]+'\n' + "ab|c\n" + lmid(2));
}
void FakeVimPlugin::test_vim_command_C()
{
TestData data;
setup(&data);
data.setText(testLines);
KEYS("j", cursor(1, 0));
KEYS("Cabc<Esc>", l[0] + "\nab|c\n" + lmid(2));
KEYS("Cabc<Esc>", l[0] + "\nabab|c\n" + lmid(2));
KEYS("$Cabc<Esc>", l[0] + "\nababab|c\n" + lmid(2));
KEYS("0C<Esc>", l[0] + "\n|\n" + lmid(2));
KEYS("0Cabc<Esc>", l[0] + "\nab|c\n" + lmid(2));
}
void FakeVimPlugin::test_vim_command_dw()
{
TestData data;
setup(&data);
data.setText(testLines);
KEYS("dw", "|#include <QtCore>\n" + lmid(2));
KEYS("dw", "|include <QtCore>\n" + lmid(2));
KEYS("dw", "|<QtCore>\n" + lmid(2));
KEYS("dw", "|QtCore>\n" + lmid(2));
KEYS("dw", "|>\n" + lmid(2));
KEYS("dw", "|\n" + lmid(2)); // Real vim has this intermediate step, too
KEYS("dw", "|#include <QtGui>\n" + lmid(3));
KEYS("dw", "|include <QtGui>\n" + lmid(3));
KEYS("dw", "|<QtGui>\n" + lmid(3));
KEYS("dw", "|QtGui>\n" + lmid(3));
KEYS("dw", "|>\n" + lmid(3));
}
void FakeVimPlugin::test_vim_command_dd()
{
TestData data;
setup(&data);
data.setText(testLines);
KEYS("j", cursor(1, 0));
KEYS("dd", l[0] + "\n|" + lmid(2));
KEYS(".", l[0] + "\n|" + lmid(3));
KEYS("3dd", l[0] + "\n |QApplication app(argc, argv);\n" + lmid(7));
KEYS("4l", l[0] + "\n QApp|lication app(argc, argv);\n" + lmid(7));
KEYS("dd", l[0] + "\n|" + lmid(7));
KEYS(".", l[0] + "\n |return app.exec();\n" + lmid(9));
KEYS("dd", l[0] + "\n|" + lmid(9));
}
void FakeVimPlugin::test_vim_command_dd_2()
{
TestData data;
setup(&data);
data.setText(testLines);
KEYS("j", cursor(1, 0));
KEYS("dd", l[0] + "\n|" + lmid(2));
KEYS("p", l[0] + '\n' + l[2] + "\n|" + l[1] + '\n' + lmid(3));
KEYS("u", l[0] + "\n|" + lmid(2));
}
void FakeVimPlugin::test_vim_command_d_dollar()
{
TestData data;
setup(&data);
data.setText(testLines);
KEYS("j$", cursor(1, -1));
KEYS("$d$", l[0]+'\n' + l[1].left(l[1].length()-2)+'|'+l[1][l[1].length()-2]+'\n' + lmid(2));
KEYS("0d$", l[0] + '\n'+"|\n" + lmid(2));
}
void FakeVimPlugin::test_vim_command_dj()
{
TestData data;
setup(&data);
data.setText(testLines);
KEYS("j$", cursor(1, -1));
KEYS("dj", l[0]+"\n|" + lmid(3));
KEYS("P", lmid(0,1)+'\n' + '|'+lmid(1));
KEYS("0", lmid(0,1)+'\n' + '|'+lmid(1));
KEYS("dj", l[0]+"\n|" + lmid(3));
KEYS("P", lmid(0,1)+'\n' + '|'+lmid(1));
KEYS("05l", l[0]+'\n' + l[1].left(5) + '|' + l[1].mid(5)+'\n' + lmid(2));
KEYS("dj", l[0]+"\n|" + lmid(3));
KEYS("P", lmid(0,1)+'\n' + '|'+lmid(1));
KEYS("dj", l[0]+"\n|" + lmid(3));
KEYS("p", lmid(0,1)+'\n' + lmid(3,1)+'\n' + '|'+lmid(1,2)+'\n' + lmid(4));
}
void FakeVimPlugin::test_vim_command_dk()
{
TestData data;
setup(&data);
data.setText(testLines);
KEYS("j$", cursor(1, -1));
KEYS("dk", '|' + lmid(2));
KEYS("P", '|' + lmid(0));
KEYS("j0", l[0]+ "\n|" + lmid(1));
KEYS("dk", '|' + lmid(2));
KEYS("P", '|' + lmid(0));
KEYS("j05l", l[0]+'\n' + l[1].left(5) + '|' + l[1].mid(5)+'\n' + lmid(2));
KEYS("dk", '|' + lmid(2));
KEYS("P", '|' + lmid(0));
KEYS("j05l", l[0]+'\n' + l[1].left(5) + '|' + l[1].mid(5)+'\n' + lmid(2));
KEYS("dk", '|' + lmid(2));
KEYS("p", lmid(2,1)+'\n' + '|' + lmid(0,2)+'\n' + lmid(3));
}
void FakeVimPlugin::test_vim_command_dgg()
{
TestData data;
setup(&data);
data.setText(testLines);
KEYS("G", lmid(0, l.size()-2)+'\n' + '|'+lmid(l.size()-2));
KEYS("dgg", "|");
KEYS("u", '|' + lmid(0));
}
void FakeVimPlugin::test_vim_command_dG()
{
TestData data;
setup(&data);
data.setText(testLines);
KEYS("dG", "|");
KEYS("u", '|' + lmid(0));
KEYS("j", cursor(1, 0));
KEYS("dG", lmid(0,1)+'\n' + '|');
KEYS("u", l[0]+'\n' + '|' + lmid(1));
KEYS("G", lmid(0, l.size()-2)+'\n' + '|'+lmid(l.size()-2));
NOT_IMPLEMENTED
// include movement to first column, as otherwise the result depends on the 'startofline' setting
KEYS("dG0", lmid(0, l.size()-2)+'\n' + '|'+lmid(l.size()-2,1));
KEYS("dG0", lmid(0, l.size()-3)+'\n' + '|'+lmid(l.size()-3,1));
}
void FakeVimPlugin::test_vim_command_D()
{
TestData data;
setup(&data);
data.setText(testLines);
KEYS("j", cursor(1, 0));
KEYS("$D", l[0]+'\n' + l[1].left(l[1].length()-2)+'|'+l[1][l[1].length()-2]+'\n' + lmid(2));
KEYS("0D", l[0] + "\n|\n" + lmid(2));
}
void FakeVimPlugin::test_vim_command_dollar()
{
TestData data;
setup(&data);
data.setText(testLines);
KEYS("j$", cursor(1, -1));
KEYS("j$", cursor(2, -1));
KEYS("2j", cursor(4, -1));
}
void FakeVimPlugin::test_vim_command_down()
{
TestData data;
setup(&data);
data.setText(testLines);
KEYS("j", l[0]+ "\n|" + lmid(1));
KEYS("3j", lmid(0,4)+'\n' + "|int main(int argc, char *argv[])\n" + lmid(5));
KEYS("4j", lmid(0,8)+'\n' + "| return app.exec();\n" + lmid(9));
}
void FakeVimPlugin::test_vim_command_dfx_down()
{
TestData data;
setup(&data);
data.setText(testLines);
KEYS("j4l", l[0] + "\n#inc|lude <QtCore>\n" + lmid(2));
//NOT_IMPLEMENTED
KEYS("df ", l[0] + "\n#inc|<QtCore>\n" + lmid(2));
KEYS("j", l[0] + "\n#inc<QtCore>\n#inc|lude <QtGui>\n" + lmid(3));
KEYS(".", l[0] + "\n#inc<QtCore>\n#inc|<QtGui>\n" + lmid(3));
KEYS("u", l[0] + "\n#inc<QtCore>\n#inc|lude <QtGui>\n" + lmid(3));
KEYS("u", l[0] + "\n#inc|lude <QtCore>\n" + lmid(2));
}
void FakeVimPlugin::test_vim_command_Cxx_down_dot()
{
TestData data;
setup(&data);
data.setText(testLines);
KEYS("j4l", l[0] + "\n#inc|lude <QtCore>\n" + lmid(2));
KEYS("Cxx<Esc>", l[0] + "\n#incx|x\n" + lmid(2));
KEYS("j", l[0] + "\n#incxx\n#incl|ude <QtGui>\n" + lmid(3));
KEYS(".", l[0] + "\n#incxx\n#inclx|x\n" + lmid(3));
}
void FakeVimPlugin::test_vim_command_e()
{
TestData data;
setup(&data);
data.setText(testLines);
KEYS("e", lmid(0,1)+'\n' + "|#include <QtCore>\n" + lmid(2));
KEYS("e", lmid(0,1)+'\n' + "#includ|e <QtCore>\n" + lmid(2));
KEYS("e", lmid(0,1)+'\n' + "#include |<QtCore>\n" + lmid(2));
KEYS("3e", lmid(0,2)+'\n' + "|#include <QtGui>\n" + lmid(3));
KEYS("e", lmid(0,2)+'\n' + "#includ|e <QtGui>\n" + lmid(3));
KEYS("e", lmid(0,2)+'\n' + "#include |<QtGui>\n" + lmid(3));
KEYS("e", lmid(0,2)+'\n' + "#include <QtGu|i>\n" + lmid(3));
KEYS("4e", lmid(0,4)+'\n' + "int main|(int argc, char *argv[])\n" + lmid(5));
KEYS("e", lmid(0,4)+'\n' + "int main(in|t argc, char *argv[])\n" + lmid(5));
KEYS("e", lmid(0,4)+'\n' + "int main(int arg|c, char *argv[])\n" + lmid(5));
KEYS("e", lmid(0,4)+'\n' + "int main(int argc|, char *argv[])\n" + lmid(5));
KEYS("e", lmid(0,4)+'\n' + "int main(int argc, cha|r *argv[])\n" + lmid(5));
KEYS("e", lmid(0,4)+'\n' + "int main(int argc, char |*argv[])\n" + lmid(5));
KEYS("e", lmid(0,4)+'\n' + "int main(int argc, char *arg|v[])\n" + lmid(5));
KEYS("e", lmid(0,4)+'\n' + "int main(int argc, char *argv[]|)\n" + lmid(5));
KEYS("e", lmid(0,5)+'\n' + "|{\n" + lmid(6));
KEYS("10k","|\n" + lmid(1)); // home.
}
void FakeVimPlugin::test_vim_command_i()
{
TestData data;
setup(&data);
data.setText(testLines);
// empty insertion at start of document
KEYS("i<Esc>", '|' + testLines);
KEYS("u", '|' + testLines);
// small insertion at start of document
KEYS("ix<Esc>", "|x" + testLines);
KEYS("u", '|' + testLines);
COMMAND("redo", "|x" + testLines);
KEYS("u", '|' + testLines);
// small insertion at start of document
KEYS("ixxx<Esc>", "xx|x" + testLines);
KEYS("u", '|' + testLines);
// combine insertions
KEYS("i1<Esc>", "|1" + testLines);
KEYS("i2<Esc>", "|21" + testLines);
KEYS("i3<Esc>", "|321" + testLines);
KEYS("u", "|21" + testLines);
KEYS("u", "|1" + testLines);
KEYS("u", '|' + testLines);
KEYS("ia<Esc>", "|a" + testLines);
KEYS("ibx<Esc>", "b|xa" + testLines);
KEYS("icyy<Esc>", "bcy|yxa" + testLines);
KEYS("u", "b|xa" + testLines);
KEYS("u", "|a" + testLines);
COMMAND("redo", "|bxa" + testLines);
KEYS("u", "|a" + testLines);
}
void FakeVimPlugin::test_vim_command_left()
{
TestData data;
setup(&data);
data.setText(testLines);
KEYS("4j", lmid(0, 4) + "\n|int main(int argc, char *argv[])\n" + lmid(5));
KEYS("h", lmid(0, 4) + "\n|int main(int argc, char *argv[])\n" + lmid(5));
KEYS("$", lmid(0, 4) + "\nint main(int argc, char *argv[]|)\n" + lmid(5));
KEYS("h", lmid(0, 4) + "\nint main(int argc, char *argv[|])\n" + lmid(5));
KEYS("3h", lmid(0, 4) + "\nint main(int argc, char *ar|gv[])\n" + lmid(5));
KEYS("50h", lmid(0, 4) + "\n|int main(int argc, char *argv[])\n" + lmid(5));
}
void FakeVimPlugin::test_vim_command_r()
{
TestData data;
setup(&data);
data.setText(testLines);
KEYS("4j", lmid(0, 4) + "\n|int main(int argc, char *argv[])\n" + lmid(5));
KEYS("$", lmid(0, 4) + "\nint main(int argc, char *argv[]|)\n" + lmid(5));
KEYS("rx", lmid(0, 4) + "\nint main(int argc, char *argv[]|x\n" + lmid(5));
KEYS("2h", lmid(0, 4) + "\nint main(int argc, char *argv|[]x\n" + lmid(5));
KEYS("4ra", lmid(0, 4) + "\nint main(int argc, char *argv|[]x\n" + lmid(5));
KEYS("3rb", lmid(0, 4) + "\nint main(int argc, char *argvbb|b\n" + lmid(5));
KEYS("2rc", lmid(0, 4) + "\nint main(int argc, char *argvbb|b\n" + lmid(5));
KEYS("h2rc",lmid(0, 4) + "\nint main(int argc, char *argvbc|c\n" + lmid(5));
}
void FakeVimPlugin::test_vim_command_right()
{
TestData data;
setup(&data);
data.setText(testLines);
KEYS("4j", lmid(0, 4) + "\n|int main(int argc, char *argv[])\n" + lmid(5));
KEYS("l", lmid(0, 4) + "\ni|nt main(int argc, char *argv[])\n" + lmid(5));
KEYS("3l", lmid(0, 4) + "\nint |main(int argc, char *argv[])\n" + lmid(5));
KEYS("50l", lmid(0, 4) + "\nint main(int argc, char *argv[]|)\n" + lmid(5));
}
void FakeVimPlugin::test_vim_command_up()
{
TestData data;
setup(&data);
data.setText(testLines);
KEYS("9j", lmid(0, 9) + "\n|}\n");
KEYS("k", lmid(0, 8) + "\n| return app.exec();\n" + lmid(9));
KEYS("4k", lmid(0, 4) + "\n|int main(int argc, char *argv[])\n" + lmid(5));
KEYS("3k", lmid(0, 1) + "\n|#include <QtCore>\n" + lmid(2));
KEYS("k", cursor(0, 0));
KEYS("2k", cursor(0, 0));
}
void FakeVimPlugin::test_vim_command_w()
{
TestData data;
setup(&data);
data.setText(testLines);
KEYS("w", lmid(0,1)+'\n' + "|#include <QtCore>\n" + lmid(2));
KEYS("w", lmid(0,1)+'\n' + "#|include <QtCore>\n" + lmid(2));
KEYS("w", lmid(0,1)+'\n' + "#include |<QtCore>\n" + lmid(2));
KEYS("3w", lmid(0,2)+'\n' + "|#include <QtGui>\n" + lmid(3));
KEYS("w", lmid(0,2)+'\n' + "#|include <QtGui>\n" + lmid(3));
KEYS("w", lmid(0,2)+'\n' + "#include |<QtGui>\n" + lmid(3));
KEYS("w", lmid(0,2)+'\n' + "#include <|QtGui>\n" + lmid(3));
KEYS("4w", lmid(0,4)+'\n' + "int |main(int argc, char *argv[])\n" + lmid(5));
KEYS("w", lmid(0,4)+'\n' + "int main|(int argc, char *argv[])\n" + lmid(5));
KEYS("w", lmid(0,4)+'\n' + "int main(|int argc, char *argv[])\n" + lmid(5));
KEYS("w", lmid(0,4)+'\n' + "int main(int |argc, char *argv[])\n" + lmid(5));
KEYS("w", lmid(0,4)+'\n' + "int main(int argc|, char *argv[])\n" + lmid(5));
KEYS("w", lmid(0,4)+'\n' + "int main(int argc, |char *argv[])\n" + lmid(5));
KEYS("w", lmid(0,4)+'\n' + "int main(int argc, char |*argv[])\n" + lmid(5));
KEYS("w", lmid(0,4)+'\n' + "int main(int argc, char *|argv[])\n" + lmid(5));
KEYS("w", lmid(0,4)+'\n' + "int main(int argc, char *argv|[])\n" + lmid(5));
KEYS("w", lmid(0,5)+'\n' + "|{\n" + lmid(6));
}
void FakeVimPlugin::test_vim_command_yyp()
{
TestData data;
setup(&data);
data.setText(testLines);
KEYS("4j", lmid(0, 4) + "\n|int main(int argc, char *argv[])\n" + lmid(5));
KEYS("yyp", lmid(0, 4) + '\n' + lmid(4, 1) + "\n|" + lmid(4));
}
void FakeVimPlugin::test_vim_command_y_dollar()
{
TestData data;
setup(&data);
data.setText(testLines);
KEYS("j", l[0]+"\n|" + lmid(1));
KEYS("$y$p", l[0]+'\n'+ l[1]+"|>\n" + lmid(2));
KEYS("$y$p", l[0]+'\n'+ l[1]+">|>\n" + lmid(2));
KEYS("$y$P", l[0]+'\n'+ l[1]+">|>>\n" + lmid(2));
KEYS("$y$P", l[0]+'\n'+ l[1]+">>|>>\n" + lmid(2));
}
void FakeVimPlugin::test_vim_command_Yp()
{
TestData data;
setup(&data);
data.setText(testLines);
KEYS("4j", lmid(0, 4) + "\n|int main(int argc, char *argv[])\n" + lmid(5));
KEYS("Yp", lmid(0, 4) + '\n' + lmid(4, 1) + "\n|" + lmid(4));
}
void FakeVimPlugin::test_vim_command_ma_yank()
{
TestData data;
setup(&data);
data.setText(testLines);
KEYS("4j", lmid(0, 4) + "\n|int main(int argc, char *argv[])\n" + lmid(5));
KEYS("ygg", '|' + lmid(0));
KEYS("4j", lmid(0, 4) + "\n|int main(int argc, char *argv[])\n" + lmid(5));
KEYS("p", lmid(0,5) + "\n|" + lmid(0,4) +'\n' + lmid(4));
data.setText(testLines);
KEYS("gg", '|' + lmid(0));
KEYS("ma", '|' + lmid(0));
KEYS("4j", lmid(0, 4) + "\n|int main(int argc, char *argv[])\n" + lmid(5));
KEYS("mb", lmid(0,4) + "\n|" + lmid(4));
KEYS("\"ay'a", '|' + lmid(0));
KEYS("'b", lmid(0,4) + "\n|" + lmid(4));
KEYS("\"ap", lmid(0,5) + "\n|" + lmid(0,4) +'\n' + lmid(4));
}
void FakeVimPlugin::test_vim_command_Gyyp()
{
TestData data;
setup(&data);
data.setText(testLines);
KEYS("G", lmid(0, l.size()-2) + "\n|" + lmid(l.size()-2));
KEYS("yyp", lmid(0) + '|' + lmid(9, 1)+'\n');
}
void FakeVimPlugin::test_i_cw_i()
{
TestData data;
setup(&data);
data.setText(testLines);
KEYS("j", l[0] + "\n|" + lmid(1));
KEYS("ixx<Esc>", l[0] + "\nx|x" + lmid(1));
KEYS("cwyy<Esc>", l[0] + "\nxy|y" + lmid(1));
KEYS("iaa<Esc>", l[0] + "\nxya|ay" + lmid(1));
}
void FakeVimPlugin::test_vim_command_J()
{
TestData data;
setup(&data);
data.setText(testLines);
KEYS("4j4l", lmid(0, 4) + "\nint |main(int argc, char *argv[])\n" + lmid(5));
KEYS("J", lmid(0, 5) + "| " + lmid(5));
KEYS("u", lmid(0, 4) + "\nint |main(int argc, char *argv[])\n" + lmid(5));
COMMAND("redo", lmid(0, 4) + "\nint |main(int argc, char *argv[]) " + lmid(5));
KEYS("3J", lmid(0, 5) + " " + lmid(5, 1) + " " + lmid(6, 1).mid(4) + "| " + lmid(7));
KEYS("uu", lmid(0, 4) + "\nint |main(int argc, char *argv[])\n" + lmid(5));
COMMAND("redo", lmid(0, 4) + "\nint |main(int argc, char *argv[]) " + lmid(5));
}
void FakeVimPlugin::test_vim_command_put_at_eol()
{
TestData data;
setup(&data);
data.setText(testLines);
KEYS("j$", cursor(1, -1));
KEYS("y$", cursor(1, -1));
KEYS("p", lmid(0,2)+"|>\n" + lmid(2));
KEYS("p", lmid(0,2)+">|>\n" + lmid(2));
KEYS("$", lmid(0,2)+">|>\n" + lmid(2));
KEYS("P", lmid(0,2)+">|>>\n" + lmid(2));
}
void FakeVimPlugin::test_vim_command_oO()
{
TestData data;
setup(&data);
data.setText(testLines);
KEYS("gg", '|' + lmid(0));
KEYS("Ol1<Esc>", "l|1\n" + lmid(0));
KEYS("gg", "|l1\n" + lmid(0));
KEYS("ol2<Esc>", "l1\n" "l|2\n" + lmid(0));
KEYS("G", "l1\n" "l2\n" + lmid(0,l.size()-2)+'\n' + '|'+lmid(l.size()-2));
KEYS("G$", "l1\n" "l2\n" + lmid(0,l.size()-2)+'\n' + '|'+lmid(l.size()-2));
KEYS("ol-1<Esc>", "l1\n" "l2\n" + lmid(0) + "l-|1\n");
KEYS("G", "l1\n" "l2\n" + lmid(0) + "|l-1\n");
KEYS("Ol-2<Esc>", "l1\n" "l2\n" + lmid(0) + "l-|2\n" + "l-1\n");
}
void FakeVimPlugin::test_vim_command_x()
{
TestData data;
setup(&data);
data.setText(testLines);
KEYS("x", '|' + lmid(0));
KEYS("j$", cursor(1, -1));
KEYS("x", lmid(0,1)+'\n' + l[1].left(l[1].length()-2)+'|'+l[1].mid(l[1].length()-2,1)+'\n' + lmid(2));
}
void FakeVimPlugin::test_vim_visual_d()
{
TestData data;
setup(&data);
data.setText(testLines);
KEYS("vd", '|' + lmid(1));
KEYS("u", '|' + lmid(0));
KEYS("vx", '|' + lmid(1));
KEYS("u", '|' + lmid(0));
KEYS("vjd", '|' + lmid(1).mid(1));
KEYS("u", '|' + lmid(0));
KEYS("j", lmid(0, 1)+'\n' + '|' + lmid(1));
KEYS("vd", lmid(0, 1)+'\n' + '|' + lmid(1).mid(1));
KEYS("u", lmid(0, 1)+'\n' + '|' + lmid(1));
KEYS("vx", lmid(0, 1)+'\n' + '|' + lmid(1).mid(1));
KEYS("u", lmid(0, 1)+'\n' + '|' + lmid(1));
KEYS("vhx", lmid(0, 1)+'\n' + '|' + lmid(1).mid(1));
KEYS("u", lmid(0, 1)+'\n' + '|' + lmid(1));
KEYS("vlx", lmid(0, 1)+'\n' + '|' + lmid(1).mid(2));
KEYS("P", lmid(0, 1)+'\n' + lmid(1).left(1)+'|'+lmid(1).mid(1));
KEYS("vhd", lmid(0, 1)+'\n' + '|' + lmid(1).mid(2));
KEYS("u", lmid(0, 1)+'\n' + '|' + lmid(1));
KEYS("v$d", lmid(0, 1)+'\n' + '|' + lmid(2));
KEYS("v$od", lmid(0, 1)+'\n' + '|' + lmid(3));
KEYS("$v$x", lmid(0, 1)+'\n' + lmid(3,1) + '|' + lmid(4));
KEYS("0v$d", lmid(0, 1)+'\n' + '|' + lmid(5));
KEYS("$v0d", lmid(0, 1)+'\n' + "|\n" + lmid(6));
KEYS("v$o0k$d", '|' + lmid(6));
}
void FakeVimPlugin::test_vim_Visual_d()
{
TestData data;
setup(&data);
data.setText(testLines);
KEYS("Vd", '|' + lmid(1));
KEYS("V2kd", '|' + lmid(2));
KEYS("u", '|' + lmid(1));
KEYS("u", '|' + lmid(0));
KEYS("j", lmid(0,1)+'\n' + '|' + lmid(1));
KEYS("V$d", lmid(0,1)+'\n' + '|' + lmid(2));
KEYS("$V$$d", lmid(0,1)+'\n' + '|' + lmid(3));
KEYS("Vkx", '|' + lmid(4));
KEYS("P", '|' + lmid(0,1)+'\n' + lmid(3));
}
void FakeVimPlugin::test_macros()
{
TestData data;
setup(&data);
// execute register content
data.setText("r1" N "r2r3");
KEYS("\"xy$", X "r1" N "r2r3");
KEYS("@x", X "11" N "r2r3");
INTEGRITY(false);
data.doKeys("j\"xy$");
KEYS("@x", "11" N X "32r3");
INTEGRITY(false);
data.setText("3<C-A>");
KEYS("\"xy$", X "3<C-A>");
KEYS("@x", X "6<C-A>");
KEYS("@x", X "9<C-A>");
KEYS("2@x", "1" X "5<C-A>");
KEYS("2@@", "2" X "1<C-A>");
KEYS("@@", "2" X "4<C-A>");
// Raw characters for macro recording.
#define ESC "\x1b"
#define ENTER "\n"
// record
data.setText("abc" N "def");
KEYS("qx" "A" ENTER "- xyz" ESC "rZjI- opq" ENTER ESC "q" , "abc" N "- xyZ" N "- opq" N X "def");
KEYS("@x" , "abc" N "- xyZ" N "- opq" N "def" N "- opq" N X "- xyZ");
data.setText(" 1 2 3" N " 4 5 6" N " 7 8 9");
KEYS("qx" "wrXj" "q", " X 2 3" N " 4 5 6" N " 7 8 9");
KEYS("2@x", " X 2 3" N " 4 X 6" N " 7 8 X");
data.setText("abc" N "def");
KEYS("qx<right>i<right> xyz <esc>q", "ab xyz" X " c" N "def");
KEYS("j0@x", "ab xyz c" N "de xyz" X " f");
data.setText("abc" N "def");
data.doCommand("unmap <S-down>");
KEYS("qx<S-down><esc>q", X "abc" N "def");
data.doCommand("noremap <S-down> ddp");
KEYS("@x", "def" N X "abc");
KEYS("gg@x", "abc" N X "def");
data.doCommand("unmap <S-down>");
}