diff --git a/.reviewboardrc b/.reviewboardrc
deleted file mode 100644
index c1d7dfe9..00000000
--- a/.reviewboardrc
+++ /dev/null
@@ -1,4 +0,0 @@
-REVIEWBOARD_URL = "https://git.reviewboard.kde.org"
-REPOSITORY = 'git://anongit.kde.org/ktexteditor'
-BRANCH = 'master'
-TARGET_GROUPS = 'kate'
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 60450c72..56e48a2d 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -1,122 +1,122 @@
cmake_minimum_required(VERSION 3.0)
-set(KF5_VERSION "5.42.0") # handled by release scripts
-set(KF5_DEP_VERSION "5.41.0") # handled by release scripts
+set(KF5_VERSION "5.50.0") # handled by release scripts
+set(KF5_DEP_VERSION "5.49.0") # handled by release scripts
project(KTextEditor VERSION ${KF5_VERSION})
# ECM setup
include(FeatureSummary)
-find_package(ECM 5.41.0 NO_MODULE)
+find_package(ECM 5.49.0 NO_MODULE)
set_package_properties(ECM PROPERTIES TYPE REQUIRED DESCRIPTION "Extra CMake Modules." URL "https://projects.kde.org/projects/kdesupport/extra-cmake-modules")
feature_summary(WHAT REQUIRED_PACKAGES_NOT_FOUND FATAL_ON_MISSING_REQUIRED_PACKAGES)
# add own modules to search path, too
set(CMAKE_MODULE_PATH ${ECM_MODULE_PATH} ${ECM_KDE_MODULE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/cmake)
include(ECMSetupVersion)
include(ECMGenerateHeaders)
include(CMakePackageConfigHelpers)
include(CheckFunctionExists)
include(CheckSymbolExists)
include(KDEInstallDirs)
include(KDEFrameworkCompilerSettings NO_POLICY_SCOPE)
include(KDECMakeSettings)
include(KDEPackageAppTemplates)
include(GenerateExportHeader)
include(ECMAddQch)
option(BUILD_QCH "Build API documentation in QCH format (for e.g. Qt Assistant, Qt Creator & KDevelop)" OFF)
add_feature_info(QCH ${BUILD_QCH} "API documentation in QCH format (for e.g. Qt Assistant, Qt Creator & KDevelop)")
ecm_setup_version(
PROJECT
VARIABLE_PREFIX KTEXTEDITOR
VERSION_HEADER "${CMAKE_CURRENT_BINARY_DIR}/ktexteditor_version.h"
PACKAGE_VERSION_FILE "${CMAKE_CURRENT_BINARY_DIR}/KF5TextEditorConfigVersion.cmake"
SOVERSION 5
)
# Dependencies
-set(REQUIRED_QT_VERSION 5.7.0)
+set(REQUIRED_QT_VERSION 5.8.0)
# Required Qt5 components to build this framework
find_package(Qt5 ${REQUIRED_QT_VERSION} NO_MODULE REQUIRED Core Widgets Qml
PrintSupport Xml XmlPatterns)
find_package(KF5Archive ${KF5_DEP_VERSION} REQUIRED)
find_package(KF5Config ${KF5_DEP_VERSION} REQUIRED)
find_package(KF5GuiAddons ${KF5_DEP_VERSION} REQUIRED)
find_package(KF5I18n ${KF5_DEP_VERSION} REQUIRED)
find_package(KF5KIO ${KF5_DEP_VERSION} REQUIRED)
find_package(KF5Parts ${KF5_DEP_VERSION} REQUIRED)
find_package(KF5Sonnet ${KF5_DEP_VERSION} REQUIRED)
find_package(KF5IconThemes ${KF5_DEP_VERSION} REQUIRED)
find_package(KF5SyntaxHighlighting ${KF5_DEP_VERSION} REQUIRED)
# libgit2 integration, at least 0.22 with proper git_libgit2_init()
find_package(LibGit2 "0.22.0")
# EditorConfig integration
find_package(EditorConfig)
# vi mode on per default
option (BUILD_VIMODE "Build vimode in" ON)
# Subdirectories
add_definitions(-DTRANSLATION_DOMAIN=\"ktexteditor5\")
if (IS_DIRECTORY "${CMAKE_CURRENT_SOURCE_DIR}/po")
ki18n_install(po)
endif()
add_subdirectory(src)
if (BUILD_TESTING)
add_subdirectory(autotests)
endif()
add_subdirectory(templates)
# Create a Config.cmake and a ConfigVersion.cmake file and install them
set(CMAKECONFIG_INSTALL_DIR "${KDE_INSTALL_CMAKEPACKAGEDIR}/KF5TextEditor")
if (BUILD_QCH)
ecm_install_qch_export(
TARGETS KF5TextEditor_QCH
FILE KF5TextEditorQchTargets.cmake
DESTINATION "${CMAKECONFIG_INSTALL_DIR}"
COMPONENT Devel
)
set(PACKAGE_INCLUDE_QCHTARGETS "include(\"\${CMAKE_CURRENT_LIST_DIR}/KF5TextEditorQchTargets.cmake\")")
endif()
configure_package_config_file(
"${CMAKE_CURRENT_SOURCE_DIR}/KF5TextEditorConfig.cmake.in"
"${CMAKE_CURRENT_BINARY_DIR}/KF5TextEditorConfig.cmake"
INSTALL_DESTINATION "${CMAKECONFIG_INSTALL_DIR}"
)
install(FILES
"${CMAKE_CURRENT_BINARY_DIR}/KF5TextEditorConfig.cmake"
"${CMAKE_CURRENT_BINARY_DIR}/KF5TextEditorConfigVersion.cmake"
DESTINATION "${CMAKECONFIG_INSTALL_DIR}"
COMPONENT Devel
)
install(EXPORT
KF5TextEditorTargets
DESTINATION "${CMAKECONFIG_INSTALL_DIR}"
FILE KF5TextEditorTargets.cmake
NAMESPACE KF5::
)
install(FILES
"${CMAKE_CURRENT_BINARY_DIR}/ktexteditor_version.h"
DESTINATION "${KDE_INSTALL_INCLUDEDIR_KF5}"
COMPONENT Devel
)
# config.h
check_symbol_exists (fdatasync unistd.h HAVE_FDATASYNC)
configure_file (config.h.cmake ${CMAKE_CURRENT_BINARY_DIR}/config.h)
# let our config.h be found first in any case
include_directories (BEFORE ${CMAKE_CURRENT_BINARY_DIR})
feature_summary(WHAT ALL FATAL_ON_MISSING_REQUIRED_PACKAGES)
diff --git a/autotests/input/indent/cppstyle/quote1/expected b/autotests/input/indent/cppstyle/quote1/expected
index f2b75f2b..1c2ecd22 100644
--- a/autotests/input/indent/cppstyle/quote1/expected
+++ b/autotests/input/indent/cppstyle/quote1/expected
@@ -1 +1,2 @@
+auto a = "R"
auto a = R"~(ok)~"
diff --git a/autotests/input/indent/cppstyle/quote1/input.js b/autotests/input/indent/cppstyle/quote1/input.js
index 263b83d6..6ee85d40 100644
--- a/autotests/input/indent/cppstyle/quote1/input.js
+++ b/autotests/input/indent/cppstyle/quote1/input.js
@@ -1,3 +1,5 @@
-v.setCursorPosition(0, 10);
+v.setCursorPosition(0, 11);
+v.type('"');
+v.setCursorPosition(1, 10);
v.type('"');
v.type("ok");
diff --git a/autotests/input/indent/cppstyle/quote1/origin b/autotests/input/indent/cppstyle/quote1/origin
index 1f8ca1fb..a41ba614 100644
--- a/autotests/input/indent/cppstyle/quote1/origin
+++ b/autotests/input/indent/cppstyle/quote1/origin
@@ -1 +1,2 @@
+auto a = "R
auto a = R
diff --git a/autotests/input/modelines.txt b/autotests/input/modelines.txt
new file mode 100644
index 00000000..6872d541
--- /dev/null
+++ b/autotests/input/modelines.txt
@@ -0,0 +1 @@
+modeline test, see katedocument_test.cpp testModelines()
diff --git a/autotests/input/syntax/cpp/results/preprocessor-bug363280.cpp.reference.html b/autotests/input/syntax/cpp/results/preprocessor-bug363280.cpp.reference.html
index 9b25c373..8e04f0ef 100644
--- a/autotests/input/syntax/cpp/results/preprocessor-bug363280.cpp.reference.html
+++ b/autotests/input/syntax/cpp/results/preprocessor-bug363280.cpp.reference.html
@@ -1,22 +1,22 @@
preprocessor-bug363280.cpp
-#if 1
+#if 1
int x; // variable shall not be grey
#endif
-#if defined (A)
+#if defined (A)
int y; // variable shall not be grey
-#elif defined (B)
+#elif defined (B)
int z; // variable shall not be grey
-#endif
+#endif
diff --git a/autotests/src/bug205447.h b/autotests/src/bug205447.h
index 98c27a95..3cbb7fb6 100644
--- a/autotests/src/bug205447.h
+++ b/autotests/src/bug205447.h
@@ -1,41 +1,41 @@
/* This file is part of the KDE libraries
Copyright (C) 2015 Zoe Clifford
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public License
along with this library; see the file COPYING.LIB. If not, write to
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02110-1301, USA.
*/
#ifndef KATE_BUG_205447_TEST_H
#define KATE_BUG_205447_TEST_H
-#include
+#include
class BugTest : public QObject
{
Q_OBJECT
public:
BugTest();
~BugTest();
private Q_SLOTS:
void initTestCase();
void cleanupTestCase();
void deleteSurrogates();
void backspaceSurrogates();
};
#endif
diff --git a/autotests/src/bug286887.h b/autotests/src/bug286887.h
index 602f2cd8..71142aec 100644
--- a/autotests/src/bug286887.h
+++ b/autotests/src/bug286887.h
@@ -1,40 +1,40 @@
/* This file is part of the KDE libraries
Copyright (C) 2012 Dominik Haumann
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public License
along with this library; see the file COPYING.LIB. If not, write to
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02110-1301, USA.
*/
#ifndef KATE_BUG_286887_TEST_H
#define KATE_BUG_286887_TEST_H
-#include
+#include
class BugTest : public QObject
{
Q_OBJECT
public:
BugTest();
~BugTest();
private Q_SLOTS:
void initTestCase();
void cleanupTestCase();
void ctrlShiftLeft();
};
#endif
diff --git a/autotests/src/bug313759.cpp b/autotests/src/bug313759.cpp
index d639f98a..d582d7f4 100644
--- a/autotests/src/bug313759.cpp
+++ b/autotests/src/bug313759.cpp
@@ -1,96 +1,96 @@
/* This file is part of the KDE libraries
* Copyright (C) 2013 Gerald Senarclens de Grancy
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public License
* along with this library; see the file COPYING.LIB. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#include "bug313759.h"
#include
#include
#include
#include
-#include
+#include
#include
#include "testutils.h"
QTEST_MAIN(BugTest)
using namespace KTextEditor;
BugTest::BugTest()
: QObject()
{
}
BugTest::~BugTest()
{
}
void BugTest::initTestCase()
{
KTextEditor::EditorPrivate::enableUnitTestMode();
}
void BugTest::cleanupTestCase()
{
}
void BugTest::tryCrash()
{
// set up document and view
KMainWindow *toplevel = new KMainWindow();
KTextEditor::DocumentPrivate *doc = new KTextEditor::DocumentPrivate(true, false, toplevel);
KTextEditor::ViewPrivate *view = static_cast(doc->createView(nullptr));
bool outputWasCustomised = false;
TestScriptEnv *env = new TestScriptEnv(doc, outputWasCustomised);
const QUrl url = QUrl::fromLocalFile(QLatin1String(TEST_DATA_DIR"bug313759.txt"));
doc->openUrl(url);
// load moveLinesDown and moveLinesUp
QFile scriptFile(QLatin1String(JS_DATA_DIR "commands/utils.js"));
QVERIFY(scriptFile.exists());
QVERIFY(scriptFile.open(QFile::ReadOnly));
QJSValue result = env->engine()->evaluate(QString::fromLatin1(scriptFile.readAll()), scriptFile.fileName());
QVERIFY2(!result.isError(), result.toString().toUtf8().constData());
// enable on the fly spell checking
doc->onTheFlySpellCheckingEnabled(true);
// view must be visible...
view->show();
view->resize(900, 800);
view->setCursorPosition(Cursor(0, 0));
doc->editBegin();
// QTest::qWait(200);
// evaluate test-script
qDebug() << "attempting crash by moving lines w/ otf spell checking enabled";
QFile sourceFile(QLatin1String(TEST_DATA_DIR"bug313759.js"));
QVERIFY(sourceFile.open(QFile::ReadOnly));
QTextStream stream(&sourceFile);
stream.setCodec("UTF8");
QString code = stream.readAll();
sourceFile.close();
// execute script
result = env->engine()->evaluate(code, QLatin1String(TEST_DATA_DIR"bug313759.txt"), 1);
QVERIFY2(!result.isError(), result.toString().toUtf8().constData());
doc->editEnd();
qDebug() << "PASS (no crash)";
}
diff --git a/autotests/src/bug313759.h b/autotests/src/bug313759.h
index 7800be06..e8bb208e 100644
--- a/autotests/src/bug313759.h
+++ b/autotests/src/bug313759.h
@@ -1,40 +1,40 @@
/* This file is part of the KDE libraries
* Copyright (C) 2012 Dominik Haumann
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public License
* along with this library; see the file COPYING.LIB. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#ifndef KATE_BUG_313759_TEST_H
#define KATE_BUG_313759_TEST_H
-#include
+#include
class BugTest : public QObject
{
Q_OBJECT
public:
BugTest();
~BugTest();
private Q_SLOTS:
void initTestCase();
void cleanupTestCase();
void tryCrash();
};
#endif
diff --git a/autotests/src/bug313769.h b/autotests/src/bug313769.h
index bd33d0f3..b80c831c 100644
--- a/autotests/src/bug313769.h
+++ b/autotests/src/bug313769.h
@@ -1,40 +1,40 @@
/* This file is part of the KDE libraries
Copyright (C) 2012 Dominik Haumann
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public License
along with this library; see the file COPYING.LIB. If not, write to
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02110-1301, USA.
*/
#ifndef KATE_BUG_313769_TEST_H
#define KATE_BUG_313769_TEST_H
-#include
+#include
class BugTest : public QObject
{
Q_OBJECT
public:
BugTest();
~BugTest();
private Q_SLOTS:
void initTestCase();
void cleanupTestCase();
void tryCrash();
};
#endif
diff --git a/autotests/src/bug317111.cpp b/autotests/src/bug317111.cpp
index 9870327d..a36425c5 100644
--- a/autotests/src/bug317111.cpp
+++ b/autotests/src/bug317111.cpp
@@ -1,90 +1,90 @@
/* This file is part of the KDE libraries
* Copyright (C) 2013 Gerald Senarclens de Grancy
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public License
* along with this library; see the file COPYING.LIB. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#include "bug317111.h"
#include
#include
#include
#include
-#include
+#include
#include
#include "testutils.h"
QTEST_MAIN(BugTest)
using namespace KTextEditor;
BugTest::BugTest()
: QObject()
{
}
BugTest::~BugTest()
{
}
void BugTest::initTestCase()
{
KTextEditor::EditorPrivate::enableUnitTestMode();
}
void BugTest::cleanupTestCase()
{
}
void BugTest::tryCrash()
{
// set up document and view
KMainWindow *toplevel = new KMainWindow();
KTextEditor::DocumentPrivate *doc = new KTextEditor::DocumentPrivate(true, false, toplevel);
KTextEditor::ViewPrivate *view = static_cast(doc->createView(nullptr));
bool outputWasCustomised = false;
TestScriptEnv *env = new TestScriptEnv(doc, outputWasCustomised);
const QUrl url = QUrl::fromLocalFile(QLatin1String(TEST_DATA_DIR"bug317111.txt"));
doc->openUrl(url);
// load buggy script
QFile scriptFile(QLatin1String(JS_DATA_DIR"commands/utils.js"));
QVERIFY(scriptFile.exists());
QVERIFY(scriptFile.open(QFile::ReadOnly));
QJSValue result = env->engine()->evaluate(QString::fromLatin1(scriptFile.readAll()), scriptFile.fileName());
QVERIFY2(!result.isError(), result.toString().toUtf8().constData());
// view must be visible...
view->show();
view->resize(900, 800);
view->setCursorPosition(Cursor(0, 0));
// evaluate test-script
qDebug() << "attempting crash by calling KTextEditor::DocumentPrivate::defStyle(-1, 0)";
QFile sourceFile(QLatin1String(TEST_DATA_DIR "bug317111.js"));
QVERIFY(sourceFile.open(QFile::ReadOnly));
QTextStream stream(&sourceFile);
stream.setCodec("UTF8");
QString code = stream.readAll();
sourceFile.close();
// execute script
result = env->engine()->evaluate(code, QLatin1String(TEST_DATA_DIR "bug317111.txt"), 1);
QVERIFY2(!result.isError(), result.toString().toUtf8().constData());
qDebug() << "PASS (no crash)";
}
diff --git a/autotests/src/bug317111.h b/autotests/src/bug317111.h
index f909ab04..ac4a7dd3 100644
--- a/autotests/src/bug317111.h
+++ b/autotests/src/bug317111.h
@@ -1,40 +1,40 @@
/* This file is part of the KDE libraries
* Copyright (C) 2012 Dominik Haumann
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public License
* along with this library; see the file COPYING.LIB. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#ifndef KATE_BUG_317111_TEST_H
#define KATE_BUG_317111_TEST_H
-#include
+#include
class BugTest : public QObject
{
Q_OBJECT
public:
BugTest();
~BugTest();
private Q_SLOTS:
void initTestCase();
void cleanupTestCase();
void tryCrash();
};
#endif
diff --git a/autotests/src/codecompletiontestmodel.h b/autotests/src/codecompletiontestmodel.h
index 95428493..77ab32a5 100644
--- a/autotests/src/codecompletiontestmodel.h
+++ b/autotests/src/codecompletiontestmodel.h
@@ -1,63 +1,63 @@
/* This file is part of the KDE project
Copyright (C) 2005 Hamish Rodda
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public License
along with this library; see the file COPYING.LIB. If not, write to
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02110-1301, USA.
*/
#ifndef CODECOMPLETIONTEST_H
#define CODECOMPLETIONTEST_H
#include
#include
namespace KTextEditor
{
class View;
class CodeCompletionInterface;
}
class CodeCompletionTestModel : public KTextEditor::CodeCompletionModel
{
Q_OBJECT
public:
CodeCompletionTestModel(KTextEditor::View *parent = nullptr, const QString &startText = QString());
KTextEditor::View *view() const;
KTextEditor::CodeCompletionInterface *cc() const;
- void completionInvoked(KTextEditor::View *view, const KTextEditor::Range &range, InvocationType invocationType) Q_DECL_OVERRIDE;
- QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const Q_DECL_OVERRIDE;
+ void completionInvoked(KTextEditor::View *view, const KTextEditor::Range &range, InvocationType invocationType) override;
+ QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
private:
QString m_startText;
bool m_autoStartText;
};
class AbbreviationCodeCompletionTestModel : public CodeCompletionTestModel
{
Q_OBJECT
public:
AbbreviationCodeCompletionTestModel(KTextEditor::View *parent = nullptr, const QString &startText = QString());
- QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const Q_DECL_OVERRIDE;
+ QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
private:
QStringList m_items;
};
#endif
diff --git a/autotests/src/codecompletiontestmodels.h b/autotests/src/codecompletiontestmodels.h
index b1dc646e..3c296fed 100644
--- a/autotests/src/codecompletiontestmodels.h
+++ b/autotests/src/codecompletiontestmodels.h
@@ -1,166 +1,166 @@
/* This file is part of the KDE libraries
Copyright (C) 2008 Niko Sams
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public License
along with this library; see the file COPYING.LIB. If not, write to
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02110-1301, USA.
*/
#ifndef KATE_COMPLETIONTESTMODELS_H
#define KATE_COMPLETIONTESTMODELS_H
#include "codecompletiontestmodel.h"
#include
#include
#include
using namespace KTextEditor;
class CustomRangeModel : public CodeCompletionTestModel, public CodeCompletionModelControllerInterface
{
Q_OBJECT
Q_INTERFACES(KTextEditor::CodeCompletionModelControllerInterface)
public:
CustomRangeModel(KTextEditor::View *parent = nullptr, const QString &startText = QString())
: CodeCompletionTestModel(parent, startText)
{}
- Range completionRange(View *view, const Cursor &position) Q_DECL_OVERRIDE
+ Range completionRange(View *view, const Cursor &position) override
{
Range range = CodeCompletionModelControllerInterface::completionRange(view, position);
if (range.start().column() > 0) {
KTextEditor::Range preRange(Cursor(range.start().line(), range.start().column() - 1),
Cursor(range.start().line(), range.start().column()));
qDebug() << preRange << view->document()->text(preRange);
if (view->document()->text(preRange) == "$") {
range.expandToRange(preRange);
qDebug() << "using custom completion range" << range;
}
}
return range;
}
- bool shouldAbortCompletion(View *view, const Range &range, const QString ¤tCompletion) Q_DECL_OVERRIDE
+ bool shouldAbortCompletion(View *view, const Range &range, const QString ¤tCompletion) override
{
Q_UNUSED(view);
Q_UNUSED(range);
static const QRegExp allowedText("^\\$?(\\w*)");
return !allowedText.exactMatch(currentCompletion);
}
};
class CustomAbortModel : public CodeCompletionTestModel, public CodeCompletionModelControllerInterface
{
Q_OBJECT
Q_INTERFACES(KTextEditor::CodeCompletionModelControllerInterface)
public:
CustomAbortModel(KTextEditor::View *parent = nullptr, const QString &startText = QString())
: CodeCompletionTestModel(parent, startText)
{}
- bool shouldAbortCompletion(View *view, const Range &range, const QString ¤tCompletion) Q_DECL_OVERRIDE
+ bool shouldAbortCompletion(View *view, const Range &range, const QString ¤tCompletion) override
{
Q_UNUSED(view);
Q_UNUSED(range);
static const QRegExp allowedText("^([\\w-]*)");
return !allowedText.exactMatch(currentCompletion);
}
};
class EmptyFilterStringModel : public CodeCompletionTestModel, public CodeCompletionModelControllerInterface
{
Q_OBJECT
Q_INTERFACES(KTextEditor::CodeCompletionModelControllerInterface)
public:
EmptyFilterStringModel(KTextEditor::View *parent = nullptr, const QString &startText = QString())
: CodeCompletionTestModel(parent, startText)
{}
- QString filterString(View *, const Range &, const Cursor &) Q_DECL_OVERRIDE
+ QString filterString(View *, const Range &, const Cursor &) override
{
return QString();
}
};
class UpdateCompletionRangeModel : public CodeCompletionTestModel, public CodeCompletionModelControllerInterface
{
Q_OBJECT
Q_INTERFACES(KTextEditor::CodeCompletionModelControllerInterface)
public:
UpdateCompletionRangeModel(KTextEditor::View *parent = nullptr, const QString &startText = QString())
: CodeCompletionTestModel(parent, startText)
{}
- Range updateCompletionRange(View *view, const Range &range) Q_DECL_OVERRIDE
+ Range updateCompletionRange(View *view, const Range &range) override
{
Q_UNUSED(view);
if (view->document()->text(range) == QString("ab")) {
return Range(Cursor(range.start().line(), 0), range.end());
}
return range;
}
- bool shouldAbortCompletion(View *view, const Range &range, const QString ¤tCompletion) Q_DECL_OVERRIDE
+ bool shouldAbortCompletion(View *view, const Range &range, const QString ¤tCompletion) override
{
Q_UNUSED(view);
Q_UNUSED(range);
Q_UNUSED(currentCompletion);
return false;
}
};
class StartCompletionModel : public CodeCompletionTestModel, public CodeCompletionModelControllerInterface
{
Q_OBJECT
Q_INTERFACES(KTextEditor::CodeCompletionModelControllerInterface)
public:
StartCompletionModel(KTextEditor::View *parent = nullptr, const QString &startText = QString())
: CodeCompletionTestModel(parent, startText)
{}
- bool shouldStartCompletion(View *view, const QString &insertedText, bool userInsertion, const Cursor &position) Q_DECL_OVERRIDE
+ bool shouldStartCompletion(View *view, const QString &insertedText, bool userInsertion, const Cursor &position) override
{
Q_UNUSED(view);
Q_UNUSED(userInsertion);
Q_UNUSED(position);
if (insertedText.isEmpty()) {
return false;
}
QChar lastChar = insertedText.at(insertedText.count() - 1);
if (lastChar == '%') {
return true;
}
return false;
}
};
class ImmideatelyAbortCompletionModel : public CodeCompletionTestModel, public CodeCompletionModelControllerInterface
{
Q_OBJECT
Q_INTERFACES(KTextEditor::CodeCompletionModelControllerInterface)
public:
ImmideatelyAbortCompletionModel(KTextEditor::View *parent = nullptr, const QString &startText = QString())
: CodeCompletionTestModel(parent, startText)
{}
- bool shouldAbortCompletion(KTextEditor::View *view, const KTextEditor::Range &range, const QString ¤tCompletion) Q_DECL_OVERRIDE
+ bool shouldAbortCompletion(KTextEditor::View *view, const KTextEditor::Range &range, const QString ¤tCompletion) override
{
Q_UNUSED(view);
Q_UNUSED(range);
Q_UNUSED(currentCompletion);
return true;
}
};
#endif
diff --git a/autotests/src/commands_test.h b/autotests/src/commands_test.h
index 77be099b..948235e1 100644
--- a/autotests/src/commands_test.h
+++ b/autotests/src/commands_test.h
@@ -1,35 +1,35 @@
/*
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public License
along with this library; see the file COPYING.LIB. If not, write to
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02110-1301, USA.
*/
#ifndef COMMANDS_TEST_H
#define COMMANDS_TEST_H
-#include
+#include
#include "script_test_base.h"
class CommandsTest : public ScriptTestBase
{
Q_OBJECT
private Q_SLOTS:
void initTestCase();
void utils_data();
void utils();
};
#endif // COMMANDS_TEST_H
diff --git a/autotests/src/configinterface_test.h b/autotests/src/configinterface_test.h
index 108b1172..75517e09 100644
--- a/autotests/src/configinterface_test.h
+++ b/autotests/src/configinterface_test.h
@@ -1,38 +1,38 @@
/* This file is part of the KDE libraries
Copyright (C) 2017 Dominik Haumann
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public License
along with this library; see the file COPYING.LIB. If not, write to
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02110-1301, USA.
*/
#ifndef KATE_CONFIG_INTERFACE_TEST_H
#define KATE_CONFIG_INTERFACE_TEST_H
-#include
+#include
class KateConfigInterfaceTest : public QObject
{
Q_OBJECT
public:
KateConfigInterfaceTest();
~KateConfigInterfaceTest();
private Q_SLOTS:
void testDocument();
void testView();
};
#endif // KATE_CONFIG_INTERFACE_TEST_H
diff --git a/autotests/src/indenttest.h b/autotests/src/indenttest.h
index 4582e52e..7bcfbded 100644
--- a/autotests/src/indenttest.h
+++ b/autotests/src/indenttest.h
@@ -1,68 +1,68 @@
/*
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public License
along with this library; see the file COPYING.LIB. If not, write to
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02110-1301, USA.
*/
#ifndef INDENTTEST_H
#define INDENTTEST_H
-#include
+#include
#include "script_test_base.h"
class IndentTest : public ScriptTestBase
{
Q_OBJECT
private Q_SLOTS:
void initTestCase();
void testPython_data();
void testPython();
void testCstyle_data();
void testCstyle();
void testCppstyle_data();
void testCppstyle();
void testCMake_data();
void testCMake();
void testRuby_data();
void testRuby();
void testHaskell_data();
void testHaskell();
void testLatex_data();
void testLatex();
void testPascal_data();
void testPascal();
void testAda_data();
void testAda();
void testXml_data();
void testXml();
void testNormal_data();
void testNormal();
void testReplicode_data();
void testReplicode();
};
#endif // INDENTTEST_H
diff --git a/autotests/src/katedocument_test.cpp b/autotests/src/katedocument_test.cpp
index 52637838..dea86ee1 100644
--- a/autotests/src/katedocument_test.cpp
+++ b/autotests/src/katedocument_test.cpp
@@ -1,463 +1,526 @@
/* This file is part of the KDE libraries
Copyright (C) 2010 Dominik Haumann
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public License
along with this library; see the file COPYING.LIB. If not, write to
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02110-1301, USA.
*/
#include "katedocument_test.h"
#include "moc_katedocument_test.cpp"
#include
#include
#include
#include
#include
#include
#include
#include
///TODO: is there a FindValgrind cmake command we could use to
/// define this automatically?
// comment this out and run the test case with:
// valgrind --tool=callgrind --instr-atstart=no ./katedocument_test testSetTextPerformance
// or similar
//
// #define USE_VALGRIND
#ifdef USE_VALGRIND
#include
#endif
using namespace KTextEditor;
QTEST_MAIN(KateDocumentTest)
class MovingRangeInvalidator : public QObject
{
Q_OBJECT
public:
explicit MovingRangeInvalidator(QObject *parent = nullptr)
: QObject(parent)
{
}
void addRange(MovingRange *range)
{
m_ranges << range;
}
QList ranges() const
{
return m_ranges;
}
public Q_SLOTS:
void aboutToInvalidateMovingInterfaceContent()
{
qDeleteAll(m_ranges);
m_ranges.clear();
}
private:
QList m_ranges;
};
KateDocumentTest::KateDocumentTest()
: QObject()
{
}
KateDocumentTest::~KateDocumentTest()
{
}
void KateDocumentTest::initTestCase()
{
KTextEditor::EditorPrivate::enableUnitTestMode();
}
// tests:
// KTextEditor::DocumentPrivate::insertText with word wrap enabled. It is checked whether the
// text is correctly wrapped and whether the moving cursors maintain the correct
// position.
// see also: http://bugs.kde.org/show_bug.cgi?id=168534
void KateDocumentTest::testWordWrap()
{
KTextEditor::DocumentPrivate doc(false, false);
doc.setWordWrap(true);
doc.setWordWrapAt(80);
const QString content = QLatin1String(".........1.........2.........3.........4.........5.........6 ........7 ........8");
// space after 7 is now kept
// else we kill indentation...
const QString firstWrap = QLatin1String(".........1.........2.........3.........4.........5.........6 ........7 \n....x....8");
// space after 6 is now kept
// else we kill indentation...
const QString secondWrap = QLatin1String(".........1.........2.........3.........4.........5.........6 \n....ooooooooooo....7 ....x....8");
doc.setText(content);
MovingCursor *c = doc.newMovingCursor(Cursor(0, 75), MovingCursor::MoveOnInsert);
QCOMPARE(doc.text(), content);
QCOMPARE(c->toCursor(), Cursor(0, 75));
// type a character at (0, 75)
doc.insertText(c->toCursor(), QLatin1String("x"));
QCOMPARE(doc.text(), firstWrap);
QCOMPARE(c->toCursor(), Cursor(1, 5));
// set cursor to (0, 65) and type "ooooooooooo"
c->setPosition(Cursor(0, 65));
doc.insertText(c->toCursor(), QLatin1String("ooooooooooo"));
QCOMPARE(doc.text(), secondWrap);
QCOMPARE(c->toCursor(), Cursor(1, 15));
}
void KateDocumentTest::testReplaceQStringList()
{
KTextEditor::DocumentPrivate doc(false, false);
doc.setWordWrap(false);
doc.setText(QLatin1String("asdf\n"
"foo\n"
"foo\n"
"bar\n"));
doc.replaceText(Range(1, 0, 3, 0), { "new", "text", "" }, false);
QCOMPARE(doc.text(), QLatin1String("asdf\n"
"new\n"
"text\n"
"bar\n"));
}
void KateDocumentTest::testMovingInterfaceSignals()
{
KTextEditor::DocumentPrivate *doc = new KTextEditor::DocumentPrivate;
QSignalSpy aboutToDeleteSpy(doc, SIGNAL(aboutToDeleteMovingInterfaceContent(KTextEditor::Document*)));
QSignalSpy aboutToInvalidateSpy(doc, SIGNAL(aboutToInvalidateMovingInterfaceContent(KTextEditor::Document*)));
QCOMPARE(doc->revision(), qint64(0));
QCOMPARE(aboutToInvalidateSpy.count(), 0);
QCOMPARE(aboutToDeleteSpy.count(), 0);
QTemporaryFile f;
f.open();
doc->openUrl(QUrl::fromLocalFile(f.fileName()));
QCOMPARE(doc->revision(), qint64(0));
//TODO: gets emitted once in closeFile and once in openFile - is that OK?
QCOMPARE(aboutToInvalidateSpy.count(), 2);
QCOMPARE(aboutToDeleteSpy.count(), 0);
doc->documentReload();
QCOMPARE(doc->revision(), qint64(0));
QCOMPARE(aboutToInvalidateSpy.count(), 4);
//TODO: gets emitted once in closeFile and once in openFile - is that OK?
QCOMPARE(aboutToDeleteSpy.count(), 0);
delete doc;
QCOMPARE(aboutToInvalidateSpy.count(), 4);
QCOMPARE(aboutToDeleteSpy.count(), 1);
}
void KateDocumentTest::testSetTextPerformance()
{
const int lines = 150;
const int columns = 80;
const int rangeLength = 4;
const int rangeGap = 1;
Q_ASSERT(columns % (rangeLength + rangeGap) == 0);
KTextEditor::DocumentPrivate doc;
MovingRangeInvalidator invalidator;
connect(&doc, SIGNAL(aboutToInvalidateMovingInterfaceContent(KTextEditor::Document*)),
&invalidator, SLOT(aboutToInvalidateMovingInterfaceContent()));
QString text;
QVector ranges;
ranges.reserve(lines * columns / (rangeLength + rangeGap));
const QString line = QString().fill('a', columns);
for (int l = 0; l < lines; ++l) {
text.append(line);
text.append('\n');
for (int c = 0; c < columns; c += rangeLength + rangeGap) {
ranges << Range(l, c, l, c + rangeLength);
}
}
// replace
QBENCHMARK {
// init
doc.setText(text);
foreach (const Range &range, ranges)
{
invalidator.addRange(doc.newMovingRange(range));
}
QCOMPARE(invalidator.ranges().size(), ranges.size());
#ifdef USE_VALGRIND
CALLGRIND_START_INSTRUMENTATION
#endif
doc.setText(text);
#ifdef USE_VALGRIND
CALLGRIND_STOP_INSTRUMENTATION
#endif
QCOMPARE(doc.text(), text);
QVERIFY(invalidator.ranges().isEmpty());
}
}
void KateDocumentTest::testRemoveTextPerformance()
{
const int lines = 5000;
const int columns = 80;
KTextEditor::DocumentPrivate doc;
QString text;
const QString line = QString().fill('a', columns);
for (int l = 0; l < lines; ++l) {
text.append(line);
text.append('\n');
}
doc.setText(text);
// replace
QBENCHMARK_ONCE {
#ifdef USE_VALGRIND
CALLGRIND_START_INSTRUMENTATION
#endif
doc.editStart();
doc.removeText(doc.documentRange());
doc.editEnd();
#ifdef USE_VALGRIND
CALLGRIND_STOP_INSTRUMENTATION
#endif
}
}
void KateDocumentTest::testForgivingApiUsage()
{
KTextEditor::DocumentPrivate doc;
QVERIFY(doc.isEmpty());
QVERIFY(doc.replaceText(Range(0, 0, 100, 100), "asdf"));
QCOMPARE(doc.text(), QString("asdf"));
QCOMPARE(doc.lines(), 1);
QVERIFY(doc.replaceText(Range(2, 5, 2, 100), "asdf"));
QCOMPARE(doc.lines(), 3);
QCOMPARE(doc.text(), QLatin1String("asdf\n\n asdf"));
QVERIFY(doc.removeText(Range(0, 0, 1000, 1000)));
QVERIFY(doc.removeText(Range(0, 0, 0, 100)));
QVERIFY(doc.isEmpty());
doc.insertText(Cursor(100, 0), "foobar");
QCOMPARE(doc.line(100), QString("foobar"));
doc.setText("nY\nnYY\n");
QVERIFY(doc.removeText(Range(0, 0, 0, 1000)));
}
void KateDocumentTest::testReplaceTabs()
{
KTextEditor::DocumentPrivate doc;
auto view = static_cast(doc.createView(nullptr));
auto reset = [&]() {
doc.setText(" Hi!");
view->setCursorPosition(Cursor(0, 0));
};
doc.setHighlightingMode ("C++");
doc.config()->setTabWidth(4);
doc.config()->setIndentationMode("cppstyle");
// no replace tabs, no indent pasted text
doc.setConfigValue("replace-tabs", false);
doc.setConfigValue("indent-pasted-text", false);
reset();
doc.insertText(Cursor(0, 0), "\t");
QCOMPARE(doc.text(), QStringLiteral("\t Hi!"));
reset();
doc.typeChars(view, "\t");
QCOMPARE(doc.text(), QStringLiteral("\t Hi!"));
reset();
doc.paste(view, "some\ncode\n 3\nhi\n");
QCOMPARE(doc.text(), QStringLiteral("some\ncode\n 3\nhi\n Hi!"));
// now, enable replace tabs
doc.setConfigValue("replace-tabs", true);
reset();
doc.insertText(Cursor(0, 0), "\t");
// calling insertText does not replace tabs
QCOMPARE(doc.text(), QStringLiteral("\t Hi!"));
reset();
doc.typeChars(view, "\t");
// typing text replaces tabs
QCOMPARE(doc.text(), QStringLiteral(" Hi!"));
reset();
doc.paste(view, "\t");
// pasting text does not with indent-pasted off
QCOMPARE(doc.text(), QStringLiteral("\t Hi!"));
doc.setConfigValue("indent-pasted-text", true);
doc.setText("int main() {\n \n}");
view->setCursorPosition(Cursor(1, 4));
doc.paste(view, "\tHi");
// ... and it still does not with indent-pasted on.
// This behaviour is up to discussion.
QCOMPARE(doc.text(), QStringLiteral("int main() {\n Hi\n}"));
reset();
doc.paste(view, "some\ncode\n 3\nhi");
QCOMPARE(doc.text(), QStringLiteral("some\ncode\n3\nhi Hi!"));
}
/**
* Provides slots to check data sent in specific signals. Slot names are derived from corresponding test names.
*/
class SignalHandler : public QObject
{
Q_OBJECT
public Q_SLOTS:
void slotMultipleLinesRemoved(KTextEditor::Document *, const KTextEditor::Range &, const QString &oldText)
{
QCOMPARE(oldText, QString("line2\nline3\n"));
}
void slotNewlineInserted(KTextEditor::Document *, const KTextEditor::Range &range)
{
QCOMPARE(range, Range(Cursor(1, 4), Cursor(2, 0)));
}
};
void KateDocumentTest::testRemoveMultipleLines()
{
KTextEditor::DocumentPrivate doc;
doc.setText("line1\n"
"line2\n"
"line3\n"
"line4\n");
SignalHandler handler;
connect(&doc, &KTextEditor::DocumentPrivate::textRemoved, &handler, &SignalHandler::slotMultipleLinesRemoved);
doc.removeText(Range(1, 0, 3, 0));
}
void KateDocumentTest::testInsertNewline()
{
KTextEditor::DocumentPrivate doc;
doc.setText("this is line\n"
"this is line2\n");
SignalHandler handler;
connect(&doc, SIGNAL(textInserted(KTextEditor::Document*,KTextEditor::Range)), &handler, SLOT(slotNewlineInserted(KTextEditor::Document*,KTextEditor::Range)));
doc.editWrapLine(1, 4);
}
void KateDocumentTest::testInsertAfterEOF()
{
KTextEditor::DocumentPrivate doc;
doc.setText("line0\n"
"line1");
const QString input = QLatin1String("line3\n"
"line4");
const QString expected = QLatin1String("line0\n"
"line1\n"
"\n"
"line3\n"
"line4");
doc.insertText(KTextEditor::Cursor(3, 0), input);
QCOMPARE(doc.text(), expected);
}
// we have two different ways of creating the checksum:
// in KateFileLoader and KTextEditor::DocumentPrivate::createDigest. Make
// sure, these two implementations result in the same checksum.
void KateDocumentTest::testDigest()
{
// Git hash of test file (git hash-object data/md5checksum.txt):
const QByteArray gitHash = "696e6d35a5d9cc28d16e56bdcb2d2a88126b814e";
// QCryptographicHash is used, therefore we need fromHex here
const QByteArray fileDigest = QByteArray::fromHex(gitHash);
// make sure, Kate::TextBuffer and KTextEditor::DocumentPrivate::createDigest() equal
KTextEditor::DocumentPrivate doc;
doc.openUrl(QUrl::fromLocalFile(QLatin1String(TEST_DATA_DIR"md5checksum.txt")));
const QByteArray bufferDigest(doc.checksum());
QVERIFY(doc.createDigest());
const QByteArray docDigest(doc.checksum());
QCOMPARE(bufferDigest, fileDigest);
QCOMPARE(docDigest, fileDigest);
}
+void KateDocumentTest::testModelines()
+{
+ // honor document variable indent-width
+ {
+ KTextEditor::DocumentPrivate doc;
+ QCOMPARE(doc.config()->indentationWidth(), 4);
+ doc.readVariableLine(QStringLiteral("kate: indent-width 3;"));
+ QCOMPARE(doc.config()->indentationWidth(), 3);
+ }
+
+ // honor document variable indent-width with * wildcard
+ {
+ KTextEditor::DocumentPrivate doc;
+ QCOMPARE(doc.config()->indentationWidth(), 4);
+ doc.readVariableLine(QStringLiteral("kate-wildcard(*): indent-width 3;"));
+ QCOMPARE(doc.config()->indentationWidth(), 3);
+ }
+
+ // ignore document variable indent-width, since the wildcard does not match
+ {
+ KTextEditor::DocumentPrivate doc;
+ QCOMPARE(doc.config()->indentationWidth(), 4);
+ doc.readVariableLine(QStringLiteral("kate-wildcard(*.txt): indent-width 3;"));
+ QCOMPARE(doc.config()->indentationWidth(), 4);
+ }
+
+ // document variable indent-width, since the wildcard does not match
+ {
+ KTextEditor::DocumentPrivate doc;
+ doc.openUrl(QUrl::fromLocalFile(QLatin1String(TEST_DATA_DIR"modelines.txt")));
+ QVERIFY(!doc.isEmpty());
+
+ // ignore wrong wildcard
+ QCOMPARE(doc.config()->indentationWidth(), 4);
+ doc.readVariableLine(QStringLiteral("kate-wildcard(*.bar): indent-width 3;"));
+ QCOMPARE(doc.config()->indentationWidth(), 4);
+
+ // read correct wildcard
+ QCOMPARE(doc.config()->indentationWidth(), 4);
+ doc.readVariableLine(QStringLiteral("kate-wildcard(*.txt): indent-width 5;"));
+ QCOMPARE(doc.config()->indentationWidth(), 5);
+
+ // honor correct wildcard
+ QCOMPARE(doc.config()->indentationWidth(), 5);
+ doc.readVariableLine(QStringLiteral("kate-wildcard(*.foo;*.txt;*.bar): indent-width 6;"));
+ QCOMPARE(doc.config()->indentationWidth(), 6);
+
+ // ignore incorrect mimetype
+ QCOMPARE(doc.config()->indentationWidth(), 6);
+ doc.readVariableLine(QStringLiteral("kate-mimetype(text/unknown): indent-width 7;"));
+ QCOMPARE(doc.config()->indentationWidth(), 6);
+
+ // honor correct mimetype
+ QCOMPARE(doc.config()->indentationWidth(), 6);
+ doc.readVariableLine(QStringLiteral("kate-mimetype(text/plain): indent-width 8;"));
+ QCOMPARE(doc.config()->indentationWidth(), 8);
+
+ // honor correct mimetype
+ QCOMPARE(doc.config()->indentationWidth(), 8);
+ doc.readVariableLine(QStringLiteral("kate-mimetype(text/foo;text/plain;text/bar): indent-width 9;"));
+ QCOMPARE(doc.config()->indentationWidth(), 9);
+ }
+}
void KateDocumentTest::testDefStyleNum()
{
KTextEditor::DocumentPrivate doc;
doc.setText("foo\nbar\nasdf");
QCOMPARE(doc.defStyleNum(0, 0), 0);
}
void KateDocumentTest::testTypeCharsWithSurrogateAndNewLine()
{
KTextEditor::DocumentPrivate doc;
auto view = static_cast(doc.createView(nullptr));
const uint surrogateUcs4String[] = { 0x1f346, '\n', 0x1f346, 0 };
const auto surrogateString = QString::fromUcs4(surrogateUcs4String);
doc.typeChars(view, surrogateString);
QCOMPARE(doc.text(), surrogateString);
}
void KateDocumentTest::testRemoveComposedCharacters()
{
KTextEditor::DocumentPrivate doc;
auto view = static_cast(doc.createView(nullptr));
view->config()->setBackspaceRemoveComposed(true);
doc.setText(QString::fromUtf8("व्यक्तियों"));
doc.del(view, Cursor(0, 0));
QCOMPARE(doc.text(), QString::fromUtf8(("क्तियों")));
doc.backspace(view, Cursor(0, 7));
QCOMPARE(doc.text(), QString::fromUtf8(("क्ति")));
}
#include "katedocument_test.moc"
diff --git a/autotests/src/katedocument_test.h b/autotests/src/katedocument_test.h
index b8936a7f..713ba23e 100644
--- a/autotests/src/katedocument_test.h
+++ b/autotests/src/katedocument_test.h
@@ -1,61 +1,62 @@
/* This file is part of the KDE libraries
Copyright (C) 2010 Dominik Haumann
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public License
along with this library; see the file COPYING.LIB. If not, write to
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02110-1301, USA.
*/
#ifndef KATE_DOCUMENT_TEST_H
#define KATE_DOCUMENT_TEST_H
-#include
+#include
class KateDocumentTest : public QObject
{
Q_OBJECT
public:
KateDocumentTest();
~KateDocumentTest();
public Q_SLOTS:
void initTestCase();
private Q_SLOTS:
void testWordWrap();
void testReplaceQStringList();
void testMovingInterfaceSignals();
void testSetTextPerformance();
void testRemoveTextPerformance();
void testForgivingApiUsage();
void testRemoveMultipleLines();
void testInsertNewline();
void testInsertAfterEOF();
void testReplaceTabs();
void testDigest();
+ void testModelines();
void testDefStyleNum();
void testTypeCharsWithSurrogateAndNewLine();
void testRemoveComposedCharacters();
};
#endif // KATE_DOCUMENT_TEST_H
diff --git a/autotests/src/kateencodingtest.cpp b/autotests/src/kateencodingtest.cpp
index 84a86946..5bb6cb17 100644
--- a/autotests/src/kateencodingtest.cpp
+++ b/autotests/src/kateencodingtest.cpp
@@ -1,63 +1,63 @@
/* This file is part of the Kate project.
*
* Copyright (C) 2010 Christoph Cullmann
* Copyright (C) 2010 Dominik Haumann
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public License
* along with this library; see the file COPYING.LIB. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#include
#include "katetextbuffer.h"
-#include
+#include
int main(int argc, char *argv[])
{
// construct core app
QCoreApplication app(argc, argv);
// test mode
KTextEditor::EditorPrivate::enableUnitTestMode();
// get arguments
QString encoding = app.arguments().at(1);
QString inFile = app.arguments().at(2);
QString outFile = app.arguments().at(3);
Kate::TextBuffer buffer(nullptr);
// set codec
buffer.setFallbackTextCodec(QTextCodec::codecForName("ISO 8859-15"));
buffer.setTextCodec(QTextCodec::codecForName(encoding.toLatin1()));
// switch to Mac EOL, this will test eol detection, as files are normal unix or dos
buffer.setEndOfLineMode(Kate::TextBuffer::eolMac);
// load file
bool encodingErrors = false;
bool tooLongLines = false;
int longestLineLoaded;
if (!buffer.load(inFile, encodingErrors, tooLongLines, longestLineLoaded, false) || encodingErrors) {
return 1;
}
// save file
if (!buffer.save(outFile)) {
return 1;
}
return 0;
}
diff --git a/autotests/src/katefoldingtest.h b/autotests/src/katefoldingtest.h
index 9482678b..73ec4747 100644
--- a/autotests/src/katefoldingtest.h
+++ b/autotests/src/katefoldingtest.h
@@ -1,39 +1,39 @@
/* This file is part of the KDE libraries
Copyright (C) 2013 Dominik Haumann
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public License
along with this library; see the file COPYING.LIB. If not, write to
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02110-1301, USA.
*/
#ifndef KATE_FOLDING_TEST_H
#define KATE_FOLDING_TEST_H
-#include
+#include
class KateFoldingTest : public QObject
{
Q_OBJECT
public Q_SLOTS:
void initTestCase();
void cleanupTestCase();
private Q_SLOTS:
void testCrash311866();
void testBug295632();
void testCrash367466();
};
#endif // KATE_FOLDING_TEST_H
diff --git a/autotests/src/katesyntaxtest.h b/autotests/src/katesyntaxtest.h
index 5c105a05..2e3348be 100644
--- a/autotests/src/katesyntaxtest.h
+++ b/autotests/src/katesyntaxtest.h
@@ -1,38 +1,38 @@
/* This file is part of the KDE libraries
Copyright (C) 2013 Dominik Haumann
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public License
along with this library; see the file COPYING.LIB. If not, write to
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02110-1301, USA.
*/
#ifndef KATE_SYNTAX_TEST_H
#define KATE_SYNTAX_TEST_H
-#include
+#include
class KateSyntaxTest : public QObject
{
Q_OBJECT
public Q_SLOTS:
void initTestCase();
void cleanupTestCase();
private Q_SLOTS:
void testSyntaxHighlighting_data();
void testSyntaxHighlighting();
};
#endif // KATE_FOLDING_TEST_H
diff --git a/autotests/src/katetextbuffertest.h b/autotests/src/katetextbuffertest.h
index 7a3df3c1..257c8e47 100644
--- a/autotests/src/katetextbuffertest.h
+++ b/autotests/src/katetextbuffertest.h
@@ -1,46 +1,46 @@
/* This file is part of the Kate project.
*
* Copyright (C) 2010 Christoph Cullmann
* Copyright (C) 2010 Dominik Haumann
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public License
* along with this library; see the file COPYING.LIB. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#ifndef KATEBUFFERTEST_H
#define KATEBUFFERTEST_H
-#include
-#include
+#include
+#include
class KateTextBufferTest : public QObject
{
Q_OBJECT
public:
KateTextBufferTest();
virtual ~KateTextBufferTest();
private Q_SLOTS:
void basicBufferTest();
void wrapLineTest();
void insertRemoveTextTest();
void cursorTest();
void foldingTest();
void nestedFoldingTest();
void saveFileInUnwritableFolder();
void saveFileWithElevatedPrivileges();
};
#endif // KATEBUFFERTEST_H
diff --git a/autotests/src/kateview_test.cpp b/autotests/src/kateview_test.cpp
index a0880f81..d9b56725 100644
--- a/autotests/src/kateview_test.cpp
+++ b/autotests/src/kateview_test.cpp
@@ -1,396 +1,433 @@
/* This file is part of the KDE libraries
Copyright (C) 2010 Milian Wolff
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public License
along with this library; see the file COPYING.LIB. If not, write to
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02110-1301, USA.
*/
#include "kateview_test.h"
#include "moc_kateview_test.cpp"
#include
#include
#include
#include
#include
#include
#include
#include
#include
using namespace KTextEditor;
QTEST_MAIN(KateViewTest)
KateViewTest::KateViewTest()
: QObject()
{
KTextEditor::EditorPrivate::enableUnitTestMode();
}
KateViewTest::~KateViewTest()
{
}
void KateViewTest::testCoordinatesToCursor()
{
KTextEditor::DocumentPrivate doc(false, false);
doc.setText("Hi World!\nHi\n");
KTextEditor::View* view1 = static_cast(doc.createView(nullptr));
view1->resize(400, 300);
view1->show();
QCOMPARE(view1->coordinatesToCursor(view1->cursorToCoordinate(KTextEditor::Cursor(0, 2))),
KTextEditor::Cursor(0, 2));
QCOMPARE(view1->coordinatesToCursor(view1->cursorToCoordinate(KTextEditor::Cursor(1, 1))),
KTextEditor::Cursor(1, 1));
// behind end of line should give an invalid cursor
QCOMPARE(view1->coordinatesToCursor(view1->cursorToCoordinate(KTextEditor::Cursor(1, 5))),
KTextEditor::Cursor::invalid());
QCOMPARE(view1->cursorToCoordinate(KTextEditor::Cursor(3, 1)), QPoint(-1, -1));
// check consistency between cursorToCoordinate(view->cursorPosition() and cursorPositionCoordinates()
// random position
view1->setCursorPosition(KTextEditor::Cursor(0, 3));
QCOMPARE(view1->coordinatesToCursor(view1->cursorToCoordinate(view1->cursorPosition())),
KTextEditor::Cursor(0, 3));
QCOMPARE(view1->coordinatesToCursor(view1->cursorPositionCoordinates()), KTextEditor::Cursor(0, 3));
// end of line
view1->setCursorPosition(KTextEditor::Cursor(0, 9));
QCOMPARE(view1->coordinatesToCursor(view1->cursorToCoordinate(KTextEditor::Cursor(0, 9))),
KTextEditor::Cursor(0, 9));
QCOMPARE(view1->coordinatesToCursor(view1->cursorPositionCoordinates()), KTextEditor::Cursor(0, 9));
// empty line
view1->setCursorPosition(KTextEditor::Cursor(2, 0));
QCOMPARE(view1->coordinatesToCursor(view1->cursorToCoordinate(KTextEditor::Cursor(2, 0))),
KTextEditor::Cursor(2, 0));
QCOMPARE(view1->coordinatesToCursor(view1->cursorPositionCoordinates()), KTextEditor::Cursor(2, 0));
// same test again, but with message widget on top visible
KTextEditor::Message *message = new KTextEditor::Message("Jo World!", KTextEditor::Message::Information);
doc.postMessage(message);
// wait 500ms until show animation is finished, so the message widget is visible
QTest::qWait(500);
QCOMPARE(view1->coordinatesToCursor(view1->cursorToCoordinate(KTextEditor::Cursor(0, 2))),
KTextEditor::Cursor(0, 2));
QCOMPARE(view1->coordinatesToCursor(view1->cursorToCoordinate(KTextEditor::Cursor(1, 1))),
KTextEditor::Cursor(1, 1));
// behind end of line should give an invalid cursor
QCOMPARE(view1->coordinatesToCursor(view1->cursorToCoordinate(KTextEditor::Cursor(1, 5))),
KTextEditor::Cursor::invalid());
QCOMPARE(view1->cursorToCoordinate(KTextEditor::Cursor(3, 1)), QPoint(-1, -1));
}
void KateViewTest::testCursorToCoordinates()
{
KTextEditor::DocumentPrivate doc(false, false);
doc.setText("int a;");
KTextEditor::ViewPrivate *view = new KTextEditor::ViewPrivate(&doc, nullptr);
view->config()->setDynWordWrap(true);
view->show();
// don't crash, see https://bugs.kde.org/show_bug.cgi?id=337863
view->cursorToCoordinate(Cursor(0, 0));
view->cursorToCoordinate(Cursor(1, 0));
view->cursorToCoordinate(Cursor(-1, 0));
}
void KateViewTest::testReloadMultipleViews()
{
QTemporaryFile file("XXXXXX.cpp");
file.open();
QTextStream stream(&file);
const QString line = "const char* foo = \"asdf\"\n";
for (int i = 0; i < 200; ++i) {
stream << line;
}
stream << flush;
file.close();
KTextEditor::DocumentPrivate doc;
QVERIFY(doc.openUrl(QUrl::fromLocalFile(file.fileName())));
QCOMPARE(doc.highlightingMode(), QString("C++"));
KTextEditor::ViewPrivate *view1 = new KTextEditor::ViewPrivate(&doc, nullptr);
KTextEditor::ViewPrivate *view2 = new KTextEditor::ViewPrivate(&doc, nullptr);
view1->show();
view2->show();
QCOMPARE(doc.views().count(), 2);
QVERIFY(doc.documentReload());
}
void KateViewTest::testTabCursorOnReload()
{
// testcase for https://bugs.kde.org/show_bug.cgi?id=258480
QTemporaryFile file("XXXXXX.cpp");
file.open();
QTextStream stream(&file);
stream << "\tfoo\n";
file.close();
KTextEditor::DocumentPrivate doc;
QVERIFY(doc.openUrl(QUrl::fromLocalFile(file.fileName())));
KTextEditor::ViewPrivate *view = new KTextEditor::ViewPrivate(&doc, nullptr);
const KTextEditor::Cursor cursor(0, 4);
view->setCursorPosition(cursor);
QCOMPARE(view->cursorPosition(), cursor);
QVERIFY(doc.documentReload());
QCOMPARE(view->cursorPosition(), cursor);
}
void KateViewTest::testLowerCaseBlockSelection()
{
// testcase for https://bugs.kde.org/show_bug.cgi?id=258480
KTextEditor::DocumentPrivate doc;
doc.setText("nY\nnYY\n");
KTextEditor::ViewPrivate *view1 = new KTextEditor::ViewPrivate(&doc, nullptr);
view1->setBlockSelection(true);
view1->setSelection(Range(0, 1, 1, 3));
view1->lowercase();
QCOMPARE(doc.text(), QString("ny\nnyy\n"));
}
+namespace
+{
+ QWidget *findViewInternal(KTextEditor::View* view)
+ {
+ foreach (QObject* child, view->children()) {
+ if (child->metaObject()->className() == QByteArrayLiteral("KateViewInternal")) {
+ return qobject_cast(child);
+ }
+ }
+ return nullptr;
+ }
+}
+
void KateViewTest::testSelection()
{
// see also: https://bugs.kde.org/show_bug.cgi?id=277422
// wrong behavior before:
// Open file with text
// click at end of some line (A) and drag to right, i.e. without selecting anything
// click somewhere else (B)
// shift click to another place (C)
// => expected: selection from B to C
// => actual: selection from A to C
QTemporaryFile file("XXXXXX.txt");
file.open();
QTextStream stream(&file);
stream << "A\n"
<< "B\n"
<< "C";
stream << flush;
file.close();
KTextEditor::DocumentPrivate doc;
QVERIFY(doc.openUrl(QUrl::fromLocalFile(file.fileName())));
KTextEditor::ViewPrivate *view = new KTextEditor::ViewPrivate(&doc, nullptr);
view->resize(100, 200);
view->show();
- QObject *internalView = nullptr;
- foreach (QObject* child, view->children()) {
- if (child->metaObject()->className() == QByteArrayLiteral("KateViewInternal")) {
- internalView = child;
- break;
- }
- }
+
+ QObject *internalView = findViewInternal(view);
QVERIFY(internalView);
const QPoint afterA = view->cursorToCoordinate(Cursor(0, 1));
const QPoint afterB = view->cursorToCoordinate(Cursor(1, 1));
const QPoint afterC = view->cursorToCoordinate(Cursor(2, 1));
// click after A
QCoreApplication::sendEvent(internalView, new QMouseEvent(QEvent::MouseButtonPress, afterA,
Qt::LeftButton, Qt::LeftButton,
Qt::NoModifier));
QCoreApplication::sendEvent(internalView, new QMouseEvent(QEvent::MouseButtonRelease, afterA,
Qt::LeftButton, Qt::LeftButton,
Qt::NoModifier));
QCOMPARE(view->cursorPosition(), Cursor(0, 1));
// drag to right
QCoreApplication::sendEvent(internalView, new QMouseEvent(QEvent::MouseButtonPress, afterA,
Qt::LeftButton, Qt::LeftButton,
Qt::NoModifier));
QCoreApplication::sendEvent(internalView, new QMouseEvent(QEvent::MouseMove, afterA + QPoint(50, 0),
Qt::LeftButton, Qt::LeftButton,
Qt::NoModifier));
QCoreApplication::sendEvent(internalView, new QMouseEvent(QEvent::MouseButtonRelease, afterA + QPoint(50, 0),
Qt::LeftButton, Qt::LeftButton,
Qt::NoModifier));
QCOMPARE(view->cursorPosition(), Cursor(0, 1));
QVERIFY(!view->selection());
// click after C
QCoreApplication::sendEvent(internalView, new QMouseEvent(QEvent::MouseButtonPress, afterC,
Qt::LeftButton, Qt::LeftButton,
Qt::NoModifier));
QCoreApplication::sendEvent(internalView, new QMouseEvent(QEvent::MouseButtonRelease, afterC,
Qt::LeftButton, Qt::LeftButton,
Qt::NoModifier));
QCOMPARE(view->cursorPosition(), Cursor(2, 1));
// shift+click after B
QCoreApplication::sendEvent(internalView, new QMouseEvent(QEvent::MouseButtonPress, afterB,
Qt::LeftButton, Qt::LeftButton,
Qt::ShiftModifier));
QCoreApplication::sendEvent(internalView, new QMouseEvent(QEvent::MouseButtonRelease, afterB,
Qt::LeftButton, Qt::LeftButton,
Qt::ShiftModifier));
QCOMPARE(view->cursorPosition(), Cursor(1, 1));
QCOMPARE(view->selectionRange(), Range(1, 1, 2, 1));
}
void KateViewTest::testKillline()
{
KTextEditor::DocumentPrivate doc;
doc.insertLines(0, { "foo", "bar", "baz" });
KTextEditor::ViewPrivate *view = new KTextEditor::ViewPrivate(&doc, nullptr);
view->setCursorPositionInternal(KTextEditor::Cursor(1, 2));
view->killLine();
QCOMPARE(doc.text(), QLatin1String("foo\nbaz\n"));
doc.clear();
QVERIFY(doc.isEmpty());
doc.insertLines(0, { "foo", "bar", "baz", "xxx" });
view->setCursorPositionInternal(KTextEditor::Cursor(1, 2));
view->shiftDown();
view->killLine();
QCOMPARE(doc.text(), QLatin1String("foo\nxxx\n"));
}
+void KateViewTest::testScrollPastEndOfDocument()
+{
+#if 0 // bug still exists, see bug 306745
+ KTextEditor::DocumentPrivate doc;
+ doc.setText(QStringLiteral("0000000000\n"
+ "1111111111\n"
+ "2222222222\n"
+ "3333333333\n"
+ "4444444444"));
+ QCOMPARE(doc.lines(), 5);
+
+ KTextEditor::ViewPrivate *view = new KTextEditor::ViewPrivate(&doc, nullptr);
+ view->setCursorPosition({ 3, 5 });
+ view->resize(400, 300);
+ view->show();
+
+ // enable "[x] Scroll past end of document"
+ view->config()->setScrollPastEnd(true);
+ QCOMPARE(view->config()->scrollPastEnd(), true);
+
+ // disable dynamic word wrap
+ view->config()->setDynWordWrap(false);
+ QCOMPARE(view->config()->dynWordWrap(), false);
+
+ view->scrollDown();
+ view->scrollDown();
+ view->scrollDown();
+ // at this point, only lines 3333333333 and 4444444444 are visible.
+ view->down();
+ QCOMPARE(view->cursorPosition(), KTextEditor::Cursor(4, 5));
+ // verify, that only lines 3333333333 and 4444444444 are still visible.
+ QCOMPARE(view->firstDisplayedLineInternal(KTextEditor::View::RealLine), 3);
+#endif
+}
+
void KateViewTest::testFoldFirstLine()
{
QTemporaryFile file("XXXXXX.cpp");
file.open();
QTextStream stream(&file);
stream << "/**\n"
<< " * foo\n"
<< " */\n"
<< "\n"
<< "int main() {}\n";
file.close();
KTextEditor::DocumentPrivate doc;
QVERIFY(doc.openUrl(QUrl::fromLocalFile(file.fileName())));
QCOMPARE(doc.highlightingMode(), QString("C++"));
KTextEditor::ViewPrivate *view = new KTextEditor::ViewPrivate(&doc, nullptr);
view->config()->setFoldFirstLine(false);
view->setCursorPosition({4, 0});
// initially, nothing is folded
QVERIFY(view->textFolding().isLineVisible(1));
// now change the config, and expect the header to be folded
view->config()->setFoldFirstLine(true);
qint64 foldedRangeId = 0;
QVERIFY(!view->textFolding().isLineVisible(1, &foldedRangeId));
// now unfold the range
QVERIFY(view->textFolding().unfoldRange(foldedRangeId));
QVERIFY(view->textFolding().isLineVisible(1));
// and save the file, we do not expect the folding to change then
doc.setModified(true);
doc.saveFile();
QVERIFY(view->textFolding().isLineVisible(1));
// now reload the document, nothing should change
doc.setModified(false);
QVERIFY(doc.documentReload());
QVERIFY(view->textFolding().isLineVisible(1));
}
// test for bug https://bugs.kde.org/374163
void KateViewTest::testDragAndDrop()
{
KTextEditor::DocumentPrivate doc(false, false);
doc.setText("line0\n"
"line1\n"
"line2\n"
"\n"
"line4");
KTextEditor::View* view = static_cast(doc.createView(nullptr));
view->show();
view->resize(400, 300);
- QWidget *internalView = nullptr;
- foreach (QObject* child, view->children()) {
- if (child->metaObject()->className() == QByteArrayLiteral("KateViewInternal")) {
- internalView = qobject_cast(child);
- break;
- }
- }
+ QWidget *internalView = findViewInternal(view);
QVERIFY(internalView);
// select "line1\n"
view->setSelection(Range(1, 0, 2, 0));
QCOMPARE(view->selectionRange(), Range(1, 0, 2, 0));
QVERIFY(QTest::qWaitForWindowExposed(view));
const QPoint startDragPos = internalView->mapFrom(view, view->cursorToCoordinate(KTextEditor::Cursor(1, 2)));
const QPoint endDragPos = internalView->mapFrom(view, view->cursorToCoordinate(KTextEditor::Cursor(3, 0)));
const QPoint gStartDragPos = internalView->mapToGlobal(startDragPos);
const QPoint gEndDragPos = internalView->mapToGlobal(endDragPos);
// now drag and drop selected text to Cursor(3, 0)
QMouseEvent pressEvent(QEvent::MouseButtonPress, startDragPos, gStartDragPos,
Qt::LeftButton, Qt::LeftButton, Qt::NoModifier);
QCoreApplication::sendEvent(internalView, &pressEvent);
// ugly workaround: Drag & Drop has own blocking event queue. Therefore, we need a single-shot timer to
// break out of the blocking event queue, see (*)
QTimer::singleShot(50, [&](){
QMouseEvent moveEvent(QEvent::MouseMove, endDragPos + QPoint(5, 0), gEndDragPos + QPoint(5, 0),
Qt::LeftButton, Qt::LeftButton, Qt::NoModifier);
QMouseEvent releaseEvent(QEvent::MouseButtonRelease, endDragPos, gEndDragPos,
Qt::LeftButton, Qt::NoButton, Qt::NoModifier);
QCoreApplication::sendEvent(internalView, &moveEvent);
QCoreApplication::sendEvent(internalView, &releaseEvent);
});
// (*) this somehow blocks...
QMouseEvent moveEvent1(QEvent::MouseMove, endDragPos + QPoint(10, 0), gEndDragPos + QPoint(10, 0),
Qt::LeftButton, Qt::LeftButton, Qt::NoModifier);
QCoreApplication::sendEvent(internalView, &moveEvent1);
QTest::qWait(100);
// final tests of dragged text
QCOMPARE(doc.text(), QString("line0\n"
"line2\n"
"line1\n"
"\n"
"line4"));
QCOMPARE(view->cursorPosition(), KTextEditor::Cursor(3, 0));
QCOMPARE(view->selectionRange(), Range(2, 0, 3, 0));
}
// kate: indent-mode cstyle; indent-width 4; replace-tabs on;
diff --git a/autotests/src/kateview_test.h b/autotests/src/kateview_test.h
index a48720d9..c449bcf7 100644
--- a/autotests/src/kateview_test.h
+++ b/autotests/src/kateview_test.h
@@ -1,50 +1,51 @@
/* This file is part of the KDE libraries
Copyright (C) 2010 Milian Wolff
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public License
along with this library; see the file COPYING.LIB. If not, write to
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02110-1301, USA.
*/
#ifndef KATE_VIEW_TEST_H
#define KATE_VIEW_TEST_H
-#include
+#include
class KateViewTest : public QObject
{
Q_OBJECT
public:
KateViewTest();
~KateViewTest();
private Q_SLOTS:
void testReloadMultipleViews();
void testTabCursorOnReload();
void testLowerCaseBlockSelection();
void testCoordinatesToCursor();
void testCursorToCoordinates();
void testSelection();
void testKillline();
+ void testScrollPastEndOfDocument();
void testFoldFirstLine();
void testDragAndDrop();
};
#endif // KATE_VIEW_TEST_H
diff --git a/autotests/src/kte_documentcursor.h b/autotests/src/kte_documentcursor.h
index 3e18a124..440750e8 100644
--- a/autotests/src/kte_documentcursor.h
+++ b/autotests/src/kte_documentcursor.h
@@ -1,43 +1,43 @@
/* This file is part of the KDE libraries
Copyright (C) 2012 Dominik Haumann
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public License
along with this library; see the file COPYING.LIB. If not, write to
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02110-1301, USA.
*/
#ifndef KTE_DOCUMENTCURSOR_TEST_H
#define KTE_DOCUMENTCURSOR_TEST_H
-#include
+#include
class DocumentCursorTest : public QObject
{
Q_OBJECT
public:
DocumentCursorTest();
~DocumentCursorTest();
private Q_SLOTS:
void initTestCase();
void cleanupTestCase();
void testConvenienceApi();
void testOperators();
void testValidTextPosition();
};
#endif
diff --git a/autotests/src/messagetest.h b/autotests/src/messagetest.h
index 7c669cb6..6398cf1f 100644
--- a/autotests/src/messagetest.h
+++ b/autotests/src/messagetest.h
@@ -1,45 +1,45 @@
/* This file is part of the KDE libraries
Copyright (C) 2013 Dominik Haumann
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public License
along with this library; see the file COPYING.LIB. If not, write to
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02110-1301, USA.
*/
#ifndef KTEXTEDITOR_MESSAGE_TEST_H
#define KTEXTEDITOR_MESSAGE_TEST_H
-#include
+#include
class MessageTest : public QObject
{
Q_OBJECT
public Q_SLOTS:
void initTestCase();
void cleanupTestCase();
private Q_SLOTS:
void testPostMessage();
void testAutoHide();
private:
void testAutoHideAfterUserInteraction();
void testMessageQueue();
void testPriority();
void testCreateView();
void testHideView();
void testHideViewAfterUserInteraction();
};
#endif // KTEXTEDITOR_MESSAGE_TEST_H
diff --git a/autotests/src/modificationsystem_test.h b/autotests/src/modificationsystem_test.h
index 87c9655b..600641fa 100644
--- a/autotests/src/modificationsystem_test.h
+++ b/autotests/src/modificationsystem_test.h
@@ -1,57 +1,57 @@
/* This file is part of the KDE libraries
Copyright (C) 2011 Dominik Haumann
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public License
along with this library; see the file COPYING.LIB. If not, write to
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02110-1301, USA.
*/
#ifndef KATE_MODIFICATION_SYSTEM_TEST_H
#define KATE_MODIFICATION_SYSTEM_TEST_H
-#include
+#include
/**
* Test the complete Line Modification System.
* Covered classes:
* - KateModification* in part/undo/
* - modification flags in Kate::TextLine in part/buffer/
*/
class ModificationSystemTest : public QObject
{
Q_OBJECT
private Q_SLOTS:
void initTestCase();
void cleanupTestCase();
void testInsertText();
void testRemoveText();
void testInsertLine();
void testRemoveLine();
void testWrapLineMid();
void testWrapLineAtEnd();
void testWrapLineAtStart();
void testUnWrapLine();
void testUnWrapLine1Empty();
void testUnWrapLine2Empty();
void testNavigation();
};
#endif
diff --git a/autotests/src/movingcursor_test.h b/autotests/src/movingcursor_test.h
index 6421ed2f..fc435194 100644
--- a/autotests/src/movingcursor_test.h
+++ b/autotests/src/movingcursor_test.h
@@ -1,40 +1,40 @@
/* This file is part of the KDE libraries
Copyright (C) 2010 Dominik Haumann
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public License
along with this library; see the file COPYING.LIB. If not, write to
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02110-1301, USA.
*/
#ifndef KATE_MOVINGCURSOR_TEST_H
#define KATE_MOVINGCURSOR_TEST_H
-#include
+#include
class MovingCursorTest : public QObject
{
Q_OBJECT
public:
MovingCursorTest();
~MovingCursorTest();
private Q_SLOTS:
void testMovingCursor();
void testConvenienceApi();
void testOperators();
void testInvalidMovingCursor();
};
#endif // KATE_MOVINGCURSOR_TEST_H
diff --git a/autotests/src/movingrange_test.cpp b/autotests/src/movingrange_test.cpp
index a4aae438..38f0b96e 100644
--- a/autotests/src/movingrange_test.cpp
+++ b/autotests/src/movingrange_test.cpp
@@ -1,443 +1,443 @@
/* This file is part of the KDE libraries
Copyright (C) 2010 Dominik Haumann
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public License
along with this library; see the file COPYING.LIB. If not, write to
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02110-1301, USA.
*/
#include "movingrange_test.h"
#include "moc_movingrange_test.cpp"
#include
#include
#include
#include
#include
#include
#include
using namespace KTextEditor;
QTEST_MAIN(MovingRangeTest)
class RangeFeedback : public MovingRangeFeedback
{
public:
RangeFeedback() : MovingRangeFeedback()
{
reset();
}
- void rangeEmpty(MovingRange * /*range*/) Q_DECL_OVERRIDE
+ void rangeEmpty(MovingRange * /*range*/) override
{
m_rangeEmptyCalled = true;
}
- void rangeInvalid(MovingRange * /*range*/) Q_DECL_OVERRIDE
+ void rangeInvalid(MovingRange * /*range*/) override
{
m_rangeInvalidCalled = true;
}
- void mouseEnteredRange(MovingRange * /*range*/, View * /*view*/) Q_DECL_OVERRIDE
+ void mouseEnteredRange(MovingRange * /*range*/, View * /*view*/) override
{
m_mouseEnteredRangeCalled = true;
}
- void mouseExitedRange(MovingRange * /*range*/, View * /*view*/) Q_DECL_OVERRIDE
+ void mouseExitedRange(MovingRange * /*range*/, View * /*view*/) override
{
m_mouseExitedRangeCalled = true;
}
- void caretEnteredRange(MovingRange * /*range*/, View * /*view*/) Q_DECL_OVERRIDE
+ void caretEnteredRange(MovingRange * /*range*/, View * /*view*/) override
{
m_caretEnteredRangeCalled = true;
}
- void caretExitedRange(MovingRange * /*range*/, View * /*view*/) Q_DECL_OVERRIDE
+ void caretExitedRange(MovingRange * /*range*/, View * /*view*/) override
{
m_caretExitedRangeCalled = true;
}
//
// Test functions to reset feedback watcher
//
public:
void reset()
{
m_rangeEmptyCalled = false;
m_rangeInvalidCalled = false;
m_mouseEnteredRangeCalled = false;
m_mouseExitedRangeCalled = false;
m_caretEnteredRangeCalled = false;
m_caretExitedRangeCalled = false;
}
void verifyReset()
{
QVERIFY(!m_rangeEmptyCalled);
QVERIFY(!m_rangeInvalidCalled);
QVERIFY(!m_mouseEnteredRangeCalled);
QVERIFY(!m_mouseExitedRangeCalled);
QVERIFY(!m_caretEnteredRangeCalled);
QVERIFY(!m_caretExitedRangeCalled);
}
bool rangeEmptyCalled() const
{
return m_rangeEmptyCalled;
}
bool rangeInvalidCalled() const
{
return m_rangeInvalidCalled;
}
bool mouseEnteredRangeCalled() const
{
return m_mouseEnteredRangeCalled;
}
bool mouseExitedRangeCalled() const
{
return m_mouseExitedRangeCalled;
}
bool caretEnteredRangeCalled() const
{
return m_caretEnteredRangeCalled;
}
bool caretExitedRangeCalled() const
{
return m_caretExitedRangeCalled;
}
private:
bool m_rangeEmptyCalled;
bool m_rangeInvalidCalled;
bool m_mouseEnteredRangeCalled;
bool m_mouseExitedRangeCalled;
bool m_caretEnteredRangeCalled;
bool m_caretExitedRangeCalled;
};
MovingRangeTest::MovingRangeTest()
: QObject()
{
KTextEditor::EditorPrivate::enableUnitTestMode();
}
MovingRangeTest::~MovingRangeTest()
{
}
// tests:
// - RangeFeedback::rangeEmpty
void MovingRangeTest::testFeedbackEmptyRange()
{
KTextEditor::DocumentPrivate doc;
// the range created below will span the 'x' characters
QString text("..xxxx\n"
"xxxx..");
doc.setText(text);
// create range feedback
RangeFeedback rf;
// allow empty
MovingRange *range = doc.newMovingRange(Range(Cursor(0, 2), Cursor(1, 4)),
KTextEditor::MovingRange::DoNotExpand,
KTextEditor::MovingRange::AllowEmpty);
range->setFeedback(&rf);
rf.verifyReset();
// remove exact range
doc.removeText(range->toRange());
QVERIFY(rf.rangeEmptyCalled());
QVERIFY(!rf.rangeInvalidCalled());
QVERIFY(!rf.mouseEnteredRangeCalled());
QVERIFY(!rf.mouseExitedRangeCalled());
QVERIFY(!rf.caretEnteredRangeCalled());
QVERIFY(!rf.caretExitedRangeCalled());
// clear document: should call rangeInvalid
rf.reset();
rf.verifyReset();
doc.clear();
QVERIFY(rf.rangeInvalidCalled());
QVERIFY(!rf.rangeEmptyCalled());
QVERIFY(!rf.mouseEnteredRangeCalled());
QVERIFY(!rf.mouseExitedRangeCalled());
QVERIFY(!rf.caretEnteredRangeCalled());
QVERIFY(!rf.caretExitedRangeCalled());
// setText: should behave just like clear document: call rangeInvalid again
doc.setText(text);
range->setRange(Range(Cursor(0, 2), Cursor(1, 4)));
rf.reset();
rf.verifyReset();
doc.setText("--yyyy\nyyyy--");
QVERIFY(rf.rangeInvalidCalled());
QVERIFY(!rf.rangeEmptyCalled());
QVERIFY(!rf.mouseEnteredRangeCalled());
QVERIFY(!rf.mouseExitedRangeCalled());
QVERIFY(!rf.caretEnteredRangeCalled());
QVERIFY(!rf.caretExitedRangeCalled());
// now remove entire document range. In this case, emptyRange should be called
// instead of rangeInvalid
doc.setText(text);
range->setRange(Range(Cursor(0, 2), Cursor(1, 4)));
rf.reset();
rf.verifyReset();
doc.removeText(doc.documentRange());
QVERIFY(rf.rangeEmptyCalled());
QVERIFY(!rf.rangeInvalidCalled());
QVERIFY(!rf.mouseEnteredRangeCalled());
QVERIFY(!rf.mouseExitedRangeCalled());
QVERIFY(!rf.caretEnteredRangeCalled());
QVERIFY(!rf.caretExitedRangeCalled());
}
// tests:
// - RangeFeedback::rangeInvalid
void MovingRangeTest::testFeedbackInvalidRange()
{
KTextEditor::DocumentPrivate doc;
// the range created below will span the 'x' characters
QString text("..xxxx\n"
"xxxx..");
doc.setText(text);
// create range feedback
RangeFeedback rf;
// allow empty
MovingRange *range = doc.newMovingRange(Range(Cursor(0, 2), Cursor(1, 4)),
KTextEditor::MovingRange::DoNotExpand,
KTextEditor::MovingRange::InvalidateIfEmpty);
range->setFeedback(&rf);
rf.verifyReset();
// remove exact range
doc.removeText(range->toRange());
QVERIFY(!rf.rangeEmptyCalled());
QVERIFY(rf.rangeInvalidCalled());
QVERIFY(!rf.mouseEnteredRangeCalled());
QVERIFY(!rf.mouseExitedRangeCalled());
QVERIFY(!rf.caretEnteredRangeCalled());
QVERIFY(!rf.caretExitedRangeCalled());
// clear document: should call rangeInvalid again
doc.setText(text);
range->setRange(Range(Cursor(0, 2), Cursor(1, 4)));
rf.reset();
rf.verifyReset();
doc.clear();
QVERIFY(rf.rangeInvalidCalled());
QVERIFY(!rf.rangeEmptyCalled());
QVERIFY(!rf.mouseEnteredRangeCalled());
QVERIFY(!rf.mouseExitedRangeCalled());
QVERIFY(!rf.caretEnteredRangeCalled());
QVERIFY(!rf.caretExitedRangeCalled());
// setText: should behave just like clear document: call rangeInvalid again
doc.setText(text);
range->setRange(Range(Cursor(0, 2), Cursor(1, 4)));
rf.reset();
rf.verifyReset();
doc.setText("--yyyy\nyyyy--");
QVERIFY(rf.rangeInvalidCalled());
QVERIFY(!rf.rangeEmptyCalled());
QVERIFY(!rf.mouseEnteredRangeCalled());
QVERIFY(!rf.mouseExitedRangeCalled());
QVERIFY(!rf.caretEnteredRangeCalled());
QVERIFY(!rf.caretExitedRangeCalled());
// now remove entire document range. Call rangeInvalid again
doc.setText(text);
range->setRange(Range(Cursor(0, 2), Cursor(1, 4)));
rf.reset();
rf.verifyReset();
doc.removeText(doc.documentRange());
QVERIFY(rf.rangeInvalidCalled());
QVERIFY(!rf.rangeEmptyCalled());
QVERIFY(!rf.mouseEnteredRangeCalled());
QVERIFY(!rf.mouseExitedRangeCalled());
QVERIFY(!rf.caretEnteredRangeCalled());
QVERIFY(!rf.caretExitedRangeCalled());
}
// tests:
// - RangeFeedback::caretEnteredRange
// - RangeFeedback::caretExitedRange
void MovingRangeTest::testFeedbackCaret()
{
KTextEditor::DocumentPrivate doc;
// the range created below will span the 'x' characters
QString text("..xxxx\n"
"xxxx..");
doc.setText(text);
KTextEditor::ViewPrivate *view = static_cast(doc.createView(nullptr));
// create range feedback
RangeFeedback rf;
// first test: with ExpandLeft | ExpandRight
{
view->setCursorPosition(Cursor(1, 6));
MovingRange *range = doc.newMovingRange(Range(Cursor(0, 2), Cursor(1, 4)),
KTextEditor::MovingRange::ExpandLeft |
KTextEditor::MovingRange::ExpandRight,
KTextEditor::MovingRange::InvalidateIfEmpty);
rf.reset();
range->setFeedback(&rf);
rf.verifyReset();
// left
view->cursorLeft();
QCOMPARE(view->cursorPosition(), Cursor(1, 5));
QVERIFY(!rf.caretEnteredRangeCalled());
QVERIFY(!rf.caretExitedRangeCalled());
view->cursorLeft();
QCOMPARE(view->cursorPosition(), Cursor(1, 4));
QVERIFY(rf.caretEnteredRangeCalled()); // ExpandRight: include cursor already now
QVERIFY(!rf.caretExitedRangeCalled());
rf.reset();
view->cursorLeft();
QCOMPARE(view->cursorPosition(), Cursor(1, 3));
QVERIFY(!rf.caretEnteredRangeCalled());
QVERIFY(!rf.caretExitedRangeCalled());
rf.reset();
view->up();
QCOMPARE(view->cursorPosition(), Cursor(0, 3));
QVERIFY(!rf.caretEnteredRangeCalled());
QVERIFY(!rf.caretExitedRangeCalled());
rf.reset();
view->cursorLeft();
QCOMPARE(view->cursorPosition(), Cursor(0, 2));
QVERIFY(!rf.caretEnteredRangeCalled());
QVERIFY(!rf.caretExitedRangeCalled());
rf.reset();
view->cursorLeft();
QCOMPARE(view->cursorPosition(), Cursor(0, 1)); // ExpandLeft: now we left it, not before
QVERIFY(!rf.caretEnteredRangeCalled());
QVERIFY(rf.caretExitedRangeCalled());
delete range;
}
// second test: with DoNotExpand
{
view->setCursorPosition(Cursor(1, 6));
MovingRange *range = doc.newMovingRange(Range(Cursor(0, 2), Cursor(1, 4)),
KTextEditor::MovingRange::DoNotExpand,
KTextEditor::MovingRange::InvalidateIfEmpty);
rf.reset();
range->setFeedback(&rf);
rf.verifyReset();
// left
view->cursorLeft();
QCOMPARE(view->cursorPosition(), Cursor(1, 5));
QVERIFY(!rf.caretEnteredRangeCalled());
QVERIFY(!rf.caretExitedRangeCalled());
view->cursorLeft();
QCOMPARE(view->cursorPosition(), Cursor(1, 4));
QVERIFY(!rf.caretEnteredRangeCalled()); // DoNotExpand: does not include cursor
QVERIFY(!rf.caretExitedRangeCalled());
rf.reset();
view->cursorLeft();
QCOMPARE(view->cursorPosition(), Cursor(1, 3));
QVERIFY(rf.caretEnteredRangeCalled());
QVERIFY(!rf.caretExitedRangeCalled());
rf.reset();
view->up();
QCOMPARE(view->cursorPosition(), Cursor(0, 3));
QVERIFY(!rf.caretEnteredRangeCalled());
QVERIFY(!rf.caretExitedRangeCalled());
rf.reset();
view->cursorLeft();
QCOMPARE(view->cursorPosition(), Cursor(0, 2));
QVERIFY(!rf.caretEnteredRangeCalled());
QVERIFY(rf.caretExitedRangeCalled()); // DoNotExpand: that's why we leave already now
rf.reset();
view->cursorLeft();
QCOMPARE(view->cursorPosition(), Cursor(0, 1));
QVERIFY(!rf.caretEnteredRangeCalled());
QVERIFY(!rf.caretExitedRangeCalled());
delete range;
}
}
// tests:
// - RangeFeedback::mouseEnteredRange
// - RangeFeedback::mouseExitedRange
void MovingRangeTest::testFeedbackMouse()
{
KTextEditor::DocumentPrivate doc;
// the range created below will span the 'x' characters
QString text("..xxxx\n"
"xxxx..");
doc.setText(text);
KTextEditor::ViewPrivate *view = static_cast(doc.createView(nullptr));
view->setCursorPosition(Cursor(1, 6));
view->show();
view->resize(200, 100);
// create range feedback
RangeFeedback rf;
QVERIFY(!rf.mouseEnteredRangeCalled());
QVERIFY(!rf.mouseExitedRangeCalled());
// allow empty
MovingRange *range = doc.newMovingRange(Range(Cursor(0, 2), Cursor(1, 4)),
KTextEditor::MovingRange::ExpandLeft |
KTextEditor::MovingRange::ExpandRight,
KTextEditor::MovingRange::InvalidateIfEmpty);
range->setFeedback(&rf);
rf.verifyReset();
// left (nothing)
QTest::mouseMove(view, view->cursorToCoordinate(Cursor(0, 0)) + QPoint(0, 5));
QTest::qWait(200); // process mouse events. do not move mouse manually
QVERIFY(!rf.mouseEnteredRangeCalled());
QVERIFY(!rf.mouseExitedRangeCalled());
// middle (enter)
rf.reset();
QTest::mouseMove(view, view->cursorToCoordinate(Cursor(0, 3)) + QPoint(0, 5));
QTest::qWait(200); // process mouse events. do not move mouse manually
QVERIFY(rf.mouseEnteredRangeCalled());
QVERIFY(!rf.mouseExitedRangeCalled());
// right (exit)
rf.reset();
QTest::mouseMove(view, view->cursorToCoordinate(Cursor(1, 6)) + QPoint(10, 5));
QTest::qWait(200); // process mouse events. do not move mouse manually
QVERIFY(!rf.mouseEnteredRangeCalled());
QVERIFY(rf.mouseExitedRangeCalled());
}
diff --git a/autotests/src/movingrange_test.h b/autotests/src/movingrange_test.h
index fae44bd5..132064ac 100644
--- a/autotests/src/movingrange_test.h
+++ b/autotests/src/movingrange_test.h
@@ -1,40 +1,40 @@
/* This file is part of the KDE libraries
Copyright (C) 2010 Dominik Haumann
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public License
along with this library; see the file COPYING.LIB. If not, write to
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02110-1301, USA.
*/
#ifndef KATE_MOVINGRANGE_TEST_H
#define KATE_MOVINGRANGE_TEST_H
-#include
+#include
class MovingRangeTest : public QObject
{
Q_OBJECT
public:
MovingRangeTest();
~MovingRangeTest();
private Q_SLOTS:
void testFeedbackEmptyRange();
void testFeedbackInvalidRange();
void testFeedbackCaret();
void testFeedbackMouse();
};
#endif // KATE_MOVINGRANGE_TEST_H
diff --git a/autotests/src/plaintextsearch_test.cpp b/autotests/src/plaintextsearch_test.cpp
index 179e9bf1..5fe24623 100644
--- a/autotests/src/plaintextsearch_test.cpp
+++ b/autotests/src/plaintextsearch_test.cpp
@@ -1,169 +1,167 @@
/* This file is part of the KDE libraries
Copyright (C) 2010 Bernhard Beschow
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public License
along with this library; see the file COPYING.LIB. If not, write to
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02110-1301, USA.
*/
#include "plaintextsearch_test.h"
#include "moc_plaintextsearch_test.cpp"
#include
#include
#include
#include
QTEST_MAIN(PlainTextSearchTest)
QtMessageHandler PlainTextSearchTest::s_msgHandler = nullptr;
void myMessageOutput(QtMsgType type, const QMessageLogContext &context, const QString &msg)
{
switch (type) {
case QtDebugMsg:
/* do nothing */
break;
default:
PlainTextSearchTest::s_msgHandler(type, context, msg);
}
}
void PlainTextSearchTest::initTestCase()
{
KTextEditor::EditorPrivate::enableUnitTestMode();
s_msgHandler = qInstallMessageHandler(myMessageOutput);
}
void PlainTextSearchTest::cleanupTestCase()
{
qInstallMessageHandler(nullptr);
}
PlainTextSearchTest::PlainTextSearchTest()
: QObject()
- , m_doc(nullptr)
- , m_search(nullptr)
{
}
PlainTextSearchTest::~PlainTextSearchTest()
{
}
void PlainTextSearchTest::init()
{
m_doc = new KTextEditor::DocumentPrivate(false, false, nullptr, this);
m_search = new KatePlainTextSearch(m_doc, Qt::CaseSensitive, false);
}
void PlainTextSearchTest::cleanup()
{
delete m_search;
delete m_doc;
}
void PlainTextSearchTest::testSearchBackward_data()
{
QTest::addColumn("searchRange");
QTest::addColumn("expectedResult");
QTest::newRow("") << KTextEditor::Range(0, 0, 1, 10) << KTextEditor::Range(1, 6, 1, 10);
QTest::newRow("") << KTextEditor::Range(0, 0, 1, 5) << KTextEditor::Range(1, 0, 1, 4);
QTest::newRow("") << KTextEditor::Range(0, 0, 1, 0) << KTextEditor::Range(0, 10, 0, 14);
}
void PlainTextSearchTest::testSearchBackward()
{
QFETCH(KTextEditor::Range, searchRange);
QFETCH(KTextEditor::Range, expectedResult);
m_doc->setText(QLatin1String("aaaa aaaa aaaa\n"
"aaaa aaaa"));
QCOMPARE(m_search->search(QLatin1String("aaaa"), searchRange, true), expectedResult);
}
void PlainTextSearchTest::testSingleLineDocument_data()
{
QTest::addColumn("searchRange");
QTest::addColumn("forwardResult");
QTest::addColumn("backwardResult");
QTest::newRow("[a a a a a a a a a a a a]") << KTextEditor::Range(0, 0, 0, 23) << KTextEditor::Range(0, 0, 0, 5) << KTextEditor::Range(0, 18, 0, 23);
QTest::newRow("[a a a a a a a a a a a ]a") << KTextEditor::Range(0, 0, 0, 22) << KTextEditor::Range(0, 0, 0, 5) << KTextEditor::Range(0, 16, 0, 21);
QTest::newRow("a[ a a a a a a a a a a a]") << KTextEditor::Range(0, 1, 0, 23) << KTextEditor::Range(0, 2, 0, 7) << KTextEditor::Range(0, 18, 0, 23);
QTest::newRow("a[ a a a a a a a a a a ]a") << KTextEditor::Range(0, 1, 0, 22) << KTextEditor::Range(0, 2, 0, 7) << KTextEditor::Range(0, 16, 0, 21);
QTest::newRow("[a a a a] a a a a a a a a") << KTextEditor::Range(0, 0, 0, 7) << KTextEditor::Range(0, 0, 0, 5) << KTextEditor::Range(0, 2, 0, 7);
QTest::newRow("[a a a ]a a a a a a a a a") << KTextEditor::Range(0, 0, 0, 6) << KTextEditor::Range(0, 0, 0, 5) << KTextEditor::Range(0, 0, 0, 5);
QTest::newRow("[a a a] a a a a a a a a a") << KTextEditor::Range(0, 0, 0, 5) << KTextEditor::Range(0, 0, 0, 5) << KTextEditor::Range(0, 0, 0, 5);
QTest::newRow("[a a ]a a a a a a a a a a") << KTextEditor::Range(0, 0, 0, 4) << KTextEditor::Range::invalid() << KTextEditor::Range::invalid();
QTest::newRow("a a a a a a a a [a a a a]") << KTextEditor::Range(0, 16, 0, 23) << KTextEditor::Range(0, 16, 0, 21) << KTextEditor::Range(0, 18, 0, 23);
QTest::newRow("a a a a a a a a a[ a a a]") << KTextEditor::Range(0, 17, 0, 23) << KTextEditor::Range(0, 18, 0, 23) << KTextEditor::Range(0, 18, 0, 23);
QTest::newRow("a a a a a a a a a [a a a]") << KTextEditor::Range(0, 18, 0, 23) << KTextEditor::Range(0, 18, 0, 23) << KTextEditor::Range(0, 18, 0, 23);
QTest::newRow("a a a a a a a a a a[ a a]") << KTextEditor::Range(0, 19, 0, 23) << KTextEditor::Range::invalid() << KTextEditor::Range::invalid();
QTest::newRow("a a a a a[ a a a a] a a a") << KTextEditor::Range(0, 9, 0, 17) << KTextEditor::Range(0, 10, 0, 15) << KTextEditor::Range(0, 12, 0, 17);
QTest::newRow("a a a a a[ a a] a a a a a") << KTextEditor::Range(0, 9, 0, 13) << KTextEditor::Range::invalid() << KTextEditor::Range::invalid();
}
void PlainTextSearchTest::testSingleLineDocument()
{
QFETCH(KTextEditor::Range, searchRange);
QFETCH(KTextEditor::Range, forwardResult);
QFETCH(KTextEditor::Range, backwardResult);
m_doc->setText(QLatin1String("a a a a a a a a a a a a"));
QCOMPARE(m_search->search(QLatin1String("a a a"), searchRange, false), forwardResult);
QCOMPARE(m_search->search(QLatin1String("a a a"), searchRange, true), backwardResult);
}
void PlainTextSearchTest::testMultilineSearch_data()
{
QTest::addColumn("pattern");
QTest::addColumn("inputRange");
QTest::addColumn("forwardResult");
QTest::newRow("") << "a a a\na a\na a a" << KTextEditor::Range(0, 0, 2, 5) << KTextEditor::Range(0, 0, 2, 5);
QTest::newRow("") << "a a a\na a\na a " << KTextEditor::Range(0, 0, 2, 5) << KTextEditor::Range(0, 0, 2, 4);
QTest::newRow("") << "a a a\na a\na a" << KTextEditor::Range(0, 0, 2, 5) << KTextEditor::Range(0, 0, 2, 3);
QTest::newRow("") << "a a a\na a\na" << KTextEditor::Range(0, 0, 2, 5) << KTextEditor::Range(0, 0, 2, 1);
QTest::newRow("") << "a a a\na a\n" << KTextEditor::Range(0, 0, 2, 5) << KTextEditor::Range(0, 0, 2, 0);
QTest::newRow("") << "a a a\na a" << KTextEditor::Range(0, 0, 2, 5) << KTextEditor::Range(0, 0, 1, 3);
QTest::newRow("") << "a a\na a" << KTextEditor::Range(0, 0, 2, 5) << KTextEditor::Range(0, 2, 1, 3);
QTest::newRow("") << "a a\na a\na a" << KTextEditor::Range(0, 0, 2, 5) << KTextEditor::Range(0, 2, 2, 3);
QTest::newRow("") << "\na a\na a" << KTextEditor::Range(0, 0, 2, 5) << KTextEditor::Range(0, 5, 2, 3);
QTest::newRow("") << "\na a\n" << KTextEditor::Range(0, 0, 2, 5) << KTextEditor::Range(0, 5, 2, 0);
QTest::newRow("") << "a a a\na a\na a a" << KTextEditor::Range(0, 0, 2, 4) << KTextEditor::Range::invalid();
QTest::newRow("") << "a a a\na a\na a " << KTextEditor::Range(0, 0, 2, 4) << KTextEditor::Range(0, 0, 2, 4);
QTest::newRow("") << "a a a\na a\n" << KTextEditor::Range(0, 0, 2, 0) << KTextEditor::Range(0, 0, 2, 0);
QTest::newRow("") << "a a a\na a\n" << KTextEditor::Range(0, 0, 1, 3) << KTextEditor::Range::invalid();
QTest::newRow("") << "a a\n" << KTextEditor::Range(0, 0, 1, 3) << KTextEditor::Range(0, 2, 1, 0);
QTest::newRow("") << "a \n" << KTextEditor::Range(0, 0, 1, 3) << KTextEditor::Range::invalid();
}
void PlainTextSearchTest::testMultilineSearch()
{
QFETCH(QString, pattern);
QFETCH(KTextEditor::Range, inputRange);
QFETCH(KTextEditor::Range, forwardResult);
m_doc->setText(QLatin1String("a a a\n"
"a a\n"
"a a a"));
QCOMPARE(m_search->search(pattern, inputRange, false), forwardResult);
}
diff --git a/autotests/src/plaintextsearch_test.h b/autotests/src/plaintextsearch_test.h
index 2c35fbe4..e1617d91 100644
--- a/autotests/src/plaintextsearch_test.h
+++ b/autotests/src/plaintextsearch_test.h
@@ -1,60 +1,60 @@
/* This file is part of the KDE libraries
Copyright (C) 2010 Bernhard Beschow
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public License
along with this library; see the file COPYING.LIB. If not, write to
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02110-1301, USA.
*/
#ifndef KATE_PLAINTEXTSEARCH_TEST_H
#define KATE_PLAINTEXTSEARCH_TEST_H
-#include
+#include
namespace KTextEditor { class DocumentPrivate; }
class KatePlainTextSearch;
class PlainTextSearchTest : public QObject
{
Q_OBJECT
public:
PlainTextSearchTest();
virtual ~PlainTextSearchTest();
private Q_SLOTS:
void initTestCase();
void cleanupTestCase();
void init();
void cleanup();
void testSearchBackward_data();
void testSearchBackward();
void testSingleLineDocument_data();
void testSingleLineDocument();
void testMultilineSearch_data();
void testMultilineSearch();
private:
- KTextEditor::DocumentPrivate *m_doc;
- KatePlainTextSearch *m_search;
+ KTextEditor::DocumentPrivate *m_doc = nullptr;
+ KatePlainTextSearch *m_search = nullptr;
public:
static QtMessageHandler s_msgHandler;
};
#endif
diff --git a/autotests/src/range_test.h b/autotests/src/range_test.h
index 7fa5a07a..c16caeed 100644
--- a/autotests/src/range_test.h
+++ b/autotests/src/range_test.h
@@ -1,48 +1,48 @@
/* This file is part of the KDE libraries
Copyright (C) 2010 Christoph Cullmann
Copyright (C) 2005 Hamish Rodda
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public License
along with this library; see the file COPYING.LIB. If not, write to
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02110-1301, USA.
*/
#ifndef KATE_RANGE_TEST_H
#define KATE_RANGE_TEST_H
-#include
+#include
#include
class RangeTest : public QObject
{
Q_OBJECT
public:
RangeTest();
~RangeTest();
private Q_SLOTS:
void testTextEditorRange();
void testTextRange();
void testInsertText();
void testCornerCaseInsertion();
void testCursorStringConversion();
void testRangeStringConversion();
private:
void rangeCheck(KTextEditor::Range &valid);
};
#endif
diff --git a/autotests/src/regexpsearch_test.h b/autotests/src/regexpsearch_test.h
index e09579d2..e0a47c9f 100644
--- a/autotests/src/regexpsearch_test.h
+++ b/autotests/src/regexpsearch_test.h
@@ -1,57 +1,57 @@
/* This file is part of the KDE libraries
Copyright (C) 2010 Bernhard Beschow
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public License
along with this library; see the file COPYING.LIB. If not, write to
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02110-1301, USA.
*/
#ifndef KATE_REGEXPSEARCH_TEST_H
#define KATE_REGEXPSEARCH_TEST_H
-#include
+#include
class RegExpSearchTest : public QObject
{
Q_OBJECT
public:
RegExpSearchTest();
virtual ~RegExpSearchTest();
private Q_SLOTS:
void testReplaceEscapeSequences_data();
void testReplaceEscapeSequences();
void testReplacementReferences_data();
void testReplacementReferences();
void testReplacementCaseConversion_data();
void testReplacementCaseConversion();
void testReplacementCounter_data();
void testReplacementCounter();
void testAnchoredRegexp_data();
void testAnchoredRegexp();
void testSearchForward();
void testSearchBackwardInSelection();
void test();
};
#endif
diff --git a/autotests/src/revision_test.h b/autotests/src/revision_test.h
index 8e5988d0..bdd0369d 100644
--- a/autotests/src/revision_test.h
+++ b/autotests/src/revision_test.h
@@ -1,38 +1,38 @@
/* This file is part of the KDE libraries
Copyright (C) 2010 Dominik Haumann
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public License
along with this library; see the file COPYING.LIB. If not, write to
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02110-1301, USA.
*/
#ifndef KATE_REVISION_TEST_H
#define KATE_REVISION_TEST_H
-#include
+#include
class RevisionTest : public QObject
{
Q_OBJECT
public:
RevisionTest();
~RevisionTest();
private Q_SLOTS:
void testTransformCursor();
void testTransformRange();
};
#endif // KATE_REVISION_TEST_H
diff --git a/autotests/src/script_test_base.h b/autotests/src/script_test_base.h
index 04d6cb6a..89222042 100644
--- a/autotests/src/script_test_base.h
+++ b/autotests/src/script_test_base.h
@@ -1,56 +1,56 @@
/*
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public License
along with this library; see the file COPYING.LIB. If not, write to
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02110-1301, USA.
*/
#ifndef SCRIPT_TEST_H
#define SCRIPT_TEST_H
-#include
-#include
-#include
+#include
+#include
+#include
class TestScriptEnv;
namespace KTextEditor { class DocumentPrivate; }
namespace KTextEditor { class ViewPrivate; }
class QMainWindow;
class ScriptTestBase : public QObject
{
Q_OBJECT
protected:
void initTestCase();
void cleanupTestCase();
typedef QPair Failure;
typedef QList ExpectedFailures;
void getTestData(const QString &script);
void runTest(const ExpectedFailures &failures);
QByteArray digestForFile(const QString &file);
TestScriptEnv *m_env;
KTextEditor::DocumentPrivate *m_document;
QMainWindow *m_toplevel;
bool m_outputWasCustomised;
QStringList m_commands;
KTextEditor::ViewPrivate *m_view;
QString m_section; // dir name in testdata/
QString m_script_dir; // dir name in part/script/data/
public:
static QtMessageHandler m_msgHandler;
};
#endif // SCRIPT_TEST_H
diff --git a/autotests/src/scriptdocument_test.cpp b/autotests/src/scriptdocument_test.cpp
index ce85e36d..5f587f46 100644
--- a/autotests/src/scriptdocument_test.cpp
+++ b/autotests/src/scriptdocument_test.cpp
@@ -1,131 +1,128 @@
/* This file is part of the KDE libraries
Copyright (C) 2010 Bernhard Beschow
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public License
along with this library; see the file COPYING.LIB. If not, write to
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02110-1301, USA.
*/
#include "scriptdocument_test.h"
#include
#include "ktexteditor/cursor.h"
#include
#include
#include
#include
#include
QTEST_MAIN(ScriptDocumentTest)
QtMessageHandler ScriptDocumentTest::s_msgHandler = nullptr;
void myMessageOutput(QtMsgType type, const QMessageLogContext &context, const QString &msg)
{
switch (type) {
case QtDebugMsg:
/* do nothing */
break;
default:
ScriptDocumentTest::s_msgHandler(type, context, msg);
}
}
void ScriptDocumentTest::initTestCase()
{
KTextEditor::EditorPrivate::enableUnitTestMode();
s_msgHandler = qInstallMessageHandler(myMessageOutput);
}
void ScriptDocumentTest::cleanupTestCase()
{
qInstallMessageHandler(nullptr);
}
ScriptDocumentTest::ScriptDocumentTest()
: QObject()
- , m_doc(nullptr)
- , m_view(nullptr)
- , m_scriptDoc(nullptr)
{
}
ScriptDocumentTest::~ScriptDocumentTest()
{
}
void ScriptDocumentTest::init()
{
m_doc = new KTextEditor::DocumentPrivate;
m_view = m_doc->createView(nullptr);
m_scriptDoc = new KateScriptDocument(nullptr, this);
m_scriptDoc->setDocument(m_doc);
}
void ScriptDocumentTest::cleanup()
{
delete m_scriptDoc;
delete m_view;
delete m_doc;
}
#if 0
void ScriptDocumentTest::testRfind_data()
{
QTest::addColumn("searchRange");
QTest::addColumn("expectedResult");
QTest::newRow("") << KTextEditor::Range(0, 0, 1, 10) << KTextEditor::Range(1, 6, 1, 10);
QTest::newRow("") << KTextEditor::Range(0, 0, 1, 5) << KTextEditor::Range(1, 0, 1, 4);
QTest::newRow("") << KTextEditor::Range(0, 0, 1, 0) << KTextEditor::Range(0, 10, 0, 14);
}
void ScriptDocumentTest::testRfind()
{
QFETCH(KTextEditor::Range, searchRange);
QFETCH(KTextEditor::Range, expectedResult);
m_doc->setText("aaaa aaaa aaaa\n"
"aaaa aaaa");
QCOMPARE(m_search->search(searchRange, "aaaa", true), expectedResult);
}
#endif
void ScriptDocumentTest::testRfind_data()
{
QTest::addColumn("searchStart");
QTest::addColumn("result");
QTest::newRow("a a a a a a a a a a a a|") << KTextEditor::Cursor(0, 23) << KTextEditor::Cursor(0, 18);
QTest::newRow("a a a a a a a a a a a |a") << KTextEditor::Cursor(0, 22) << KTextEditor::Cursor(0, 16);
QTest::newRow("a a a a| a a a a a a a a") << KTextEditor::Cursor(0, 7) << KTextEditor::Cursor(0, 2);
QTest::newRow("a a a |a a a a a a a a a") << KTextEditor::Cursor(0, 6) << KTextEditor::Cursor(0, 0);
QTest::newRow("a a a| a a a a a a a a a") << KTextEditor::Cursor(0, 5) << KTextEditor::Cursor(0, 0);
QTest::newRow("a a |a a a a a a a a a a") << KTextEditor::Cursor(0, 4) << KTextEditor::Cursor::invalid();
}
void ScriptDocumentTest::testRfind()
{
QFETCH(KTextEditor::Cursor, searchStart);
QFETCH(KTextEditor::Cursor, result);
m_scriptDoc->setText("a a a a a a a a a a a a");
KTextEditor::Cursor cursor = m_scriptDoc->rfind(searchStart, "a a a");
QCOMPARE(cursor, result);
}
#include "moc_scriptdocument_test.cpp"
diff --git a/autotests/src/scriptdocument_test.h b/autotests/src/scriptdocument_test.h
index 3e684085..91fb74f9 100644
--- a/autotests/src/scriptdocument_test.h
+++ b/autotests/src/scriptdocument_test.h
@@ -1,60 +1,60 @@
/* This file is part of the KDE libraries
Copyright (C) 2010 Bernhard Beschow
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public License
along with this library; see the file COPYING.LIB. If not, write to
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02110-1301, USA.
*/
#ifndef KATE_SCRIPTDOCUMENT_TEST_H
#define KATE_SCRIPTDOCUMENT_TEST_H
-#include
+#include
namespace KTextEditor
{
class View;
}
namespace KTextEditor { class DocumentPrivate; }
class KateScriptDocument;
class ScriptDocumentTest : public QObject
{
Q_OBJECT
public:
ScriptDocumentTest();
virtual ~ScriptDocumentTest();
private Q_SLOTS:
void initTestCase();
void cleanupTestCase();
void init();
void cleanup();
void testRfind_data();
void testRfind();
private:
- KTextEditor::DocumentPrivate *m_doc;
- KTextEditor::View *m_view;
- KateScriptDocument *m_scriptDoc;
+ KTextEditor::DocumentPrivate *m_doc = nullptr;
+ KTextEditor::View *m_view = nullptr;
+ KateScriptDocument *m_scriptDoc = nullptr;
public:
static QtMessageHandler s_msgHandler;
};
#endif
diff --git a/autotests/src/scripting_test.cpp b/autotests/src/scripting_test.cpp
index f54c1fd6..a62193e2 100644
--- a/autotests/src/scripting_test.cpp
+++ b/autotests/src/scripting_test.cpp
@@ -1,74 +1,74 @@
/**
* This file is part of the KDE project
*
* Copyright (C) 2013 Gerald Senarclens de Grancy
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public License
* along with this library; see the file COPYING.LIB. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*
*/
//BEGIN Includes
#include "scripting_test.h"
#include "kateview.h"
#include "katedocument.h"
#include "kateconfig.h"
#include "katecmd.h"
#include "kateglobal.h"
#include
#include
#include
#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
+#include
#include
#include "script_test_base.h"
#include "testutils.h"
QTEST_MAIN(ScriptingTest)
#define FAILURE( test, comment ) qMakePair( (test), (comment) )
void ScriptingTest::initTestCase()
{
ScriptTestBase::initTestCase();
m_section = "scripting";
m_script_dir = "";
}
void ScriptingTest::bugs_data()
{
getTestData("bugs");
}
void ScriptingTest::bugs()
{
runTest(ExpectedFailures());
}
diff --git a/autotests/src/scripting_test.h b/autotests/src/scripting_test.h
index 3b226f23..06d190ee 100644
--- a/autotests/src/scripting_test.h
+++ b/autotests/src/scripting_test.h
@@ -1,35 +1,35 @@
/*
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public License
along with this library; see the file COPYING.LIB. If not, write to
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02110-1301, USA.
*/
#ifndef SCRIPTINGTEST_H
#define SCRIPTINGTEST_H
-#include
+#include
#include "script_test_base.h"
class ScriptingTest : public ScriptTestBase
{
Q_OBJECT
private Q_SLOTS:
void initTestCase();
void bugs_data();
void bugs();
};
#endif // SCRIPTINGTEST_H
diff --git a/autotests/src/searchbar_test.h b/autotests/src/searchbar_test.h
index 0fa1cb5e..1fc9eed3 100644
--- a/autotests/src/searchbar_test.h
+++ b/autotests/src/searchbar_test.h
@@ -1,79 +1,79 @@
/* This file is part of the KDE libraries
Copyright (C) 2010 Bernhard Beschow
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public License
along with this library; see the file COPYING.LIB. If not, write to
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02110-1301, USA.
*/
#ifndef KATE_SEARCHBAR_TEST_H
#define KATE_SEARCHBAR_TEST_H
-#include
+#include
class SearchBarTest : public QObject
{
Q_OBJECT
public:
SearchBarTest();
~SearchBarTest();
public Q_SLOTS:
void initTestCase();
void cleanupTestCase();
private Q_SLOTS:
void testFindNextIncremental();
void testSetMatchCaseIncremental();
void testSetMatchCasePower();
void testSetSelectionOnlyPower();
void testSetSearchPattern_data();
void testSetSearchPattern();
void testSetSelectionOnly();
void testFindAll_data();
void testFindAll();
void testReplaceAll();
void testFindSelectionForward_data();
void testFindSelectionForward();
void testRemoveWithSelectionForward_data();
void testRemoveWithSelectionForward();
void testRemoveInSelectionForward_data();
void testRemoveInSelectionForward();
void testReplaceWithDoubleSelecion_data();
void testReplaceWithDoubleSelecion();
void testReplaceDollar();
void testSearchHistoryIncremental();
void testSearchHistoryPower();
void testReplaceInBlockMode();
void testReplaceManyCapturesBug365124();
};
#endif
diff --git a/autotests/src/templatehandler_test.h b/autotests/src/templatehandler_test.h
index 055f6cdb..d396629a 100644
--- a/autotests/src/templatehandler_test.h
+++ b/autotests/src/templatehandler_test.h
@@ -1,63 +1,63 @@
/* This file is part of the KDE libraries
Copyright (C) 2010 Bernhard Beschow
Copyright (C) 2014 Sven Brauch
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public License
along with this library; see the file COPYING.LIB. If not, write to
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02110-1301, USA.
*/
#ifndef KATE_UNDOMANAGER_TEST_H
#define KATE_UNDOMANAGER_TEST_H
-#include
+#include
class TemplateHandlerTest : public QObject
{
Q_OBJECT
public:
TemplateHandlerTest();
private Q_SLOTS:
void testUndo();
void testSimpleMirror();
void testSimpleMirror_data();
void testDefaults();
void testDefaults_data();
void testDefaultMirror();
void testFunctionMirror();
void testNotEditableFields();
void testNotEditableFields_data();
void testAdjacentRanges();
void testTab();
void testTab_data();
void testExitAtCursor();
void testAutoSelection();
void testCanRetrieveSelection();
void testEscapes();
};
#endif
diff --git a/autotests/src/testutils.h b/autotests/src/testutils.h
index 9feab271..5a76bad5 100644
--- a/autotests/src/testutils.h
+++ b/autotests/src/testutils.h
@@ -1,204 +1,204 @@
/**
* This file is part of the KDE project
*
* Copyright (C) 2001,2003 Peter Kelly (pmk@post.com)
* Copyright 2006, 2007 Leo Savernik (l.savernik@aon.at)
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public License
* along with this library; see the file COPYING.LIB. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*
*/
#ifndef TESTUTILS_H
#define TESTUTILS_H
#include "katescriptview.h"
#include "katescriptdocument.h"
-#include
+#include
namespace KTextEditor { class ViewPrivate; }
class RegressionTest;
class KCmdLineArgs;
class OutputObject;
class KateViewObject;
class KateDocumentObject;
/**
* @internal
* The backbone of Kate's automatic regression tests.
*/
class TestScriptEnv : public QObject
{
public:
explicit TestScriptEnv(KTextEditor::DocumentPrivate *part, bool &cflag);
virtual ~TestScriptEnv();
QJSEngine *engine() const
{
return m_engine;
}
/** returns the output object */
OutputObject *output() const
{
return m_output;
}
private:
QJSEngine *m_engine;
KateViewObject *m_viewObj;
KateDocumentObject *m_docObj;
OutputObject *m_output;
};
/**
* @internal
*/
class KateViewObject : public KateScriptView
{
Q_OBJECT
public:
explicit KateViewObject(QJSEngine *engine, KTextEditor::ViewPrivate *view);
virtual ~KateViewObject();
// Edit functions
Q_INVOKABLE void keyReturn(int cnt = 1);
Q_INVOKABLE void backspace(int cnt = 1);
Q_INVOKABLE void deleteWordLeft(int cnt = 1);
Q_INVOKABLE void keyDelete(int cnt = 1);
Q_INVOKABLE void deleteWordRight(int cnt = 1);
Q_INVOKABLE void transpose(int cnt = 1);
Q_INVOKABLE void cursorLeft(int cnt = 1);
Q_INVOKABLE void shiftCursorLeft(int cnt = 1);
Q_INVOKABLE void cursorRight(int cnt = 1);
Q_INVOKABLE void shiftCursorRight(int cnt = 1);
Q_INVOKABLE void wordLeft(int cnt = 1);
Q_INVOKABLE void shiftWordLeft(int cnt = 1);
Q_INVOKABLE void wordRight(int cnt = 1);
Q_INVOKABLE void shiftWordRight(int cnt = 1);
Q_INVOKABLE void home(int cnt = 1);
Q_INVOKABLE void shiftHome(int cnt = 1);
Q_INVOKABLE void end(int cnt = 1);
Q_INVOKABLE void shiftEnd(int cnt = 1);
Q_INVOKABLE void up(int cnt = 1);
Q_INVOKABLE void shiftUp(int cnt = 1);
Q_INVOKABLE void down(int cnt = 1);
Q_INVOKABLE void shiftDown(int cnt = 1);
Q_INVOKABLE void scrollUp(int cnt = 1);
Q_INVOKABLE void scrollDown(int cnt = 1);
Q_INVOKABLE void topOfView(int cnt = 1);
Q_INVOKABLE void shiftTopOfView(int cnt = 1);
Q_INVOKABLE void bottomOfView(int cnt = 1);
Q_INVOKABLE void shiftBottomOfView(int cnt = 1);
Q_INVOKABLE void pageUp(int cnt = 1);
Q_INVOKABLE void shiftPageUp(int cnt = 1);
Q_INVOKABLE void pageDown(int cnt = 1);
Q_INVOKABLE void shiftPageDown(int cnt = 1);
Q_INVOKABLE void top(int cnt = 1);
Q_INVOKABLE void shiftTop(int cnt = 1);
Q_INVOKABLE void bottom(int cnt = 1);
Q_INVOKABLE void shiftBottom(int cnt = 1);
Q_INVOKABLE void toMatchingBracket(int cnt = 1);
Q_INVOKABLE void shiftToMatchingBracket(int cnt = 1);
Q_INVOKABLE bool type(const QString &str);
/**
* Toggle auto brackets. If you make use of it, make sure to
* disable them again at the end of your test, otherwise any following tests may fail.
*/
Q_INVOKABLE void setAutoBrackets(bool enable = true);
// Aliases
Q_INVOKABLE void enter(int cnt = 1); // KeyReturn
Q_INVOKABLE void cursorPrev(int cnt = 1); // CursorLeft
Q_INVOKABLE void left(int cnt = 1); // CursorLeft
Q_INVOKABLE void prev(int cnt = 1); // CursorLeft
Q_INVOKABLE void shiftCursorPrev(int cnt = 1); // ShiftCursorLeft
Q_INVOKABLE void shiftLeft(int cnt = 1); // ShiftCursorLeft
Q_INVOKABLE void shiftPrev(int cnt = 1); // ShiftCursorLeft
Q_INVOKABLE void cursorNext(int cnt = 1); // CursorRight
Q_INVOKABLE void right(int cnt = 1); // CursorRight
Q_INVOKABLE void next(int cnt = 1); // CursorRight
Q_INVOKABLE void shiftCursorNext(int cnt = 1); // ShiftCursorRight
Q_INVOKABLE void shiftRight(int cnt = 1); // ShiftCursorRight
Q_INVOKABLE void shiftNext(int cnt = 1); // ShiftCursorRight
Q_INVOKABLE void wordPrev(int cnt = 1); // WordLeft
Q_INVOKABLE void shiftWordPrev(int cnt = 1); // ShiftWordLeft
Q_INVOKABLE void wordNext(int cnt = 1); // WordRight
Q_INVOKABLE void shiftWordNext(int cnt = 1); // ShiftWordRight
private:
Q_DISABLE_COPY(KateViewObject)
};
/**
* @internal
*/
class KateDocumentObject : public KateScriptDocument
{
Q_OBJECT
public:
explicit KateDocumentObject(QJSEngine *engine, KTextEditor::DocumentPrivate *doc);
virtual ~KateDocumentObject();
private:
Q_DISABLE_COPY(KateDocumentObject)
};
/**
* Customizing output to result-files. Writing any output into result files
* inhibits outputting the content of the katepart after script execution,
* enabling one to check for coordinates and the like.
* @internal
*/
class OutputObject : public QObject
{
Q_OBJECT
public:
OutputObject(KTextEditor::ViewPrivate *v, bool &cflag);
virtual ~OutputObject();
void output(bool cp, bool ln);
Q_INVOKABLE void write();
Q_INVOKABLE void writeln();
Q_INVOKABLE void writeLn();
Q_INVOKABLE void print();
Q_INVOKABLE void println();
Q_INVOKABLE void printLn();
Q_INVOKABLE void writeCursorPosition();
Q_INVOKABLE void writeCursorPositionln();
Q_INVOKABLE void cursorPosition();
Q_INVOKABLE void cursorPositionln();
Q_INVOKABLE void cursorPositionLn();
Q_INVOKABLE void pos();
Q_INVOKABLE void posln();
Q_INVOKABLE void posLn();
private:
KTextEditor::ViewPrivate *view;
bool &cflag;
};
#endif // TESTUTILS_H
diff --git a/autotests/src/undomanager_test.h b/autotests/src/undomanager_test.h
index 47fc2dab..016a2902 100644
--- a/autotests/src/undomanager_test.h
+++ b/autotests/src/undomanager_test.h
@@ -1,45 +1,45 @@
/* This file is part of the KDE libraries
Copyright (C) 2010 Bernhard Beschow
Copyright (C) 2009 Dominik Haumann
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public License
along with this library; see the file COPYING.LIB. If not, write to
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02110-1301, USA.
*/
#ifndef KATE_UNDOMANAGER_TEST_H
#define KATE_UNDOMANAGER_TEST_H
-#include
+#include
class UndoManagerTest : public QObject
{
Q_OBJECT
public:
UndoManagerTest();
private Q_SLOTS:
void testUndoRedoCount();
void testSafePoint();
void testCursorPosition();
void testSelectionUndo();
void testUndoWordWrapBug301367();
private:
class TestDocument;
};
#endif
diff --git a/autotests/src/vimode/base.cpp b/autotests/src/vimode/base.cpp
index d2c100f9..09d04713 100644
--- a/autotests/src/vimode/base.cpp
+++ b/autotests/src/vimode/base.cpp
@@ -1,334 +1,337 @@
/*
* This file is part of the KDE libraries
*
* Copyright (C) 2014 Miquel Sabaté Solà
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
* You should have received a copy of the GNU Library General Public License
* along with this library; see the file COPYING.LIB. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#include
#include
#include
#include
#include
#include "base.h"
#include "vimode/macros.h"
#include "vimode/mappings.h"
#include "vimode/globalstate.h"
using namespace KateVi;
using namespace KTextEditor;
//BEGIN: BaseTest
BaseTest::BaseTest()
{
kate_view = nullptr;
kate_document = nullptr;
mainWindow = new QMainWindow;
- mainWindowLayout = new QVBoxLayout(mainWindow);
- mainWindow->setLayout(mainWindowLayout);
+ auto centralWidget = new QWidget();
+ mainWindowLayout = new QVBoxLayout(centralWidget);
+ centralWidget->setLayout(mainWindowLayout);
+ mainWindow->setCentralWidget(centralWidget);
+ mainWindow->resize(640, 480);
m_codesToModifiers.insert("ctrl", Qt::ControlModifier);
m_codesToModifiers.insert("alt", Qt::AltModifier);
m_codesToModifiers.insert("meta", Qt::MetaModifier);
m_codesToModifiers.insert("keypad", Qt::KeypadModifier);
m_codesToSpecialKeys.insert("backspace", Qt::Key_Backspace);
m_codesToSpecialKeys.insert("esc", Qt::Key_Escape);
m_codesToSpecialKeys.insert("return", Qt::Key_Return);
m_codesToSpecialKeys.insert("enter", Qt::Key_Enter);
m_codesToSpecialKeys.insert("left", Qt::Key_Left);
m_codesToSpecialKeys.insert("right", Qt::Key_Right);
m_codesToSpecialKeys.insert("up", Qt::Key_Up);
m_codesToSpecialKeys.insert("down", Qt::Key_Down);
m_codesToSpecialKeys.insert("home", Qt::Key_Home);
m_codesToSpecialKeys.insert("end", Qt::Key_End);
m_codesToSpecialKeys.insert("delete", Qt::Key_Delete);
m_codesToSpecialKeys.insert("insert", Qt::Key_Insert);
m_codesToSpecialKeys.insert("pageup", Qt::Key_PageUp);
m_codesToSpecialKeys.insert("pagedown", Qt::Key_PageDown);
}
BaseTest::~BaseTest()
{
delete kate_document;
}
void BaseTest::waitForCompletionWidgetToActivate(KTextEditor::ViewPrivate *kate_view)
{
const QDateTime start = QDateTime::currentDateTime();
while (start.msecsTo(QDateTime::currentDateTime()) < 1000) {
if (kate_view->isCompletionActive()) {
break;
}
QApplication::processEvents();
}
QVERIFY(kate_view->isCompletionActive());
}
void BaseTest::init()
{
delete kate_view;
delete kate_document;
kate_document = new KTextEditor::DocumentPrivate(false, false, nullptr, nullptr);
// fixed indentation options
kate_document->config()->setTabWidth(8);
kate_document->config()->setIndentationWidth(2);
kate_document->config()->setReplaceTabsDyn(false);
kate_view = new KTextEditor::ViewPrivate(kate_document, mainWindow);
mainWindowLayout->addWidget(kate_view);
kate_view->setInputMode(View::ViInputMode);
Q_ASSERT(kate_view->currentInputMode()->viewInputMode() == KTextEditor::View::ViInputMode);
vi_input_mode = dynamic_cast(kate_view->currentInputMode());
vi_input_mode_manager = vi_input_mode->viInputModeManager();
Q_ASSERT(vi_input_mode_manager);
vi_global = vi_input_mode->globalState();
Q_ASSERT(vi_global);
kate_document->config()->setShowSpaces(true); // Flush out some issues in the KateRenderer when rendering spaces.
kate_view->config()->setScrollBarMiniMap(false);
kate_view->config()->setScrollBarPreview(false);
connect(kate_document, &KTextEditor::DocumentPrivate::textInserted,
this, &BaseTest::textInserted);
connect(kate_document, &KTextEditor::DocumentPrivate::textRemoved,
this, &BaseTest::textRemoved);
}
void BaseTest::TestPressKey(const QString &str)
{
if (m_firstBatchOfKeypressesForTest) {
qDebug() << "\n\n>>> running command " << str << " on text " << kate_document->text();
} else {
qDebug() << "\n>>> running further keypresses " << str << " on text " << kate_document->text();
}
m_firstBatchOfKeypressesForTest = false;
for (int i = 0; i < str.length(); i++) {
Qt::KeyboardModifiers keyboard_modifier = Qt::NoModifier;
QString key;
int keyCode = -1;
// Looking for keyboard modifiers
if (str[i] == QChar('\\')) {
int endOfModifier = -1;
Qt::KeyboardModifier parsedModifier = parseCodedModifier(str, i, &endOfModifier);
int endOfSpecialKey = -1;
Qt::Key parsedSpecialKey = parseCodedSpecialKey(str, i, &endOfSpecialKey);
if (parsedModifier != Qt::NoModifier) {
keyboard_modifier = parsedModifier;
// Move to the character after the '-' in the modifier.
i = endOfModifier + 1;
// Is this a modifier plus special key?
int endOfSpecialKeyAfterModifier = -1;
const Qt::Key parsedCodedSpecialKeyAfterModifier = parseCodedSpecialKey(str, i, &endOfSpecialKeyAfterModifier);
if (parsedCodedSpecialKeyAfterModifier != Qt::Key_unknown) {
key = QString(parsedCodedSpecialKeyAfterModifier);
keyCode = parsedCodedSpecialKeyAfterModifier;
i = endOfSpecialKeyAfterModifier;
}
} else if (parsedSpecialKey != Qt::Key_unknown) {
key = QString(parsedSpecialKey);
keyCode = parsedSpecialKey;
i = endOfSpecialKey;
} else if (str.mid(i, 2) == QString("\\:")) {
int start_cmd = i + 2;
for (i += 2; true; i++) {
if (str.at(i) == '\\') {
if (i + 1 < str.length() && str.at(i + 1) == '\\') {
// A backslash within a command; skip.
i += 2;
} else {
// End of command.
break;
}
}
}
const QString commandToExecute = str.mid(start_cmd, i - start_cmd).replace("\\\\", "\\");
qDebug() << "Executing command directly from ViModeTest:\n" << commandToExecute;
vi_input_mode->viModeEmulatedCommandBar()->executeCommand(commandToExecute);
// We've handled the command; go back round the loop, avoiding sending
// the closing \ to vi_input_mode_manager.
continue;
} else if (str.mid(i, 2) == QString("\\\\")) {
key = QString("\\");
keyCode = Qt::Key_Backslash;
i++;
} else {
Q_ASSERT(false); //Do not use "\" in tests except for modifiers, command mode (\\:) and literal backslashes "\\\\")
}
}
if (keyCode == -1) {
key = str[i];
keyCode = key[0].unicode();
// Kate Vim mode's internals identifier e.g. CTRL-C by Qt::Key_C plus the control modifier,
// so we need to translate e.g. 'c' to Key_C.
if (key[0].isLetter()) {
if (key[0].toLower() == key[0]) {
keyCode = keyCode - 'a' + Qt::Key_A;
} else {
keyCode = keyCode - 'A' + Qt::Key_A;
keyboard_modifier |= Qt::ShiftModifier;
}
}
}
QKeyEvent *key_event = new QKeyEvent(QEvent::KeyPress, keyCode, keyboard_modifier, key);
// Attempt to simulate how Qt usually sends events - typically, we want to send them
// to kate_view->focusProxy() (which is a KateViewInternal).
QWidget *destWidget = nullptr;
if (QApplication::activePopupWidget()) {
// According to the docs, the activePopupWidget, if present, takes all events.
destWidget = QApplication::activePopupWidget();
} else if (QApplication::focusWidget()) {
if (QApplication::focusWidget()->focusProxy()) {
destWidget = QApplication::focusWidget()->focusProxy();
} else {
destWidget = QApplication::focusWidget();
}
} else {
destWidget = kate_view->focusProxy();
}
QApplication::postEvent(destWidget, key_event);
QApplication::sendPostedEvents();
}
}
void BaseTest::BeginTest(const QString &original)
{
vi_input_mode_manager->viEnterNormalMode();
vi_input_mode->reset();
vi_input_mode_manager = vi_input_mode->viInputModeManager();
kate_document->setText(original);
kate_document->undoManager()->clearUndo();
kate_document->undoManager()->clearRedo();
kate_view->setCursorPosition(Cursor(0, 0));
m_firstBatchOfKeypressesForTest = true;
}
void BaseTest::FinishTest_(int line, const char *file, const QString &expected,
Expectation expectation,
const QString &failureReason)
{
if (expectation == ShouldFail) {
if (!QTest::qExpectFail("", failureReason.toLocal8Bit().constData(), QTest::Continue, file, line)) {
return;
}
qDebug() << "Actual text:\n\t" << kate_document->text() << "\nShould be (for this test to pass):\n\t" << expected;
}
if (!QTest::qCompare(kate_document->text(), expected, "kate_document->text()", "expected_text", file, line)) {
return;
}
Q_ASSERT(!emulatedCommandBarTextEdit()->isVisible() && "Make sure you close the command bar before the end of a test!");
}
void BaseTest::DoTest_(int line, const char *file, const QString &original, const QString &command,
const QString &expected, Expectation expectation,
const QString &failureReason)
{
BeginTest(original);
TestPressKey(command);
FinishTest_(line, file, expected, expectation, failureReason);
}
Qt::KeyboardModifier BaseTest::parseCodedModifier(const QString &string, int startPos, int *destEndOfCodedModifier)
{
foreach (const QString &modifierCode, m_codesToModifiers.keys()) {
// The "+2" is from the leading '\' and the trailing '-'
if (string.mid(startPos, modifierCode.length() + 2) == QString("\\") + modifierCode + "-") {
if (destEndOfCodedModifier) {
// destEndOfCodeModifier lies on the trailing '-'.
*destEndOfCodedModifier = startPos + modifierCode.length() + 1;
Q_ASSERT(string[*destEndOfCodedModifier] == '-');
}
return m_codesToModifiers.value(modifierCode);
}
}
return Qt::NoModifier;
}
Qt::Key BaseTest::parseCodedSpecialKey(const QString &string, int startPos, int *destEndOfCodedKey)
{
foreach (const QString &specialKeyCode, m_codesToSpecialKeys.keys()) {
// "+1" is for the leading '\'.
if (string.mid(startPos, specialKeyCode.length() + 1) == QString("\\") + specialKeyCode) {
if (destEndOfCodedKey) {
*destEndOfCodedKey = startPos + specialKeyCode.length();
}
return m_codesToSpecialKeys.value(specialKeyCode);
}
}
return Qt::Key_unknown;
}
KateVi::EmulatedCommandBar * BaseTest::emulatedCommandBar()
{
KateVi::EmulatedCommandBar *emulatedCommandBar = vi_input_mode->viModeEmulatedCommandBar();
Q_ASSERT(emulatedCommandBar);
return emulatedCommandBar;
}
QLineEdit * BaseTest::emulatedCommandBarTextEdit()
{
QLineEdit *emulatedCommandBarText = emulatedCommandBar()->findChild("commandtext");
Q_ASSERT(emulatedCommandBarText);
return emulatedCommandBarText;
}
void BaseTest::ensureKateViewVisible()
{
mainWindow->show();
kate_view->show();
QApplication::setActiveWindow(mainWindow);
kate_view->setFocus();
const QDateTime startTime = QDateTime::currentDateTime();
while (startTime.msecsTo(QDateTime::currentDateTime()) < 3000 && !mainWindow->isActiveWindow()) {
QApplication::processEvents();
}
QVERIFY(kate_view->isVisible());
QVERIFY(mainWindow->isActiveWindow());
}
void BaseTest::clearAllMappings()
{
vi_global->mappings()->clear(Mappings::NormalModeMapping);
vi_global->mappings()->clear(Mappings::VisualModeMapping);
vi_global->mappings()->clear(Mappings::InsertModeMapping);
vi_global->mappings()->clear(Mappings::CommandModeMapping);
}
void BaseTest::clearAllMacros()
{
vi_global->macros()->clear();
}
void BaseTest::textInserted(Document *document, KTextEditor::Range range)
{
m_docChanges.append(DocChange(DocChange::TextInserted, range, document->text(range)));
}
void BaseTest::textRemoved(Document *document, KTextEditor::Range range)
{
Q_UNUSED(document);
m_docChanges.append(DocChange(DocChange::TextRemoved, range));
}
//END: BaseTest
diff --git a/autotests/src/vimode/completion.h b/autotests/src/vimode/completion.h
index 19aa6a7f..25ef3470 100644
--- a/autotests/src/vimode/completion.h
+++ b/autotests/src/vimode/completion.h
@@ -1,70 +1,70 @@
/*
* This file is part of the KDE libraries
*
* Copyright (C) 2014 Miquel Sabaté Solà
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
* You should have received a copy of the GNU Library General Public License
* along with this library; see the file COPYING.LIB. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#ifndef COMPLETION_TEST_H
#define COMPLETION_TEST_H
#include "base.h"
#include "fakecodecompletiontestmodel.h"
/**
* This class handles implements a completion model for the completion
* tests defined in the CompletionTest class.
*/
class VimCodeCompletionTestModel : public KTextEditor::CodeCompletionModel
{
public:
VimCodeCompletionTestModel(KTextEditor::View *parent);
- QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const Q_DECL_OVERRIDE;
+ QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
KTextEditor::CodeCompletionInterface *cc() const;
};
/**
* This class implements a completion model used in the CompletionTest class
* to test that code completion is not invoked.
*/
class FailTestOnInvocationModel : public KTextEditor::CodeCompletionModel
{
public:
FailTestOnInvocationModel(KTextEditor::View *parent);
- QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const Q_DECL_OVERRIDE;
+ QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override;
void failTest() const;
KTextEditor::CodeCompletionInterface *cc() const;
};
class CompletionTest : public BaseTest
{
Q_OBJECT
private Q_SLOTS:
void FakeCodeCompletionTests();
void CompletionTests();
private:
void waitForCompletionWidgetToActivate();
void clearTrackedDocumentChanges();
};
#endif /* COMPLETION_TEST_H */
diff --git a/autotests/src/vimode/emulatedcommandbar.cpp b/autotests/src/vimode/emulatedcommandbar.cpp
index c1a89b14..74938373 100644
--- a/autotests/src/vimode/emulatedcommandbar.cpp
+++ b/autotests/src/vimode/emulatedcommandbar.cpp
@@ -1,3377 +1,3377 @@
/* This file is part of the KDE libraries
Copyright (C) 2011 Kuzmich Svyatoslav
Copyright (C) 2012 - 2013 Simon St James
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public License
along with this library; see the file COPYING.LIB. If not, write to
the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
Boston, MA 02110-1301, USA.
*/
#include
#include
#include "emulatedcommandbar.h"
#include
#include
#include
#include "keys.h"
#include "view.h"
#include "emulatedcommandbarsetupandteardown.h"
#include "vimode/mappings.h"
#include "vimode/globalstate.h"
#include
#include
#include
#include
#include
#include
#include
QTEST_MAIN(EmulatedCommandBarTest)
using namespace KTextEditor;
using namespace KateVi;
void EmulatedCommandBarTest::EmulatedCommandBarTests()
{
// Ensure that some preconditions for these tests are setup, and (more importantly)
// ensure that they are reverted no matter how these tests end.
EmulatedCommandBarSetUpAndTearDown emulatedCommandBarSetUpAndTearDown(vi_input_mode, kate_view, mainWindow);
// Verify that we can get a non-null pointer to the emulated command bar.
EmulatedCommandBar *emulatedCommandBar = vi_input_mode->viModeEmulatedCommandBar();
QVERIFY(emulatedCommandBar);
// Should initially be hidden.
QVERIFY(!emulatedCommandBar->isVisible());
// Test that "/" invokes the emulated command bar (if we are configured to use it)
BeginTest("");
TestPressKey("/");
QVERIFY(emulatedCommandBar->isVisible());
QCOMPARE(emulatedCommandTypeIndicator()->text(), QString("/"));
QVERIFY(emulatedCommandTypeIndicator()->isVisible());
QVERIFY(emulatedCommandBarTextEdit());
QVERIFY(emulatedCommandBarTextEdit()->text().isEmpty());
// Make sure the keypresses end up changing the text.
QVERIFY(emulatedCommandBarTextEdit()->isVisible());
TestPressKey("foo");
QCOMPARE(emulatedCommandBarTextEdit()->text(), QString("foo"));
// Make sure ctrl-c dismisses it (assuming we allow Vim to steal the ctrl-c shortcut).
TestPressKey("\\ctrl-c");
QVERIFY(!emulatedCommandBar->isVisible());
// Ensure that ESC dismisses it, too.
BeginTest("");
TestPressKey("/");
QVERIFY(emulatedCommandBar->isVisible());
TestPressKey("\\esc");
QVERIFY(!emulatedCommandBar->isVisible());
FinishTest("");
// Ensure that Ctrl-[ dismisses it, too.
BeginTest("");
TestPressKey("/");
QVERIFY(emulatedCommandBar->isVisible());
TestPressKey("\\ctrl-[");
QVERIFY(!emulatedCommandBar->isVisible());
FinishTest("");
// Ensure that Enter dismisses it, too.
BeginTest("");
TestPressKey("/");
QVERIFY(emulatedCommandBar->isVisible());
TestPressKey("\\enter");
QVERIFY(!emulatedCommandBar->isVisible());
FinishTest("");
// Ensure that Return dismisses it, too.
BeginTest("");
TestPressKey("/");
QVERIFY(emulatedCommandBar->isVisible());
TestPressKey("\\return");
QVERIFY(!emulatedCommandBar->isVisible());
FinishTest("");
// Ensure that text is always initially empty.
BeginTest("");
TestPressKey("/a\\enter");
TestPressKey("/");
QVERIFY(emulatedCommandBarTextEdit()->text().isEmpty());
TestPressKey("\\enter");
FinishTest("");
// Check backspace works.
BeginTest("");
TestPressKey("/foo\\backspace");
QCOMPARE(emulatedCommandBarTextEdit()->text(), QString("fo"));
TestPressKey("\\enter");
FinishTest("");
// Check ctrl-h works.
BeginTest("");
TestPressKey("/bar\\ctrl-h");
QCOMPARE(emulatedCommandBarTextEdit()->text(), QString("ba"));
TestPressKey("\\enter");
FinishTest("");
// ctrl-h should dismiss bar when empty.
BeginTest("");
TestPressKey("/\\ctrl-h");
QVERIFY(!emulatedCommandBar->isVisible());
FinishTest("");
// ctrl-h should not dismiss bar when there is stuff to the left of cursor.
BeginTest("");
TestPressKey("/a\\ctrl-h");
QVERIFY(emulatedCommandBar->isVisible());
TestPressKey("\\enter");
FinishTest("");
// ctrl-h should not dismiss bar when bar is not empty, even if there is nothing to the left of cursor.
BeginTest("");
TestPressKey("/a\\left\\ctrl-h");
QVERIFY(emulatedCommandBar->isVisible());
TestPressKey("\\enter");
FinishTest("");
// Same for backspace.
BeginTest("");
TestPressKey("/bar\\backspace");
QCOMPARE(emulatedCommandBarTextEdit()->text(), QString("ba"));
TestPressKey("\\enter");
FinishTest("");
BeginTest("");
TestPressKey("/\\backspace");
QVERIFY(!emulatedCommandBar->isVisible());
FinishTest("");
BeginTest("");
TestPressKey("/a\\backspace");
QVERIFY(emulatedCommandBar->isVisible());
TestPressKey("\\enter");
FinishTest("");
BeginTest("");
TestPressKey("/a\\left\\backspace");
QVERIFY(emulatedCommandBar->isVisible());
TestPressKey("\\enter");
FinishTest("");
// Check ctrl-b works.
BeginTest("");
TestPressKey("/bar foo xyz\\ctrl-bX");
QCOMPARE(emulatedCommandBarTextEdit()->text(), QString("Xbar foo xyz"));
TestPressKey("\\enter");
FinishTest("");
// Check ctrl-e works.
BeginTest("");
TestPressKey("/bar foo xyz\\ctrl-b\\ctrl-eX");
QCOMPARE(emulatedCommandBarTextEdit()->text(), QString("bar foo xyzX"));
TestPressKey("\\enter");
FinishTest("");
// Check ctrl-w works.
BeginTest("");
TestPressKey("/foo bar\\ctrl-w");
QCOMPARE(emulatedCommandBarTextEdit()->text(), QString("foo "));
TestPressKey("\\enter");
FinishTest("");
// Check ctrl-w works on empty command bar.
BeginTest("");
TestPressKey("/\\ctrl-w");
QCOMPARE(emulatedCommandBarTextEdit()->text(), QString(""));
TestPressKey("\\enter");
FinishTest("");
// Check ctrl-w works in middle of word.
BeginTest("");
TestPressKey("/foo bar\\left\\left\\ctrl-w");
QCOMPARE(emulatedCommandBarTextEdit()->text(), QString("foo ar"));
TestPressKey("\\enter");
FinishTest("");
// Check ctrl-w leaves the cursor in the right place when in the middle of word.
BeginTest("");
TestPressKey("/foo bar\\left\\left\\ctrl-wX");
QCOMPARE(emulatedCommandBarTextEdit()->text(), QString("foo Xar"));
TestPressKey("\\enter");
FinishTest("");
// Check ctrl-w works when at the beginning of the text.
BeginTest("");
TestPressKey("/foo\\left\\left\\left\\ctrl-w");
QCOMPARE(emulatedCommandBarTextEdit()->text(), QString("foo"));
TestPressKey("\\enter");
FinishTest("");
// Check ctrl-w works when the character to the left is a space.
BeginTest("");
TestPressKey("/foo bar \\ctrl-w");
QCOMPARE(emulatedCommandBarTextEdit()->text(), QString("foo "));
TestPressKey("\\enter");
FinishTest("");
// Check ctrl-w works when all characters to the left of the cursor are spaces.
BeginTest("");
TestPressKey("/ \\ctrl-w");
QCOMPARE(emulatedCommandBarTextEdit()->text(), QString(""));
TestPressKey("\\enter");
FinishTest("");
// Check ctrl-w works when all characters to the left of the cursor are non-spaces.
BeginTest("");
TestPressKey("/foo\\ctrl-w");
QCOMPARE(emulatedCommandBarTextEdit()->text(), QString(""));
TestPressKey("\\enter");
FinishTest("");
// Check ctrl-w does not continue to delete subsequent alphanumerics if the characters to the left of the cursor
// are non-space, non-alphanumerics.
BeginTest("");
TestPressKey("/foo!!!\\ctrl-w");
QCOMPARE(emulatedCommandBarTextEdit()->text(), QString("foo"));
TestPressKey("\\enter");
FinishTest("");
// Check ctrl-w does not continue to delete subsequent alphanumerics if the characters to the left of the cursor
// are non-space, non-alphanumerics.
BeginTest("");
TestPressKey("/foo!!!\\ctrl-w");
QCOMPARE(emulatedCommandBarTextEdit()->text(), QString("foo"));
TestPressKey("\\enter");
FinishTest("");
// Check ctrl-w deletes underscores and alphanumerics to the left of the cursor, but stops when it reaches a
// character that is none of these.
BeginTest("");
TestPressKey("/foo!!!_d1\\ctrl-w");
QCOMPARE(emulatedCommandBarTextEdit()->text(), QString("foo!!!"));
TestPressKey("\\enter");
FinishTest("");
// Check ctrl-w doesn't swallow the spaces preceding the block of non-word chars.
BeginTest("");
TestPressKey("/foo !!!\\ctrl-w");
QCOMPARE(emulatedCommandBarTextEdit()->text(), QString("foo "));
TestPressKey("\\enter");
FinishTest("");
// Check ctrl-w doesn't swallow the spaces preceding the word.
BeginTest("");
TestPressKey("/foo 1d_\\ctrl-w");
QCOMPARE(emulatedCommandBarTextEdit()->text(), QString("foo "));
TestPressKey("\\enter");
FinishTest("");
// Check there is a "waiting for register" indicator, initially hidden.
BeginTest("");
TestPressKey("/");
QLabel* waitingForRegisterIndicator = emulatedCommandBar->findChild("waitingforregisterindicator");
QVERIFY(waitingForRegisterIndicator);
QVERIFY(!waitingForRegisterIndicator->isVisible());
QCOMPARE(waitingForRegisterIndicator->text(), QString("\""));
TestPressKey("\\enter");
FinishTest("");
// Test that ctrl-r causes it to become visible. It is displayed to the right of the text edit.
BeginTest("");
TestPressKey("/\\ctrl-r");
QVERIFY(waitingForRegisterIndicator->isVisible());
QVERIFY(waitingForRegisterIndicator->x() >= emulatedCommandBarTextEdit()->x() + emulatedCommandBarTextEdit()->width());
TestPressKey("\\ctrl-c");
TestPressKey("\\ctrl-c");
FinishTest("");
// The first ctrl-c after ctrl-r (when no register entered) hides the waiting for register
// indicator, but not the bar.
BeginTest("");
TestPressKey("/\\ctrl-r");
QVERIFY(waitingForRegisterIndicator->isVisible());
TestPressKey("\\ctrl-c");
QVERIFY(!waitingForRegisterIndicator->isVisible());
QVERIFY(emulatedCommandBar->isVisible());
TestPressKey("\\ctrl-c"); // Dismiss the bar.
FinishTest("");
// The first ctrl-c after ctrl-r (when no register entered) aborts waiting for register.
BeginTest("foo");
TestPressKey("\"cyiw/\\ctrl-r\\ctrl-ca");
QCOMPARE(emulatedCommandBarTextEdit()->text(), QString("a"));
TestPressKey("\\ctrl-c"); // Dismiss the bar.
FinishTest("foo");
// Same as above, but for ctrl-[ instead of ctrl-c.
BeginTest("");
TestPressKey("/\\ctrl-r");
QVERIFY(waitingForRegisterIndicator->isVisible());
TestPressKey("\\ctrl-[");
QVERIFY(!waitingForRegisterIndicator->isVisible());
QVERIFY(emulatedCommandBar->isVisible());
TestPressKey("\\ctrl-c"); // Dismiss the bar.
FinishTest("");
BeginTest("foo");
TestPressKey("\"cyiw/\\ctrl-r\\ctrl-[a");
QCOMPARE(emulatedCommandBarTextEdit()->text(), QString("a"));
TestPressKey("\\ctrl-c"); // Dismiss the bar.
FinishTest("foo");
// Check ctrl-r works with registers, and hides the "waiting for register" indicator.
BeginTest("xyz");
TestPressKey("\"ayiw/foo\\ctrl-ra");
QCOMPARE(emulatedCommandBarTextEdit()->text(), QString("fooxyz"));
QVERIFY(!waitingForRegisterIndicator->isVisible());
TestPressKey("\\enter");
FinishTest("xyz");
// Check ctrl-r inserts text at the current cursor position.
BeginTest("xyz");
TestPressKey("\"ayiw/foo\\left\\ctrl-ra");
QCOMPARE(emulatedCommandBarTextEdit()->text(), QString("foxyzo"));
TestPressKey("\\enter");
FinishTest("xyz");
// Check ctrl-r ctrl-w inserts word under the cursor, and hides the "waiting for register" indicator.
BeginTest("foo bar xyz");
TestPressKey("w/\\left\\ctrl-r\\ctrl-w");
QCOMPARE(emulatedCommandBarTextEdit()->text(), QString("bar"));
QVERIFY(!waitingForRegisterIndicator->isVisible());
TestPressKey("\\enter");
FinishTest("foo bar xyz");
// Check ctrl-r ctrl-w doesn't insert the contents of register w!
BeginTest("foo baz xyz");
TestPressKey("\"wyiww/\\left\\ctrl-r\\ctrl-w");
QCOMPARE(emulatedCommandBarTextEdit()->text(), QString("baz"));
TestPressKey("\\enter");
FinishTest("foo baz xyz");
// Check ctrl-r ctrl-w inserts at the current cursor position.
BeginTest("foo nose xyz");
TestPressKey("w/bar\\left\\ctrl-r\\ctrl-w");
QCOMPARE(emulatedCommandBarTextEdit()->text(), QString("banoser"));
TestPressKey("\\enter");
FinishTest("foo nose xyz");
// Cursor position is at the end of the inserted text after ctrl-r ctrl-w.
BeginTest("foo nose xyz");
TestPressKey("w/bar\\left\\ctrl-r\\ctrl-wX");
QCOMPARE(emulatedCommandBarTextEdit()->text(), QString("banoseXr"));
TestPressKey("\\enter");
FinishTest("foo nose xyz");
// Cursor position is at the end of the inserted register contents after ctrl-r.
BeginTest("xyz");
TestPressKey("\"ayiw/foo\\left\\ctrl-raX");
QCOMPARE(emulatedCommandBarTextEdit()->text(), QString("foxyzXo"));
TestPressKey("\\enter");
FinishTest("xyz");
// Insert clipboard contents on ctrl-r +. We implicitly need to test the ability to handle
// shift key key events when waiting for register (they should be ignored).
BeginTest("xyz");
QApplication::clipboard()->setText("vimodetestclipboardtext");
TestPressKey("/\\ctrl-r");
QKeyEvent *shiftKeyDown = new QKeyEvent(QEvent::KeyPress, Qt::Key_Shift, Qt::NoModifier);
QApplication::postEvent(emulatedCommandBarTextEdit(), shiftKeyDown);
QApplication::sendPostedEvents();
TestPressKey("+");
QKeyEvent *shiftKeyUp = new QKeyEvent(QEvent::KeyPress, Qt::Key_Shift, Qt::NoModifier);
QApplication::postEvent(emulatedCommandBarTextEdit(), shiftKeyUp);
QApplication::sendPostedEvents();
QCOMPARE(emulatedCommandBarTextEdit()->text(), QString("vimodetestclipboardtext"));
TestPressKey("\\enter");
FinishTest("xyz");
// Similarly, test that we can press "ctrl" after ctrl-r without it being taken for a register.
BeginTest("wordundercursor");
TestPressKey("/\\ctrl-r");
QKeyEvent *ctrlKeyDown = new QKeyEvent(QEvent::KeyPress, Qt::Key_Control, Qt::NoModifier);
QApplication::postEvent(emulatedCommandBarTextEdit(), ctrlKeyDown);
QApplication::sendPostedEvents();
QKeyEvent *ctrlKeyUp = new QKeyEvent(QEvent::KeyRelease, Qt::Key_Control, Qt::NoModifier);
QApplication::postEvent(emulatedCommandBarTextEdit(), ctrlKeyUp);
QApplication::sendPostedEvents();
QVERIFY(waitingForRegisterIndicator->isVisible());
TestPressKey("\\ctrl-w");
QCOMPARE(emulatedCommandBarTextEdit()->text(), QString("wordundercursor"));
TestPressKey("\\ctrl-c"); // Dismiss the bar.
FinishTest("wordundercursor");
// Begin tests for ctrl-g, which is almost identical to ctrl-r save that the contents, when added,
// are escaped for searching.
// Normal register contents/ word under cursor are added as normal.
BeginTest("wordinregisterb wordundercursor");
TestPressKey("\"byiw");
TestPressKey("/\\ctrl-g");
QVERIFY(waitingForRegisterIndicator->isVisible());
QVERIFY(waitingForRegisterIndicator->x() >= emulatedCommandBarTextEdit()->x() + emulatedCommandBarTextEdit()->width());
TestPressKey("b");
QCOMPARE(emulatedCommandBarTextEdit()->text(), QString("wordinregisterb"));
QVERIFY(!waitingForRegisterIndicator->isVisible());
TestPressKey("\\ctrl-c\\ctrl-cw/\\ctrl-g\\ctrl-w");
QCOMPARE(emulatedCommandBarTextEdit()->text(), QString("wordundercursor"));
QVERIFY(!waitingForRegisterIndicator->isVisible());
TestPressKey("\\ctrl-c");
TestPressKey("\\ctrl-c");
FinishTest("wordinregisterb wordundercursor");
// \'s must be escaped when inserted via ctrl-g.
DoTest("foo a\\b\\\\c\\\\\\d", "wYb/\\ctrl-g0\\enterrX", "foo X\\b\\\\c\\\\\\d");
// $'s must be escaped when inserted via ctrl-g.
DoTest("foo a$b", "wYb/\\ctrl-g0\\enterrX", "foo X$b");
DoTest("foo a$b$c", "wYb/\\ctrl-g0\\enterrX", "foo X$b$c");
DoTest("foo a\\$b\\$c", "wYb/\\ctrl-g0\\enterrX", "foo X\\$b\\$c");
// ^'s must be escaped when inserted via ctrl-g.
DoTest("foo a^b", "wYb/\\ctrl-g0\\enterrX", "foo X^b");
DoTest("foo a^b^c", "wYb/\\ctrl-g0\\enterrX", "foo X^b^c");
DoTest("foo a\\^b\\^c", "wYb/\\ctrl-g0\\enterrX", "foo X\\^b\\^c");
// .'s must be escaped when inserted via ctrl-g.
DoTest("foo axb a.b", "wwYgg/\\ctrl-g0\\enterrX", "foo axb X.b");
DoTest("foo a\\xb Na\\.b", "fNlYgg/\\ctrl-g0\\enterrX", "foo a\\xb NX\\.b");
// *'s must be escaped when inserted via ctrl-g
DoTest("foo axxxxb ax*b", "wwYgg/\\ctrl-g0\\enterrX", "foo axxxxb Xx*b");
DoTest("foo a\\xxxxb Na\\x*X", "fNlYgg/\\ctrl-g0\\enterrX", "foo a\\xxxxb NX\\x*X");
// /'s must be escaped when inserted via ctrl-g.
DoTest("foo a a/b", "wwYgg/\\ctrl-g0\\enterrX", "foo a X/b");
DoTest("foo a a/b/c", "wwYgg/\\ctrl-g0\\enterrX", "foo a X/b/c");
DoTest("foo a a\\/b\\/c", "wwYgg/\\ctrl-g0\\enterrX", "foo a X\\/b\\/c");
// ['s and ]'s must be escaped when inserted via ctrl-g.
DoTest("foo axb a[xyz]b", "wwYgg/\\ctrl-g0\\enterrX", "foo axb X[xyz]b");
DoTest("foo a[b", "wYb/\\ctrl-g0\\enterrX", "foo X[b");
DoTest("foo a[b[c", "wYb/\\ctrl-g0\\enterrX", "foo X[b[c");
DoTest("foo a\\[b\\[c", "wYb/\\ctrl-g0\\enterrX", "foo X\\[b\\[c");
DoTest("foo a]b", "wYb/\\ctrl-g0\\enterrX", "foo X]b");
DoTest("foo a]b]c", "wYb/\\ctrl-g0\\enterrX", "foo X]b]c");
DoTest("foo a\\]b\\]c", "wYb/\\ctrl-g0\\enterrX", "foo X\\]b\\]c");
// Test that expressions involving {'s and }'s work when inserted via ctrl-g.
DoTest("foo {", "wYgg/\\ctrl-g0\\enterrX", "foo X");
DoTest("foo }", "wYgg/\\ctrl-g0\\enterrX", "foo X");
DoTest("foo aaaaa \\aaaaa a\\{5}", "WWWYgg/\\ctrl-g0\\enterrX", "foo aaaaa \\aaaaa X\\{5}");
DoTest("foo }", "wYgg/\\ctrl-g0\\enterrX", "foo X");
// Transform newlines into "\\n" when inserted via ctrl-g.
DoTest(" \nfoo\nfoo\nxyz\nbar\n123", "jjvjjllygg/\\ctrl-g0\\enterrX", " \nfoo\nXoo\nxyz\nbar\n123");
DoTest(" \nfoo\nfoo\nxyz\nbar\n123", "jjvjjllygg/\\ctrl-g0/e\\enterrX", " \nfoo\nfoo\nxyz\nbaX\n123");
// Don't do any escaping for ctrl-r, though.
BeginTest("foo .*$^\\/");
TestPressKey("wY/\\ctrl-r0");
QCOMPARE(emulatedCommandBarTextEdit()->text(), QString(".*$^\\/"));
TestPressKey("\\ctrl-c");
TestPressKey("\\ctrl-c");
FinishTest("foo .*$^\\/");
// Ensure that the flag that says "next register insertion should be escaped for searching"
// is cleared if we do ctrl-g but then abort with ctrl-c.
DoTest("foo a$b", "/\\ctrl-g\\ctrl-c\\ctrl-cwYgg/\\ctrl-r0\\enterrX", "Xoo a$b");
// Ensure that we actually perform a search while typing.
BeginTest("abcd");
TestPressKey("/c");
verifyCursorAt(Cursor(0, 2));
TestPressKey("\\enter");
FinishTest("abcd");
// Ensure that the search is from the cursor.
BeginTest("acbcd");
TestPressKey("ll/c");
verifyCursorAt(Cursor(0, 3));
TestPressKey("\\enter");
FinishTest("acbcd");
// Reset the cursor to the original position on Ctrl-C
BeginTest("acbcd");
TestPressKey("ll/c\\ctrl-crX");
FinishTest("acXcd");
// Reset the cursor to the original position on Ctrl-[
BeginTest("acbcd");
TestPressKey("ll/c\\ctrl-[rX");
FinishTest("acXcd");
// Reset the cursor to the original position on ESC
BeginTest("acbcd");
TestPressKey("ll/c\\escrX");
FinishTest("acXcd");
// *Do not* reset the cursor to the original position on Enter.
BeginTest("acbcd");
TestPressKey("ll/c\\enterrX");
FinishTest("acbXd");
// *Do not* reset the cursor to the original position on Return.
BeginTest("acbcd");
TestPressKey("ll/c\\returnrX");
FinishTest("acbXd");
// Should work with mappings.
clearAllMappings();
vi_global->mappings()->add(Mappings::NormalModeMapping, "'testmapping", "/crX", Mappings::Recursive);
BeginTest("acbcd");
TestPressKey("'testmapping");
FinishTest("aXbcd");
clearAllMappings();
// Don't send keys that were part of a mapping to the emulated command bar.
vi_global->mappings()->add(Mappings::NormalModeMapping, "H", "/a", Mappings::Recursive);
BeginTest("foo a aH");
TestPressKey("H\\enterrX");
FinishTest("foo X aH");
clearAllMappings();
// Incremental searching from the original position.
BeginTest("foo bar foop fool food");
TestPressKey("ll/foo");
verifyCursorAt(Cursor(0, 8));
TestPressKey("l");
verifyCursorAt(Cursor(0, 13));
TestPressKey("\\backspace");
verifyCursorAt(Cursor(0, 8));
TestPressKey("\\enter");
FinishTest("foo bar foop fool food");
// End up back at the start if no match found
BeginTest("foo bar foop fool food");
TestPressKey("ll/fool");
verifyCursorAt(Cursor(0, 13));
TestPressKey("\\backspacex");
verifyCursorAt(Cursor(0, 2));
TestPressKey("\\enter");
FinishTest("foo bar foop fool food");
// Wrap around if no match found.
BeginTest("afoom bar foop fool food");
TestPressKey("lll/foom");
verifyCursorAt(Cursor(0, 1));
TestPressKey("\\enter");
FinishTest("afoom bar foop fool food");
// SmartCase: match case-insensitively if the search text is all lower-case.
DoTest("foo BaR", "ll/bar\\enterrX", "foo XaR");
// SmartCase: match case-sensitively if the search text is mixed case.
DoTest("foo BaR bAr", "ll/bAr\\enterrX", "foo BaR XAr");
// Assume regex by default.
DoTest("foo bwibblear", "ll/b.*ar\\enterrX", "foo Xwibblear");
// Set the last search pattern.
DoTest("foo bar", "ll/bar\\enterggnrX", "foo Xar");
// Make sure the last search pattern is a regex, too.
DoTest("foo bwibblear", "ll/b.*ar\\enterggnrX", "foo Xwibblear");
// 'n' should search case-insensitively if the original search was case-insensitive.
DoTest("foo bAR", "ll/bar\\enterggnrX", "foo XAR");
// 'n' should search case-sensitively if the original search was case-sensitive.
DoTest("foo bar bAR", "ll/bAR\\enterggnrX", "foo bar XAR");
// 'N' should search case-insensitively if the original search was case-insensitive.
DoTest("foo bAR xyz", "ll/bar\\enter$NrX", "foo XAR xyz");
// 'N' should search case-sensitively if the original search was case-sensitive.
DoTest("foo bAR bar", "ll/bAR\\enter$NrX", "foo XAR bar");
// Don't forget to set the last search to case-insensitive.
DoTest("foo bAR bar", "ll/bAR\\enter^/bar\\enter^nrX", "foo XAR bar");
// Usage of \C for manually specifying case sensitivity.
// Strip occurrences of "\C" from the pattern to find.
DoTest("foo bar", "/\\\\Cba\\\\Cr\\enterrX", "foo Xar");
// Be careful about escaping, though!
DoTest("foo \\Cba\\Cr", "/\\\\\\\\Cb\\\\Ca\\\\\\\\C\\\\C\\\\Cr\\enterrX", "foo XCba\\Cr");
// The item added to the search history should contain all the original \C's.
clearSearchHistory();
BeginTest("foo \\Cba\\Cr");
TestPressKey("/\\\\\\\\Cb\\\\Ca\\\\\\\\C\\\\C\\\\Cr\\enterrX");
QCOMPARE(searchHistory().first(), QString("\\\\Cb\\Ca\\\\C\\C\\Cr"));
FinishTest("foo XCba\\Cr");
// If there is an escaped C, assume case sensitivity.
DoTest("foo bAr BAr bar", "/ba\\\\Cr\\enterrX", "foo bAr BAr Xar");
// The last search pattern should be the last search with escaped C's stripped.
DoTest("foo \\Cbar\nfoo \\Cbar", "/\\\\\\\\Cba\\\\C\\\\Cr\\enterggjnrX", "foo \\Cbar\nfoo XCbar");
// If the last search pattern had an escaped "\C", then the next search should be case-sensitive.
DoTest("foo bar\nfoo bAr BAr bar", "/ba\\\\Cr\\enterggjnrX", "foo bar\nfoo bAr BAr Xar");
// Don't set the last search parameters if we abort, though.
DoTest("foo bar xyz", "/bar\\enter/xyz\\ctrl-cggnrX", "foo Xar xyz");
DoTest("foo bar bAr", "/bar\\enter/bA\\ctrl-cggnrX", "foo Xar bAr");
DoTest("foo bar bar", "/bar\\enter?ba\\ctrl-cggnrX", "foo Xar bar");
// Don't let ":" trample all over the search parameters, either.
DoTest("foo bar xyz foo", "/bar\\entergg*:yank\\enterggnrX", "foo bar xyz Xoo");
// Some mirror tests for "?"
// Test that "?" summons the search bar, with empty text and with the "?" indicator.
QVERIFY(!emulatedCommandBar->isVisible());
BeginTest("");
TestPressKey("?");
QVERIFY(emulatedCommandBar->isVisible());
QCOMPARE(emulatedCommandTypeIndicator()->text(), QString("?"));
QVERIFY(emulatedCommandTypeIndicator()->isVisible());
QVERIFY(emulatedCommandBarTextEdit());
QVERIFY(emulatedCommandBarTextEdit()->text().isEmpty());
TestPressKey("\\enter");
FinishTest("");
// Search backwards.
DoTest("foo foo bar foo foo", "ww?foo\\enterrX", "foo Xoo bar foo foo");
// Reset cursor if we find nothing.
BeginTest("foo foo bar foo foo");
TestPressKey("ww?foo");
verifyCursorAt(Cursor(0, 4));
TestPressKey("d");
verifyCursorAt(Cursor(0, 8));
TestPressKey("\\enter");
FinishTest("foo foo bar foo foo");
// Wrap to the end if we find nothing.
DoTest("foo foo bar xyz xyz", "ww?xyz\\enterrX", "foo foo bar xyz Xyz");
// Specify that the last was backwards when using '?'
DoTest("foo foo bar foo foo", "ww?foo\\enter^wwnrX", "foo Xoo bar foo foo");
// ... and make sure we do the equivalent with "/"
BeginTest("foo foo bar foo foo");
TestPressKey("ww?foo\\enter^ww/foo");
QCOMPARE(emulatedCommandTypeIndicator()->text(), QString("/"));
TestPressKey("\\enter^wwnrX");
FinishTest("foo foo bar Xoo foo");
// If we are at the beginning of a word, that word is not the first match in a search
// for that word.
DoTest("foo foo foo", "w/foo\\enterrX", "foo foo Xoo");
DoTest("foo foo foo", "w?foo\\enterrX", "Xoo foo foo");
// When searching backwards, ensure we can find a match whose range includes the starting cursor position,
// if we allow it to wrap around.
DoTest("foo foofoofoo bar", "wlll?foofoofoo\\enterrX", "foo Xoofoofoo bar");
// When searching backwards, ensure we can find a match whose range includes the starting cursor position,
// even if we don't allow it to wrap around.
DoTest("foo foofoofoo foofoofoo", "wlll?foofoofoo\\enterrX", "foo Xoofoofoo foofoofoo");
// The same, but where we the match ends at the end of the line or document.
DoTest("foo foofoofoo\nfoofoofoo", "wlll?foofoofoo\\enterrX", "foo Xoofoofoo\nfoofoofoo");
DoTest("foo foofoofoo", "wlll?foofoofoo\\enterrX", "foo Xoofoofoo");
// Searching forwards for just "/" repeats last search.
DoTest("foo bar", "/bar\\entergg//\\enterrX", "foo Xar");
// The "last search" can be one initiated via e.g. "*".
DoTest("foo bar foo", "/bar\\entergg*gg//\\enterrX", "foo bar Xoo");
// Searching backwards for just "?" repeats last search.
DoTest("foo bar bar", "/bar\\entergg??\\enterrX", "foo bar Xar");
// Search forwards treats "?" as a literal.
DoTest("foo ?ba?r", "/?ba?r\\enterrX", "foo Xba?r");
// As always, be careful with escaping!
DoTest("foo ?ba\\?r", "/?ba\\\\\\\\\\\\?r\\enterrX", "foo Xba\\?r");
// Searching forwards for just "?" finds literal question marks.
DoTest("foo ??", "/?\\enterrX", "foo X?");
// Searching backwards for just "/" finds literal forward slashes.
DoTest("foo //", "?/\\enterrX", "foo /X");
// Searching forwards, stuff after (and including) an unescaped "/" is ignored.
DoTest("foo ba bar bar/xyz", "/bar/xyz\\enterrX", "foo ba Xar bar/xyz");
// Needs to be unescaped, though!
DoTest("foo bar bar/xyz", "/bar\\\\/xyz\\enterrX", "foo bar Xar/xyz");
DoTest("foo bar bar\\/xyz", "/bar\\\\\\\\/xyz\\enterrX", "foo bar Xar\\/xyz");
// Searching backwards, stuff after (and including) an unescaped "?" is ignored.
DoTest("foo bar bar?xyz bar ba", "?bar?xyz\\enterrX", "foo bar bar?xyz Xar ba");
// Needs to be unescaped, though!
DoTest("foo bar bar?xyz bar ba", "?bar\\\\?xyz\\enterrX", "foo bar Xar?xyz bar ba");
DoTest("foo bar bar\\?xyz bar ba", "?bar\\\\\\\\?xyz\\enterrX", "foo bar Xar\\?xyz bar ba");
// If, in a forward search, the first character after the first unescaped "/" is an e, then
// we place the cursor at the end of the word.
DoTest("foo ba bar bar/eyz", "/bar/e\\enterrX", "foo ba baX bar/eyz");
// Needs to be unescaped, though!
DoTest("foo bar bar/eyz", "/bar\\\\/e\\enterrX", "foo bar Xar/eyz");
DoTest("foo bar bar\\/xyz", "/bar\\\\\\\\/e\\enterrX", "foo bar barX/xyz");
// If, in a backward search, the first character after the first unescaped "?" is an e, then
// we place the cursor at the end of the word.
DoTest("foo bar bar?eyz bar ba", "?bar?e\\enterrX", "foo bar bar?eyz baX ba");
// Needs to be unescaped, though!
DoTest("foo bar bar?eyz bar ba", "?bar\\\\?e\\enterrX", "foo bar Xar?eyz bar ba");
DoTest("foo bar bar\\?eyz bar ba", "?bar\\\\\\\\?e\\enterrX", "foo bar barX?eyz bar ba");
// Quick check that repeating the last search and placing the cursor at the end of the match works.
DoTest("foo bar bar", "/bar\\entergg//e\\enterrX", "foo baX bar");
DoTest("foo bar bar", "?bar\\entergg??e\\enterrX", "foo bar baX");
// When repeating a change, don't try to convert from Vim to Qt regex again.
DoTest("foo bar()", "/bar()\\entergg//e\\enterrX", "foo bar(X");
DoTest("foo bar()", "?bar()\\entergg??e\\enterrX", "foo bar(X");
// If the last search said that we should place the cursor at the end of the match, then
// do this with n & N.
DoTest("foo bar bar foo", "/bar/e\\enterggnrX", "foo baX bar foo");
DoTest("foo bar bar foo", "/bar/e\\enterggNrX", "foo bar baX foo");
// Don't do this if that search was aborted, though.
DoTest("foo bar bar foo", "/bar\\enter/bar/e\\ctrl-cggnrX", "foo Xar bar foo");
DoTest("foo bar bar foo", "/bar\\enter/bar/e\\ctrl-cggNrX", "foo bar Xar foo");
// "#" and "*" reset the "place cursor at the end of the match" to false.
DoTest("foo bar bar foo", "/bar/e\\enterggw*nrX", "foo Xar bar foo");
DoTest("foo bar bar foo", "/bar/e\\enterggw#nrX", "foo Xar bar foo");
// "/" and "?" should be usable as motions.
DoTest("foo bar", "ld/bar\\enter", "fbar");
// They are not linewise.
DoTest("foo bar\nxyz", "ld/yz\\enter", "fyz");
DoTest("foo bar\nxyz", "jld?oo\\enter", "fyz");
// Should be usable in Visual Mode without aborting Visual Mode.
DoTest("foo bar", "lv/bar\\enterd", "far");
// Same for ?.
DoTest("foo bar", "$hd?oo\\enter", "far");
DoTest("foo bar", "$hv?oo\\enterd", "fr");
DoTest("foo bar", "lv?bar\\enterd", "far");
// If we abort the "/" / "?" motion, the command should be aborted, too.
DoTest("foo bar", "d/bar\\esc", "foo bar");
DoTest("foo bar", "d/bar\\ctrl-c", "foo bar");
DoTest("foo bar", "d/bar\\ctrl-[", "foo bar");
// We should be able to repeat a command using "/" or "?" as the motion.
DoTest("foo bar bar bar", "d/bar\\enter.", "bar bar");
// The "synthetic" Enter keypress should not be logged as part of the command to be repeated.
DoTest("foo bar bar bar\nxyz", "d/bar\\enter.rX", "Xar bar\nxyz");
// Counting.
DoTest("foo bar bar bar", "2/bar\\enterrX", "foo bar Xar bar");
// Counting with wraparound.
DoTest("foo bar bar bar", "4/bar\\enterrX", "foo Xar bar bar");
// Counting in Visual Mode.
DoTest("foo bar bar bar", "v2/bar\\enterd", "ar bar");
// Should update the selection in Visual Mode as we search.
BeginTest("foo bar bbc");
TestPressKey("vl/b");
QCOMPARE(kate_view->selectionText(), QString("foo b"));
TestPressKey("b");
QCOMPARE(kate_view->selectionText(), QString("foo bar b"));
TestPressKey("\\ctrl-h");
QCOMPARE(kate_view->selectionText(), QString("foo b"));
TestPressKey("notexists");
QCOMPARE(kate_view->selectionText(), QString("fo"));
TestPressKey("\\enter"); // Dismiss bar.
QCOMPARE(kate_view->selectionText(), QString("fo"));
FinishTest("foo bar bbc");
BeginTest("foo\nxyz\nbar\nbbc");
TestPressKey("Vj/b");
QCOMPARE(kate_view->selectionText(), QString("foo\nxyz\nbar"));
TestPressKey("b");
QCOMPARE(kate_view->selectionText(), QString("foo\nxyz\nbar\nbbc"));
TestPressKey("\\ctrl-h");
QCOMPARE(kate_view->selectionText(), QString("foo\nxyz\nbar"));
TestPressKey("notexists");
QCOMPARE(kate_view->selectionText(), QString("foo\nxyz"));
TestPressKey("\\ctrl-c"); // Dismiss bar.
FinishTest("foo\nxyz\nbar\nbbc");
// Dismissing the search bar in visual mode should leave original selection.
BeginTest("foo bar bbc");
TestPressKey("vl/\\ctrl-c");
QCOMPARE(kate_view->selectionText(), QString("fo"));
FinishTest("foo bar bbc");
BeginTest("foo bar bbc");
TestPressKey("vl?\\ctrl-c");
QCOMPARE(kate_view->selectionText(), QString("fo"));
FinishTest("foo bar bbc");
BeginTest("foo bar bbc");
TestPressKey("vl/b\\ctrl-c");
QCOMPARE(kate_view->selectionText(), QString("fo"));
FinishTest("foo bar bbc");
BeginTest("foo\nbar\nbbc");
TestPressKey("Vl/b\\ctrl-c");
QCOMPARE(kate_view->selectionText(), QString("foo"));
FinishTest("foo\nbar\nbbc");
// Search-highlighting tests.
const QColor searchHighlightColour = kate_view->renderer()->config()->searchHighlightColor();
BeginTest("foo bar xyz");
// Sanity test.
const QList rangesInitial = rangesOnFirstLine();
Q_ASSERT(rangesInitial.isEmpty() && "Assumptions about ranges are wrong - this test is invalid and may need updating!");
FinishTest("foo bar xyz");
// Test highlighting single character match.
BeginTest("foo bar xyz");
TestPressKey("/b");
QCOMPARE(rangesOnFirstLine().size(), rangesInitial.size() + 1);
QCOMPARE(rangesOnFirstLine().first()->attribute()->background().color(), searchHighlightColour);
QCOMPARE(rangesOnFirstLine().first()->start().line(), 0);
QCOMPARE(rangesOnFirstLine().first()->start().column(), 4);
QCOMPARE(rangesOnFirstLine().first()->end().line(), 0);
QCOMPARE(rangesOnFirstLine().first()->end().column(), 5);
TestPressKey("\\enter");
FinishTest("foo bar xyz");
// Test highlighting two character match.
BeginTest("foo bar xyz");
TestPressKey("/ba");
QCOMPARE(rangesOnFirstLine().size(), rangesInitial.size() + 1);
QCOMPARE(rangesOnFirstLine().first()->start().line(), 0);
QCOMPARE(rangesOnFirstLine().first()->start().column(), 4);
QCOMPARE(rangesOnFirstLine().first()->end().line(), 0);
QCOMPARE(rangesOnFirstLine().first()->end().column(), 6);
TestPressKey("\\enter");
FinishTest("foo bar xyz");
// Test no highlighting if no longer a match.
BeginTest("foo bar xyz");
TestPressKey("/baz");
QCOMPARE(rangesOnFirstLine().size(), rangesInitial.size());
TestPressKey("\\enter");
FinishTest("foo bar xyz");
// Test highlighting on wraparound.
BeginTest(" foo bar xyz");
TestPressKey("ww/foo");
QCOMPARE(rangesOnFirstLine().size(), rangesInitial.size() + 1);
QCOMPARE(rangesOnFirstLine().first()->start().line(), 0);
QCOMPARE(rangesOnFirstLine().first()->start().column(), 1);
QCOMPARE(rangesOnFirstLine().first()->end().line(), 0);
QCOMPARE(rangesOnFirstLine().first()->end().column(), 4);
TestPressKey("\\enter");
FinishTest(" foo bar xyz");
// Test highlighting backwards
BeginTest("foo bar xyz");
TestPressKey("$?ba");
QCOMPARE(rangesOnFirstLine().size(), rangesInitial.size() + 1);
QCOMPARE(rangesOnFirstLine().first()->start().line(), 0);
QCOMPARE(rangesOnFirstLine().first()->start().column(), 4);
QCOMPARE(rangesOnFirstLine().first()->end().line(), 0);
QCOMPARE(rangesOnFirstLine().first()->end().column(), 6);
TestPressKey("\\enter");
FinishTest("foo bar xyz");
// Test no highlighting when no match is found searching backwards
BeginTest("foo bar xyz");
TestPressKey("$?baz");
QCOMPARE(rangesOnFirstLine().size(), rangesInitial.size());
TestPressKey("\\enter");
FinishTest("foo bar xyz");
// Test highlight when wrapping around after searching backwards.
BeginTest("foo bar xyz");
TestPressKey("w?xyz");
QCOMPARE(rangesOnFirstLine().size(), rangesInitial.size() + 1);
QCOMPARE(rangesOnFirstLine().first()->start().line(), 0);
QCOMPARE(rangesOnFirstLine().first()->start().column(), 8);
QCOMPARE(rangesOnFirstLine().first()->end().line(), 0);
QCOMPARE(rangesOnFirstLine().first()->end().column(), 11);
TestPressKey("\\enter");
FinishTest("foo bar xyz");
// Test no highlighting when bar is dismissed.
DoTest("foo bar xyz", "/bar\\ctrl-c", "foo bar xyz");
QCOMPARE(rangesOnFirstLine().size(), rangesInitial.size());
DoTest("foo bar xyz", "/bar\\enter", "foo bar xyz");
QCOMPARE(rangesOnFirstLine().size(), rangesInitial.size());
DoTest("foo bar xyz", "/bar\\ctrl-[", "foo bar xyz");
QCOMPARE(rangesOnFirstLine().size(), rangesInitial.size());
DoTest("foo bar xyz", "/bar\\return", "foo bar xyz");
QCOMPARE(rangesOnFirstLine().size(), rangesInitial.size());
DoTest("foo bar xyz", "/bar\\esc", "foo bar xyz");
QCOMPARE(rangesOnFirstLine().size(), rangesInitial.size());
// Update colour on config change.
BeginTest("foo bar xyz");
TestPressKey("/xyz");
const QColor newSearchHighlightColour = QColor(255, 0, 0);
kate_view->renderer()->config()->setSearchHighlightColor(newSearchHighlightColour);
QCOMPARE(rangesOnFirstLine().size(), rangesInitial.size() + 1);
QCOMPARE(rangesOnFirstLine().first()->attribute()->background().color(), newSearchHighlightColour);
TestPressKey("\\enter");
FinishTest("foo bar xyz");
// Set the background colour appropriately.
KColorScheme currentColorScheme(QPalette::Normal);
const QColor normalBackgroundColour = QPalette().brush(QPalette::Base).color();
const QColor matchBackgroundColour = currentColorScheme.background(KColorScheme::PositiveBackground).color();
const QColor noMatchBackgroundColour = currentColorScheme.background(KColorScheme::NegativeBackground).color();
BeginTest("foo bar xyz");
TestPressKey("/xyz");
verifyTextEditBackgroundColour(matchBackgroundColour);
TestPressKey("a");
verifyTextEditBackgroundColour(noMatchBackgroundColour);
TestPressKey("\\ctrl-w");
verifyTextEditBackgroundColour(normalBackgroundColour);
TestPressKey("/xyz\\enter/");
verifyTextEditBackgroundColour(normalBackgroundColour);
TestPressKey("\\enter");
FinishTest("foo bar xyz");
// Escape regex's in a Vim-ish style.
// Unescaped ( and ) are always literals.
DoTest("foo bar( xyz", "/bar(\\enterrX", "foo Xar( xyz");
DoTest("foo bar) xyz", "/bar)\\enterrX", "foo Xar) xyz");
// + is literal, unless it is already escaped.
DoTest("foo bar+ xyz", "/bar+ \\enterrX", "foo Xar+ xyz");
DoTest(" foo+AAAAbar", "/foo+A\\\\+bar\\enterrX", " Xoo+AAAAbar");
DoTest(" foo++++bar", "/foo+\\\\+bar\\enterrX", " Xoo++++bar");
DoTest(" foo++++bar", "/+\\enterrX", " fooX+++bar");
// An escaped "\" is a literal, of course.
DoTest("foo x\\y", "/x\\\\\\\\y\\enterrX", "foo X\\y");
// ( and ), if escaped, are not literals.
DoTest("foo barbarxyz", "/ \\\\(bar\\\\)\\\\+xyz\\enterrX", "foo Xbarbarxyz");
// Handle escaping correctly if we have an escaped and unescaped bracket next to each other.
DoTest("foo x(A)y", "/x(\\\\(.\\\\))y\\enterrX", "foo X(A)y");
// |, if unescaped, is literal.
DoTest("foo |bar", "/|\\enterrX", "foo Xbar");
// |, if escaped, is not a literal.
DoTest("foo xfoo\\y xbary", "/x\\\\(foo\\\\|bar\\\\)y\\enterrX", "foo xfoo\\y Xbary");
// A single [ is a literal.
DoTest("foo bar[", "/bar[\\enterrX", "foo Xar[");
// A single ] is a literal.
DoTest("foo bar]", "/bar]\\enterrX", "foo Xar]");
// A matching [ and ] are *not* literals.
DoTest("foo xbcay", "/x[abc]\\\\+y\\enterrX", "foo Xbcay");
DoTest("foo xbcay", "/[abc]\\\\+y\\enterrX", "foo xXcay");
DoTest("foo xbaadcdcy", "/x[ab]\\\\+[cd]\\\\+y\\enterrX", "foo Xbaadcdcy");
// Need to be an unescaped match, though.
DoTest("foo xbcay", "/x[abc\\\\]\\\\+y\\enterrX", "Xoo xbcay");
DoTest("foo xbcay", "/x\\\\[abc]\\\\+y\\enterrX", "Xoo xbcay");
DoTest("foo x[abc]]]]]y", "/x\\\\[abc]\\\\+y\\enterrX", "foo X[abc]]]]]y");
// An escaped '[' between matching unescaped '[' and ']' is treated as a literal '['
DoTest("foo xb[cay", "/x[a\\\\[bc]\\\\+y\\enterrX", "foo Xb[cay");
// An escaped ']' between matching unescaped '[' and ']' is treated as a literal ']'
DoTest("foo xb]cay", "/x[a\\\\]bc]\\\\+y\\enterrX", "foo Xb]cay");
// An escaped '[' not between other square brackets is a literal.
DoTest("foo xb[cay", "/xb\\\\[\\enterrX", "foo Xb[cay");
DoTest("foo xb[cay", "/\\\\[ca\\enterrX", "foo xbXcay");
// An escaped ']' not between other square brackets is a literal.
DoTest("foo xb]cay", "/xb\\\\]\\enterrX", "foo Xb]cay");
DoTest("foo xb]cay", "/\\\\]ca\\enterrX", "foo xbXcay");
// An unescaped '[' not between other square brackets is a literal.
DoTest("foo xbaba[y", "/x[ab]\\\\+[y\\enterrX", "foo Xbaba[y");
DoTest("foo xbaba[dcdcy", "/x[ab]\\\\+[[cd]\\\\+y\\enterrX", "foo Xbaba[dcdcy");
// An unescaped ']' not between other square brackets is a literal.
DoTest("foo xbaba]y", "/x[ab]\\\\+]y\\enterrX", "foo Xbaba]y");
DoTest("foo xbaba]dcdcy", "/x[ab]\\\\+][cd]\\\\+y\\enterrX", "foo Xbaba]dcdcy");
// Be more clever about how we indentify escaping: the presence of a preceding
// backslash is not always sufficient!
DoTest("foo x\\babay", "/x\\\\\\\\[ab]\\\\+y\\enterrX", "foo X\\babay");
DoTest("foo x\\[abc]]]]y", "/x\\\\\\\\\\\\[abc]\\\\+y\\enterrX", "foo X\\[abc]]]]y");
DoTest("foo xa\\b\\c\\y", "/x[abc\\\\\\\\]\\\\+y\\enterrX", "foo Xa\\b\\c\\y");
DoTest("foo x[abc\\]]]]y", "/x[abc\\\\\\\\\\\\]\\\\+y\\enterrX", "foo X[abc\\]]]]y");
DoTest("foo xa[\\b\\[y", "/x[ab\\\\\\\\[]\\\\+y\\enterrX", "foo Xa[\\b\\[y");
DoTest("foo x\\[y", "/x\\\\\\\\[y\\enterrX", "foo X\\[y");
DoTest("foo x\\]y", "/x\\\\\\\\]y\\enterrX", "foo X\\]y");
DoTest("foo x\\+y", "/x\\\\\\\\+y\\enterrX", "foo X\\+y");
// A dot is not a literal, nor is a star.
DoTest("foo bar", "/o.*b\\enterrX", "fXo bar");
// Escaped dots and stars are literals, though.
DoTest("foo xay x.y", "/x\\\\.y\\enterrX", "foo xay X.y");
DoTest("foo xaaaay xa*y", "/xa\\\\*y\\enterrX", "foo xaaaay Xa*y");
// Unescaped curly braces are literals.
DoTest("foo x{}y", "/x{}y\\enterrX", "foo X{}y");
// Escaped curly brackets are quantifers.
DoTest("foo xaaaaay", "/xa\\\\{5\\\\}y\\enterrX", "foo Xaaaaay");
// Matching curly brackets where only the first is escaped are also quantifiers.
DoTest("foo xaaaaaybbbz", "/xa\\\\{5}yb\\\\{3}z\\enterrX", "foo Xaaaaaybbbz");
// Make sure it really is escaped, though!
DoTest("foo xa\\{5}", "/xa\\\\\\\\{5}\\enterrX", "foo Xa\\{5}");
// Don't crash if the first character is a }
DoTest("foo aaaaay", "/{\\enterrX", "Xoo aaaaay");
// Vim's '\<' and '\>' map, roughly, to Qt's '\b'
DoTest("foo xbar barx bar", "/bar\\\\>\\enterrX", "foo xXar barx bar");
DoTest("foo xbar barx bar", "/\\\\\\enterrX", "foo xbar barx Xar ");
DoTest("foo xbar barx bar", "/\\\\\\enterrX", "foo xbar barx Xar");
DoTest("foo xbar barx\nbar", "/\\\\\\enterrX", "foo xbar barx\nXar");
// Escaped "^" and "$" are treated as literals.
DoTest("foo x^$y", "/x\\\\^\\\\$y\\enterrX", "foo X^$y");
// Ensure that it is the escaped version of the pattern that is recorded as the last search pattern.
DoTest("foo bar( xyz", "/bar(\\enterggnrX", "foo Xar( xyz");
// Don't log keypresses sent to the emulated command bar as commands to be repeated via "."!
DoTest("foo", "/diw\\enterciwbar\\ctrl-c.", "bar");
// Don't leave Visual mode on aborting a search.
DoTest("foo bar", "vw/\\ctrl-cd", "ar");
DoTest("foo bar", "vw/\\ctrl-[d", "ar");
// Don't crash on leaving Visual Mode on aborting a search. This is perhaps the most opaque regression
// test ever; what it's testing for is the situation where the synthetic keypress issue by the emulated
// command bar on the "ctrl-[" is sent to the key mapper. This in turn converts it into a weird character
// which is then, upon not being recognised as part of a mapping, sent back around the keypress processing,
// where it ends up being sent to the emulated command bar's text edit, which in turn issues a "text changed"
// event where the text is still empty, which tries to move the cursor to (-1, -1), which causes a crash deep
// within Kate. So, in a nutshell: this test ensures that the keymapper never handles the synthetic keypress :)
DoTest("", "ifoo\\ctrl-cv/\\ctrl-[", "foo");
// History auto-completion tests.
clearSearchHistory();
QVERIFY(searchHistory().isEmpty());
vi_global->searchHistory()->append("foo");
vi_global->searchHistory()->append("bar");
QCOMPARE(searchHistory(), QStringList() << "foo" << "bar");
clearSearchHistory();
QVERIFY(searchHistory().isEmpty());
// Ensure current search bar text is added to the history if we press enter.
DoTest("foo bar", "/bar\\enter", "foo bar");
DoTest("foo bar", "/xyz\\enter", "foo bar");
QCOMPARE(searchHistory(), QStringList() << "bar" << "xyz");
// Interesting - Vim adds the search bar text to the history even if we abort via e.g. ctrl-c, ctrl-[, etc.
clearSearchHistory();
DoTest("foo bar", "/baz\\ctrl-[", "foo bar");
QCOMPARE(searchHistory(), QStringList() << "baz");
clearSearchHistory();
DoTest("foo bar", "/foo\\esc", "foo bar");
QCOMPARE(searchHistory(), QStringList() << "foo");
clearSearchHistory();
DoTest("foo bar", "/nose\\ctrl-c", "foo bar");
QCOMPARE(searchHistory(), QStringList() << "nose");
clearSearchHistory();
vi_global->searchHistory()->append("foo");
vi_global->searchHistory()->append("bar");
QVERIFY(emulatedCommandBarCompleter() != nullptr);
BeginTest("foo bar");
TestPressKey("/\\ctrl-p");
verifyCommandBarCompletionVisible();
// Make sure the completion appears in roughly the correct place: this is a little fragile :/
const QPoint completerRectTopLeft = emulatedCommandBarCompleter()->popup()->mapToGlobal(emulatedCommandBarCompleter()->popup()->rect().topLeft()) ;
const QPoint barEditBottomLeft = emulatedCommandBarTextEdit()->mapToGlobal(emulatedCommandBarTextEdit()->rect().bottomLeft());
QCOMPARE(completerRectTopLeft.x(), barEditBottomLeft.x());
QVERIFY(qAbs(completerRectTopLeft.y() - barEditBottomLeft.y()) <= 1);
// Will activate the current completion item, activating the search, and dismissing the bar.
TestPressKey("\\enter");
QVERIFY(!emulatedCommandBarCompleter()->popup()->isVisible());
// Close the command bar.
FinishTest("foo bar");
// Don't show completion with an empty search bar.
clearSearchHistory();
vi_global->searchHistory()->append("foo");
BeginTest("foo bar");
TestPressKey("/");
QVERIFY(!emulatedCommandBarCompleter()->popup()->isVisible());
TestPressKey("\\enter");
FinishTest("foo bar");
// Don't auto-complete, either.
clearSearchHistory();
vi_global->searchHistory()->append("foo");
BeginTest("foo bar");
TestPressKey("/f");
QVERIFY(!emulatedCommandBarCompleter()->popup()->isVisible());
TestPressKey("\\enter");
FinishTest("foo bar");
clearSearchHistory();
vi_global->searchHistory()->append("xyz");
vi_global->searchHistory()->append("bar");
QVERIFY(emulatedCommandBarCompleter() != nullptr);
BeginTest("foo bar");
TestPressKey("/\\ctrl-p");
QCOMPARE(emulatedCommandBarCompleter()->currentCompletion(), QString("bar"));
TestPressKey("\\enter"); // Dismiss bar.
FinishTest("foo bar");
clearSearchHistory();
vi_global->searchHistory()->append("xyz");
vi_global->searchHistory()->append("bar");
vi_global->searchHistory()->append("foo");
QVERIFY(emulatedCommandBarCompleter() != nullptr);
BeginTest("foo bar");
TestPressKey("/\\ctrl-p");
QCOMPARE(emulatedCommandBarTextEdit()->text(), QString("foo"));
QCOMPARE(emulatedCommandBarCompleter()->currentCompletion(), QString("foo"));
QCOMPARE(emulatedCommandBarCompleter()->popup()->currentIndex().row(), 0);
TestPressKey("\\ctrl-p");
QCOMPARE(emulatedCommandBarTextEdit()->text(), QString("bar"));
QCOMPARE(emulatedCommandBarCompleter()->currentCompletion(), QString("bar"));
QCOMPARE(emulatedCommandBarCompleter()->popup()->currentIndex().row(), 1);
TestPressKey("\\ctrl-p");
QCOMPARE(emulatedCommandBarTextEdit()->text(), QString("xyz"));
QCOMPARE(emulatedCommandBarCompleter()->currentCompletion(), QString("xyz"));
QCOMPARE(emulatedCommandBarCompleter()->popup()->currentIndex().row(), 2);
TestPressKey("\\ctrl-p");
QCOMPARE(emulatedCommandBarTextEdit()->text(), QString("foo"));
QCOMPARE(emulatedCommandBarCompleter()->currentCompletion(), QString("foo")); // Wrap-around
QCOMPARE(emulatedCommandBarCompleter()->popup()->currentIndex().row(), 0);
TestPressKey("\\enter"); // Dismiss bar.
FinishTest("foo bar");
clearSearchHistory();
vi_global->searchHistory()->append("xyz");
vi_global->searchHistory()->append("bar");
vi_global->searchHistory()->append("foo");
QVERIFY(emulatedCommandBarCompleter() != nullptr);
BeginTest("foo bar");
TestPressKey("/\\ctrl-n");
verifyCommandBarCompletionVisible();
QCOMPARE(emulatedCommandBarTextEdit()->text(), QString("xyz"));
QCOMPARE(emulatedCommandBarCompleter()->currentCompletion(), QString("xyz"));
QCOMPARE(emulatedCommandBarCompleter()->popup()->currentIndex().row(), 2);
TestPressKey("\\ctrl-n");
QCOMPARE(emulatedCommandBarTextEdit()->text(), QString("bar"));
QCOMPARE(emulatedCommandBarCompleter()->currentCompletion(), QString("bar"));
QCOMPARE(emulatedCommandBarCompleter()->popup()->currentIndex().row(), 1);
TestPressKey("\\ctrl-n");
QCOMPARE(emulatedCommandBarTextEdit()->text(), QString("foo"));
QCOMPARE(emulatedCommandBarCompleter()->currentCompletion(), QString("foo"));
QCOMPARE(emulatedCommandBarCompleter()->popup()->currentIndex().row(), 0);
TestPressKey("\\ctrl-n");
QCOMPARE(emulatedCommandBarTextEdit()->text(), QString("xyz"));
QCOMPARE(emulatedCommandBarCompleter()->currentCompletion(), QString("xyz")); // Wrap-around.
QCOMPARE(emulatedCommandBarCompleter()->popup()->currentIndex().row(), 2);
TestPressKey("\\enter"); // Dismiss bar.
FinishTest("foo bar");
clearSearchHistory();
vi_global->searchHistory()->append("xyz");
vi_global->searchHistory()->append("bar");
vi_global->searchHistory()->append("foo");
BeginTest("foo bar");
TestPressKey("/\\ctrl-n\\ctrl-n");
QCOMPARE(emulatedCommandBarTextEdit()->text(), QString("bar"));
TestPressKey("\\enter"); // Dismiss bar.
FinishTest("foo bar");
// If we add something to the history, remove any earliest occurrences (this is what Vim appears to do)
// and append to the end.
clearSearchHistory();
vi_global->searchHistory()->append("bar");
vi_global->searchHistory()->append("xyz");
vi_global->searchHistory()->append("foo");
vi_global->searchHistory()->append("xyz");
QCOMPARE(searchHistory(), QStringList() << "bar" << "foo" << "xyz");
// Push out older entries if we have too many search items in the history.
const int HISTORY_SIZE_LIMIT = 100;
clearSearchHistory();
for (int i = 1; i <= HISTORY_SIZE_LIMIT; i++)
{
vi_global->searchHistory()->append(QString("searchhistoryitem %1").arg(i));
}
QCOMPARE(searchHistory().size(), HISTORY_SIZE_LIMIT);
QCOMPARE(searchHistory().first(), QString("searchhistoryitem 1"));
QCOMPARE(searchHistory().last(), QString("searchhistoryitem 100"));
vi_global->searchHistory()->append(QString("searchhistoryitem %1").arg(HISTORY_SIZE_LIMIT + 1));
QCOMPARE(searchHistory().size(), HISTORY_SIZE_LIMIT);
QCOMPARE(searchHistory().first(), QString("searchhistoryitem 2"));
QCOMPARE(searchHistory().last(), QString("searchhistoryitem %1").arg(HISTORY_SIZE_LIMIT + 1));
// Don't add empty searches to the history.
clearSearchHistory();
DoTest("foo bar", "/\\enter", "foo bar");
QVERIFY(searchHistory().isEmpty());
// "*" and "#" should add the relevant word to the search history, enclosed between \< and \>
clearSearchHistory();
BeginTest("foo bar");
TestPressKey("*");
QVERIFY(!searchHistory().isEmpty());
QCOMPARE(searchHistory().last(), QString("\\"));
TestPressKey("w#");
QCOMPARE(searchHistory().size(), 2);
QCOMPARE(searchHistory().last(), QString("\\"));
// Auto-complete words from the document on ctrl-space.
// Test that we can actually find a single word and add it to the list of completions.
BeginTest("foo");
TestPressKey("/\\ctrl- ");
verifyCommandBarCompletionVisible();
QCOMPARE(emulatedCommandBarCompleter()->currentCompletion(), QString("foo"));
TestPressKey("\\enter\\enter"); // Dismiss completion, then bar.
FinishTest("foo");
// Count digits and underscores as being part of a word.
BeginTest("foo_12");
TestPressKey("/\\ctrl- ");
verifyCommandBarCompletionVisible();
QCOMPARE(emulatedCommandBarCompleter()->currentCompletion(), QString("foo_12"));
TestPressKey("\\enter\\enter"); // Dismiss completion, then bar.
FinishTest("foo_12");
// This feels a bit better to me, usability-wise: in the special case of completion from document, where
// the completion list is manually summoned, allow one to press Enter without the bar being dismissed
// (just dismiss the completion list instead).
BeginTest("foo_12");
TestPressKey("/\\ctrl- \\ctrl-p\\enter");
QVERIFY(emulatedCommandBar->isVisible());
QVERIFY(!emulatedCommandBarCompleter()->popup()->isVisible());
TestPressKey("\\enter"); // Dismiss bar.
FinishTest("foo_12");
// Check that we can find multiple words on one line.
BeginTest("bar (foo) [xyz]");
TestPressKey("/\\ctrl- ");
QStringListModel *completerStringListModel = dynamic_cast(emulatedCommandBarCompleter()->model());
Q_ASSERT(completerStringListModel);
QCOMPARE(completerStringListModel->stringList(), QStringList() << "bar" << "foo" << "xyz");
TestPressKey("\\enter\\enter"); // Dismiss completion, then bar.
FinishTest("bar (foo) [xyz]");
// Check that we arrange the found words in case-insensitive sorted order.
BeginTest("D c e a b f");
TestPressKey("/\\ctrl- ");
verifyCommandBarCompletionsMatches(QStringList() << "a" << "b" << "c" << "D" << "e" << "f");
TestPressKey("\\enter\\enter"); // Dismiss completion, then bar.
FinishTest("D c e a b f");
// Check that we don't include the same word multiple times.
BeginTest("foo bar bar bar foo");
TestPressKey("/\\ctrl- ");
verifyCommandBarCompletionsMatches(QStringList() << "bar" << "foo");
TestPressKey("\\enter\\enter"); // Dismiss completion, then bar.
FinishTest("foo bar bar bar foo");
// Check that we search only a narrow portion of the document, around the cursor (4096 lines either
// side, say).
QStringList manyLines;
for (int i = 1; i < 2 * 4096 + 3; i++)
{
// Pad the digits so that when sorted alphabetically, they are also sorted numerically.
manyLines << QString("word%1").arg(i, 5, 10, QChar('0'));
}
QStringList allButFirstAndLastOfManyLines = manyLines;
allButFirstAndLastOfManyLines.removeFirst();
allButFirstAndLastOfManyLines.removeLast();
BeginTest(manyLines.join("\n"));
TestPressKey("4097j/\\ctrl- ");
verifyCommandBarCompletionsMatches(allButFirstAndLastOfManyLines);
TestPressKey("\\enter\\enter"); // Dismiss completion, then bar.
FinishTest(manyLines.join("\n"));
// "The current word" means the word before the cursor in the command bar, and includes numbers
// and underscores. Make sure also that the completion prefix is set when the completion is first invoked.
BeginTest("foo fee foa_11 foa_11b");
// Write "bar(foa112$nose" and position cursor before the "2", then invoke completion.
TestPressKey("/bar(foa_112$nose\\left\\left\\left\\left\\left\\left\\ctrl- ");
verifyCommandBarCompletionsMatches(QStringList() << "foa_11" << "foa_11b");
TestPressKey("\\enter\\enter"); // Dismiss completion, then bar.
FinishTest("foo fee foa_11 foa_11b");
// But don't count "-" as being part of the current word.
BeginTest("foo_12");
TestPressKey("/bar-foo\\ctrl- ");
verifyCommandBarCompletionVisible();
QCOMPARE(emulatedCommandBarCompleter()->currentCompletion(), QString("foo_12"));
TestPressKey("\\enter\\enter"); // Dismiss completion, then bar.
FinishTest("foo_12");
// Be case insensitive.
BeginTest("foo Fo12 fOo13 FO45");
TestPressKey("/fo\\ctrl- ");
verifyCommandBarCompletionsMatches(QStringList() << "Fo12" << "FO45" << "foo" << "fOo13");
TestPressKey("\\enter\\enter"); // Dismiss completion, then bar.
FinishTest("foo Fo12 fOo13 FO45");
// Feed the current word to complete to the completer as we type/ edit.
BeginTest("foo fee foa foab");
TestPressKey("/xyz|f\\ctrl- o");
verifyCommandBarCompletionsMatches(QStringList() << "foa" << "foab" << "foo");
TestPressKey("a");
verifyCommandBarCompletionsMatches(QStringList() << "foa" << "foab");
TestPressKey("\\ctrl-h");
verifyCommandBarCompletionsMatches(QStringList() << "foa" << "foab" << "foo");
TestPressKey("o");
verifyCommandBarCompletionsMatches(QStringList() << "foo");
TestPressKey("\\enter\\enter"); // Dismiss completion, then bar.
FinishTest("foo fee foa foab");
// Upon selecting a completion with an empty command bar, add the completed text to the command bar.
BeginTest("foo fee fob foables");
TestPressKey("/\\ctrl- foa\\ctrl-p");
QCOMPARE(emulatedCommandBarTextEdit()->text(), QString("foables"));
verifyCommandBarCompletionVisible();
TestPressKey("\\enter\\enter"); // Dismiss completion, then bar.
FinishTest("foo fee fob foables");
// If bar is non-empty, replace the word under the cursor.
BeginTest("foo fee foa foab");
TestPressKey("/xyz|f$nose\\left\\left\\left\\left\\left\\ctrl- oa\\ctrl-p");
QCOMPARE(emulatedCommandBarTextEdit()->text(), QString("xyz|foab$nose"));
TestPressKey("\\enter\\enter"); // Dismiss completion, then bar.
FinishTest("foo fee foa foab");
// Place the cursor at the end of the completed text.
BeginTest("foo fee foa foab");
TestPressKey("/xyz|f$nose\\left\\left\\left\\left\\left\\ctrl- oa\\ctrl-p\\enterX");
QCOMPARE(emulatedCommandBarTextEdit()->text(), QString("xyz|foabX$nose"));
TestPressKey("\\ctrl-c"); // Dismiss completion, then bar.
FinishTest("foo fee foa foab");
// If we're completing from history, though, the entire text gets set, and the completion prefix
// is the beginning of the entire text, not the current word before the cursor.
clearSearchHistory();
vi_global->searchHistory()->append("foo(bar");
BeginTest("");
TestPressKey("/foo(b\\ctrl-p");
verifyCommandBarCompletionVisible();
verifyCommandBarCompletionsMatches(QStringList() << "foo(bar");
QCOMPARE(emulatedCommandBarTextEdit()->text(), QString("foo(bar"));
TestPressKey("\\enter"); // Dismiss bar.
FinishTest("");
// If we're completing from history and we abort the completion via ctrl-c or ctrl-[, we revert the whole
// text to the last manually typed text.
clearSearchHistory();
vi_global->searchHistory()->append("foo(b|ar");
BeginTest("");
TestPressKey("/foo(b\\ctrl-p");
verifyCommandBarCompletionVisible();
verifyCommandBarCompletionsMatches(QStringList() << "foo(b|ar");
QCOMPARE(emulatedCommandBarTextEdit()->text(), QString("foo(b|ar"));
TestPressKey("\\ctrl-c"); // Dismiss completion.
QCOMPARE(emulatedCommandBarTextEdit()->text(), QString("foo(b"));
TestPressKey("\\enter"); // Dismiss bar.
FinishTest("");
// Scroll completion list if necessary so that currently selected completion is visible.
BeginTest("a b c d e f g h i j k l m n o p q r s t u v w x y z");
TestPressKey("/\\ctrl- ");
const int lastItemRow = 25;
const QRect initialLastCompletionItemRect = emulatedCommandBarCompleter()->popup()->visualRect(emulatedCommandBarCompleter()->popup()->model()->index(lastItemRow, 0));
QVERIFY(!emulatedCommandBarCompleter()->popup()->rect().contains(initialLastCompletionItemRect)); // If this fails, then we have an error in the test setup: initally, the last item in the list should be outside of the bounds of the popup.
TestPressKey("\\ctrl-n");
QCOMPARE(emulatedCommandBarCompleter()->currentCompletion(), QString("z"));
const QRect lastCompletionItemRect = emulatedCommandBarCompleter()->popup()->visualRect(emulatedCommandBarCompleter()->popup()->model()->index(lastItemRow, 0));
QVERIFY(emulatedCommandBarCompleter()->popup()->rect().contains(lastCompletionItemRect));
TestPressKey("\\enter\\enter"); // Dismiss completion, then bar.
FinishTest("a b c d e f g h i j k l m n o p q r s t u v w x y z");
// Ensure that the completion list changes size appropriately as the number of candidate completions changes.
BeginTest("a ab abc");
TestPressKey("/\\ctrl- ");
const int initialPopupHeight = emulatedCommandBarCompleter()->popup()->height();
TestPressKey("ab");
const int popupHeightAfterEliminatingOne = emulatedCommandBarCompleter()->popup()->height();
QVERIFY(popupHeightAfterEliminatingOne < initialPopupHeight);
TestPressKey("\\enter\\enter"); // Dismiss completion, then bar.
FinishTest("a ab abc");
// Ensure that the completion list disappears when no candidate completions are found, but re-appears
// when some are found.
BeginTest("a ab abc");
TestPressKey("/\\ctrl- ");
TestPressKey("abd");
QVERIFY(!emulatedCommandBarCompleter()->popup()->isVisible());
TestPressKey("\\ctrl-h");
verifyCommandBarCompletionVisible();
TestPressKey("\\enter\\enter"); // Dismiss completion, then bar.
FinishTest("a ab abc");
// ctrl-c and ctrl-[ when the completion list is visible should dismiss the completion list, but *not*
// the emulated command bar. TODO - same goes for ESC, but this is harder as KateViewInternal dismisses it
// itself.
BeginTest("a ab abc");
TestPressKey("/\\ctrl- \\ctrl-cdiw");
QVERIFY(!emulatedCommandBarCompleter()->popup()->isVisible());
QVERIFY(emulatedCommandBar->isVisible());
TestPressKey("\\enter"); // Dismiss bar.
TestPressKey("/\\ctrl- \\ctrl-[diw");
QVERIFY(!emulatedCommandBarCompleter()->popup()->isVisible());
QVERIFY(emulatedCommandBar->isVisible());
TestPressKey("\\enter"); // Dismiss bar.
FinishTest("a ab abc");
// If we implicitly choose an element from the summoned completion list (by highlighting it, then
// continuing to edit the text), the completion box should not re-appear unless explicitly summoned
// again, even if the current word has a valid completion.
BeginTest("a ab abc");
TestPressKey("/\\ctrl- \\ctrl-p");
TestPressKey(".a");
QVERIFY(!emulatedCommandBarCompleter()->popup()->isVisible());
TestPressKey("\\enter"); // Dismiss bar.
FinishTest("a ab abc");
// If we dismiss the summoned completion list via ctrl-c or ctrl-[, it should not re-appear unless explicitly summoned
// again, even if the current word has a valid completion.
BeginTest("a ab abc");
TestPressKey("/\\ctrl- \\ctrl-c");
TestPressKey(".a");
QVERIFY(!emulatedCommandBarCompleter()->popup()->isVisible());
TestPressKey("\\enter");
TestPressKey("/\\ctrl- \\ctrl-[");
TestPressKey(".a");
QVERIFY(!emulatedCommandBarCompleter()->popup()->isVisible());
TestPressKey("\\enter"); // Dismiss bar.
FinishTest("a ab abc");
// If we select a completion from an empty bar, but then dismiss it via ctrl-c or ctrl-[, then we
// should restore the empty text.
BeginTest("foo");
TestPressKey("/\\ctrl- \\ctrl-p");
QCOMPARE(emulatedCommandBarTextEdit()->text(), QString("foo"));
TestPressKey("\\ctrl-c");
QVERIFY(!emulatedCommandBarCompleter()->popup()->isVisible());
QVERIFY(emulatedCommandBar->isVisible());
QCOMPARE(emulatedCommandBarTextEdit()->text(), QString(""));
TestPressKey("\\enter"); // Dismiss bar.
FinishTest("foo");
BeginTest("foo");
TestPressKey("/\\ctrl- \\ctrl-p");
QCOMPARE(emulatedCommandBarTextEdit()->text(), QString("foo"));
TestPressKey("\\ctrl-[");
QVERIFY(!emulatedCommandBarCompleter()->popup()->isVisible());
QVERIFY(emulatedCommandBar->isVisible());
QCOMPARE(emulatedCommandBarTextEdit()->text(), QString(""));
TestPressKey("\\enter"); // Dismiss bar.
FinishTest("foo");
// If we select a completion but then dismiss it via ctrl-c or ctrl-[, then we
// should restore the last manually typed word.
BeginTest("fooabc");
TestPressKey("/f\\ctrl- o\\ctrl-p");
QCOMPARE(emulatedCommandBarTextEdit()->text(), QString("fooabc"));
TestPressKey("\\ctrl-c");
QVERIFY(!emulatedCommandBarCompleter()->popup()->isVisible());
QVERIFY(emulatedCommandBar->isVisible());
QCOMPARE(emulatedCommandBarTextEdit()->text(), QString("fo"));
TestPressKey("\\enter"); // Dismiss bar.
FinishTest("fooabc");
// If we select a completion but then dismiss it via ctrl-c or ctrl-[, then we
// should restore the word currently being typed to the last manually typed word.
BeginTest("fooabc");
TestPressKey("/ab\\ctrl- |fo\\ctrl-p");
TestPressKey("\\ctrl-c");
QCOMPARE(emulatedCommandBarTextEdit()->text(), QString("ab|fo"));
TestPressKey("\\enter"); // Dismiss bar.
FinishTest("fooabc");
// Set the completion prefix for the search history completion as soon as it is shown.
clearSearchHistory();
vi_global->searchHistory()->append("foo(bar");
vi_global->searchHistory()->append("xyz");
BeginTest("");
TestPressKey("/f\\ctrl-p");
verifyCommandBarCompletionVisible();
verifyCommandBarCompletionsMatches(QStringList() << "foo(bar");
TestPressKey("\\enter"); // Dismiss bar.
FinishTest("");
// Command Mode (:) tests.
// ":" should summon the command bar, with ":" as the label.
BeginTest("");
TestPressKey(":");
QVERIFY(emulatedCommandBar->isVisible());
QCOMPARE(emulatedCommandTypeIndicator()->text(), QString(":"));
QVERIFY(emulatedCommandTypeIndicator()->isVisible());
QVERIFY(emulatedCommandBarTextEdit());
QVERIFY(emulatedCommandBarTextEdit()->text().isEmpty());
TestPressKey("\\esc");
FinishTest("");
// If we have a selection, it should be encoded as a range in the text edit.
BeginTest("d\nb\na\nc");
TestPressKey("Vjjj:");
QCOMPARE(emulatedCommandBarTextEdit()->text(), QString("'<,'>"));
TestPressKey("\\esc");
FinishTest("d\nb\na\nc");
// If we have a count, it should be encoded as a range in the text edit.
BeginTest("d\nb\na\nc");
TestPressKey("7:");
QCOMPARE(emulatedCommandBarTextEdit()->text(), QString(".,.+6"));
TestPressKey("\\esc");
FinishTest("d\nb\na\nc");
// Don't go doing an incremental search when we press keys!
BeginTest("foo bar xyz");
TestPressKey(":bar");
QCOMPARE(rangesOnFirstLine().size(), rangesInitial.size());
TestPressKey("\\esc");
FinishTest("foo bar xyz");
// Execute the command on Enter.
DoTest("d\nb\na\nc", "Vjjj:sort\\enter", "a\nb\nc\nd");
// Don't crash if we call a non-existent command with a range.
DoTest("123", ":42nonexistentcommand\\enter", "123");
// Bar background should always be normal for command bar.
BeginTest("foo");
TestPressKey("/foo\\enter:");
verifyTextEditBackgroundColour(normalBackgroundColour);
TestPressKey("\\ctrl-c/bar\\enter:");
verifyTextEditBackgroundColour(normalBackgroundColour);
TestPressKey("\\esc");
FinishTest("foo");
const int commandResponseMessageTimeOutMSOverride = QString::fromLatin1(qgetenv("KATE_VIMODE_TEST_COMMANDRESPONSEMESSAGETIMEOUTMS")).toInt();
const long commandResponseMessageTimeOutMS = (commandResponseMessageTimeOutMSOverride > 0) ? commandResponseMessageTimeOutMSOverride : 4000;
{
// If there is any output from the command, show it in a label for a short amount of time
// (make sure the bar type indicator is hidden, here, as it looks messy).
emulatedCommandBar->setCommandResponseMessageTimeout(commandResponseMessageTimeOutMS);
BeginTest("foo bar xyz");
const QDateTime timeJustBeforeCommandExecuted = QDateTime::currentDateTime();
TestPressKey(":commandthatdoesnotexist\\enter");
QVERIFY(emulatedCommandBar->isVisible());
QVERIFY(commandResponseMessageDisplay());
QVERIFY(commandResponseMessageDisplay()->isVisible());
QVERIFY(!emulatedCommandBarTextEdit()->isVisible());
QVERIFY(!emulatedCommandTypeIndicator()->isVisible());
// Be a bit vague about the exact message, due to i18n, etc.
QVERIFY(commandResponseMessageDisplay()->text().contains("commandthatdoesnotexist"));
waitForEmulatedCommandBarToHide(4 * commandResponseMessageTimeOutMS);
QVERIFY(timeJustBeforeCommandExecuted.msecsTo(QDateTime::currentDateTime()) >= commandResponseMessageTimeOutMS - 500); // "- 500" because coarse timers can fire up to 500ms *prematurely*.
QVERIFY(!emulatedCommandBar->isVisible());
// Piggy-back on this test, as the bug we're about to test for would actually make setting
// up the conditions again in a separate test impossible ;)
// When we next summon the bar, the response message should be invisible; the editor visible & editable;
// and the bar type indicator visible again.
TestPressKey("/");
QVERIFY(!commandResponseMessageDisplay()->isVisible());
QVERIFY(emulatedCommandBarTextEdit()->isVisible());
QVERIFY(emulatedCommandBarTextEdit()->isEnabled());
QVERIFY(emulatedCommandBar->isVisible());
TestPressKey("\\esc"); // Dismiss the bar.
FinishTest("foo bar xyz");
}
{
// Show the same message twice in a row.
BeginTest("foo bar xyz");
TestPressKey(":othercommandthatdoesnotexist\\enter");
QDateTime startWaitingForMessageToHide = QDateTime::currentDateTime();
waitForEmulatedCommandBarToHide(4 * commandResponseMessageTimeOutMS);
TestPressKey(":othercommandthatdoesnotexist\\enter");
QVERIFY(commandResponseMessageDisplay()->isVisible());
// Wait for it to disappear again, as a courtesy for the next test.
waitForEmulatedCommandBarToHide(4 * commandResponseMessageTimeOutMS);
}
{
// Emulated command bar should not steal keypresses when it is merely showing the results of an executed command.
BeginTest("foo bar");
TestPressKey(":commandthatdoesnotexist\\enterrX");
Q_ASSERT_X(commandResponseMessageDisplay()->isVisible(), "running test", "Need to increase timeJustBeforeCommandExecuted!");
FinishTest("Xoo bar");
}
{
// Don't send the synthetic "enter" keypress (for making search-as-a-motion work) when we finally hide.
BeginTest("foo bar\nbar");
TestPressKey(":commandthatdoesnotexist\\enter");
Q_ASSERT_X(commandResponseMessageDisplay()->isVisible(), "running test", "Need to increase timeJustBeforeCommandExecuted!");
waitForEmulatedCommandBarToHide(commandResponseMessageTimeOutMS * 4);
TestPressKey("rX");
FinishTest("Xoo bar\nbar");
}
{
// The timeout should be cancelled when we invoke the command bar again.
BeginTest("");
TestPressKey(":commandthatdoesnotexist\\enter");
const QDateTime waitStartedTime = QDateTime::currentDateTime();
TestPressKey(":");
// Wait ample time for the timeout to fire. Do not use waitForEmulatedCommandBarToHide for this!
while(waitStartedTime.msecsTo(QDateTime::currentDateTime()) < commandResponseMessageTimeOutMS * 2)
{
QApplication::processEvents();
}
QVERIFY(emulatedCommandBar->isVisible());
TestPressKey("\\esc"); // Dismiss the bar.
FinishTest("");
}
{
// The timeout should not cause kate_view to regain focus if we have manually taken it away.
qDebug()<< " NOTE: this test is weirdly fragile, so if it starts failing, comment it out and e-mail me: it may well be more trouble that it's worth.";
BeginTest("");
TestPressKey(":commandthatdoesnotexist\\enter");
while (QApplication::hasPendingEvents())
{
// Wait for any focus changes to take effect.
QApplication::processEvents();
}
const QDateTime waitStartedTime = QDateTime::currentDateTime();
QLineEdit *dummyToFocus = new QLineEdit(QString("Sausage"), mainWindow);
// Take focus away from kate_view by giving it to dummyToFocus.
QApplication::setActiveWindow(mainWindow);
kate_view->setFocus();
mainWindowLayout->addWidget(dummyToFocus);
dummyToFocus->show();
dummyToFocus->setEnabled(true);
dummyToFocus->setFocus();
// Allow dummyToFocus to receive focus.
while(!dummyToFocus->hasFocus())
{
QApplication::processEvents();
}
QVERIFY(dummyToFocus->hasFocus());
// Wait ample time for the timeout to fire. Do not use waitForEmulatedCommandBarToHide for this -
// the bar never actually hides in this instance, and I think it would take some deep changes in
// Kate to make it do so (the KateCommandLineBar as the same issue).
while(waitStartedTime.msecsTo(QDateTime::currentDateTime()) < commandResponseMessageTimeOutMS * 2)
{
QApplication::processEvents();
}
QVERIFY(dummyToFocus->hasFocus());
QVERIFY(emulatedCommandBar->isVisible());
mainWindowLayout->removeWidget(dummyToFocus);
// Restore focus to the kate_view.
kate_view->setFocus();
while(!kate_view->hasFocus())
{
QApplication::processEvents();
}
// *Now* wait for the command bar to disappear - giving kate_view focus should trigger it.
waitForEmulatedCommandBarToHide(commandResponseMessageTimeOutMS * 4);
FinishTest("");
}
{
// No completion should be shown when the bar is first shown: this gives us an opportunity
// to invoke command history via ctrl-p and ctrl-n.
BeginTest("");
TestPressKey(":");
QVERIFY(!emulatedCommandBarCompleter()->popup()->isVisible());
TestPressKey("\\ctrl-c"); // Dismiss bar
FinishTest("");
}
{
// Should be able to switch to completion from document, even when we have a completion from commands.
BeginTest("soggy1 soggy2");
TestPressKey(":so");
verifyCommandBarCompletionContains(QStringList() << "sort");
TestPressKey("\\ctrl- ");
verifyCommandBarCompletionsMatches(QStringList() << "soggy1" << "soggy2");
TestPressKey("\\ctrl-c"); // Dismiss completer
TestPressKey("\\ctrl-c"); // Dismiss bar
FinishTest("soggy1 soggy2");
}
{
// If we dismiss the command completion then change the text, it should summon the completion
// again.
BeginTest("");
TestPressKey(":so");
TestPressKey("\\ctrl-c"); // Dismiss completer
TestPressKey("r");
verifyCommandBarCompletionVisible();
verifyCommandBarCompletionContains(QStringList() << "sort");
TestPressKey("\\ctrl-c"); // Dismiss completer
TestPressKey("\\ctrl-c"); // Dismiss bar
FinishTest("");
}
{
// Completion should be dismissed when we are showing command response text.
BeginTest("");
TestPressKey(":set-au\\enter");
QVERIFY(commandResponseMessageDisplay()->isVisible());
QVERIFY(!emulatedCommandBarCompleter()->popup()->isVisible());
waitForEmulatedCommandBarToHide(commandResponseMessageTimeOutMS * 4);
FinishTest("");
}
// If we abort completion via ctrl-c or ctrl-[, we should revert the current word to the last
// manually entered word.
BeginTest("");
TestPressKey(":se\\ctrl-p");
verifyCommandBarCompletionVisible();
QVERIFY(emulatedCommandBarTextEdit()->text() != "se");
TestPressKey("\\ctrl-c"); // Dismiss completer
QCOMPARE(emulatedCommandBarTextEdit()->text(), QString("se"));
TestPressKey("\\ctrl-c"); // Dismiss bar
FinishTest("");
// In practice, it's annoying if, as we enter ":s/se", completions pop up after the "se":
// for now, only summon completion if we are on the first word in the text.
BeginTest("");
TestPressKey(":s/se");
QVERIFY(!emulatedCommandBarCompleter()->popup()->isVisible());
TestPressKey("\\ctrl-c"); // Dismiss bar
FinishTest("");
BeginTest("");
TestPressKey(":.,.+7s/se");
QVERIFY(!emulatedCommandBarCompleter()->popup()->isVisible());
TestPressKey("\\ctrl-c"); // Dismiss bar
FinishTest("");
// Don't blank the text if we activate command history completion with no command history.
BeginTest("");
clearCommandHistory();
TestPressKey(":s/se\\ctrl-p");
QVERIFY(!emulatedCommandBarCompleter()->popup()->isVisible());
QCOMPARE(emulatedCommandBarTextEdit()->text(), QString("s/se"));
TestPressKey("\\ctrl-c"); // Dismiss bar
FinishTest("");
// On completion, only update the command in front of the cursor.
BeginTest("");
clearCommandHistory();
TestPressKey(":.,.+6s/se\\left\\left\\leftet-auto-in\\ctrl-p");
QCOMPARE(emulatedCommandBarTextEdit()->text(), QString(".,.+6set-auto-indent/se"));
TestPressKey("\\ctrl-c"); // Dismiss completer.
TestPressKey("\\ctrl-c"); // Dismiss bar
FinishTest("");
// On completion, place the cursor after the new command.
BeginTest("");
clearCommandHistory();
TestPressKey(":.,.+6s/fo\\left\\left\\leftet-auto-in\\ctrl-pX");
QCOMPARE(emulatedCommandBarTextEdit()->text(), QString(".,.+6set-auto-indentX/fo"));
TestPressKey("\\ctrl-c"); // Dismiss completer.
TestPressKey("\\ctrl-c"); // Dismiss bar
FinishTest("");
// "The current word", for Commands, can contain "-".
BeginTest("");
TestPressKey(":set-\\ctrl-p");
verifyCommandBarCompletionVisible();
QVERIFY(emulatedCommandBarTextEdit()->text() != "set-");
QVERIFY(emulatedCommandBarCompleter()->currentCompletion().startsWith("set-"));
QCOMPARE(emulatedCommandBarTextEdit()->text(), emulatedCommandBarCompleter()->currentCompletion());
TestPressKey("\\ctrl-c"); // Dismiss completion.
TestPressKey("\\ctrl-c"); // Dismiss bar.
FinishTest("");
{
// Don't switch from word-from-document to command-completion just because we press a key, though!
BeginTest("soggy1 soggy2");
TestPressKey(":\\ctrl- s");
TestPressKey("o");
verifyCommandBarCompletionVisible();
verifyCommandBarCompletionsMatches(QStringList() << "soggy1" << "soggy2");
TestPressKey("\\ctrl-c"); // Dismiss completer
TestPressKey("\\ctrl-c"); // Dismiss bar
FinishTest("soggy1 soggy2");
}
{
// If we're in a place where there is no command completion allowed, don't go hiding the word
// completion as we type.
BeginTest("soggy1 soggy2");
TestPressKey(":s/s\\ctrl- o");
verifyCommandBarCompletionVisible();
verifyCommandBarCompletionsMatches(QStringList() << "soggy1" << "soggy2");
TestPressKey("\\ctrl-c"); // Dismiss completer
TestPressKey("\\ctrl-c"); // Dismiss bar
FinishTest("soggy1 soggy2");
}
{
// Don't show command completion before we start typing a command: we want ctrl-p/n
// to go through command history instead (we'll test for that second part later).
BeginTest("soggy1 soggy2");
TestPressKey(":");
QVERIFY(!emulatedCommandBarCompleter()->popup()->isVisible());
TestPressKey("\\ctrl-cvl:");
QVERIFY(!emulatedCommandBarCompleter()->popup()->isVisible());
TestPressKey("\\ctrl-c"); // Dismiss bar
FinishTest("soggy1 soggy2");
}
{
// Aborting ":" should leave us in normal mode with no selection.
BeginTest("foo bar");
TestPressKey("vw:\\ctrl-[");
QVERIFY(kate_view->selectionText().isEmpty());
TestPressKey("wdiw");
BeginTest("foo ");
}
// Command history tests.
clearCommandHistory();
QVERIFY(commandHistory().isEmpty());
vi_global->commandHistory()->append("foo");
vi_global->commandHistory()->append("bar");
QCOMPARE(commandHistory(), QStringList() << "foo" << "bar");
clearCommandHistory();
QVERIFY(commandHistory().isEmpty());
// If we add something to the history, remove any earliest occurrences (this is what Vim appears to do)
// and append to the end.
clearCommandHistory();
vi_global->commandHistory()->append("bar");
vi_global->commandHistory()->append("xyz");
vi_global->commandHistory()->append("foo");
vi_global->commandHistory()->append("xyz");
QCOMPARE(commandHistory(), QStringList() << "bar" << "foo" << "xyz");
// Push out older entries if we have too many command items in the history.
clearCommandHistory();
for (int i = 1; i <= HISTORY_SIZE_LIMIT; i++)
{
vi_global->commandHistory()->append(QString("commandhistoryitem %1").arg(i));
}
QCOMPARE(commandHistory().size(), HISTORY_SIZE_LIMIT);
QCOMPARE(commandHistory().first(), QString("commandhistoryitem 1"));
QCOMPARE(commandHistory().last(), QString("commandhistoryitem 100"));
vi_global->commandHistory()->append(QString("commandhistoryitem %1").arg(HISTORY_SIZE_LIMIT + 1));
QCOMPARE(commandHistory().size(), HISTORY_SIZE_LIMIT);
QCOMPARE(commandHistory().first(), QString("commandhistoryitem 2"));
QCOMPARE(commandHistory().last(), QString("commandhistoryitem %1").arg(HISTORY_SIZE_LIMIT + 1));
// Don't add empty commands to the history.
clearCommandHistory();
DoTest("foo bar", ":\\enter", "foo bar");
QVERIFY(commandHistory().isEmpty());
clearCommandHistory();
BeginTest("");
TestPressKey(":sort\\enter");
QCOMPARE(commandHistory(), QStringList() << "sort");
TestPressKey(":yank\\enter");
QCOMPARE(commandHistory(), QStringList() << "sort" << "yank");
// Add to history immediately: don't wait for the command response display to timeout.
TestPressKey(":commandthatdoesnotexist\\enter");
QCOMPARE(commandHistory(), QStringList() << "sort" << "yank" << "commandthatdoesnotexist");
// Vim adds aborted commands to the history too, oddly.
TestPressKey(":abortedcommand\\ctrl-c");
QCOMPARE(commandHistory(), QStringList() << "sort" << "yank" << "commandthatdoesnotexist" << "abortedcommand");
// Only add for commands, not searches!
TestPressKey("/donotaddme\\enter?donotaddmeeither\\enter/donotaddme\\ctrl-c?donotaddmeeither\\ctrl-c");
QCOMPARE(commandHistory(), QStringList() << "sort" << "yank" << "commandthatdoesnotexist" << "abortedcommand");
FinishTest("");
// Commands should not be added to the search history!
clearCommandHistory();
clearSearchHistory();
BeginTest("");
TestPressKey(":sort\\enter");
QVERIFY(searchHistory().isEmpty());
FinishTest("");
// With an empty command bar, ctrl-p / ctrl-n should go through history.
clearCommandHistory();
vi_global->commandHistory()->append("command1");
vi_global->commandHistory()->append("command2");
BeginTest("");
TestPressKey(":\\ctrl-p");
verifyCommandBarCompletionVisible();
QCOMPARE(emulatedCommandBarCompleter()->currentCompletion(), QString("command2"));
QCOMPARE(emulatedCommandBarTextEdit()->text(), emulatedCommandBarCompleter()->currentCompletion());
TestPressKey("\\ctrl-c"); // Dismiss completer
TestPressKey("\\ctrl-c"); // Dismiss bar
FinishTest("");
clearCommandHistory();
vi_global->commandHistory()->append("command1");
vi_global->commandHistory()->append("command2");
BeginTest("");
TestPressKey(":\\ctrl-n");
verifyCommandBarCompletionVisible();
QCOMPARE(emulatedCommandBarCompleter()->currentCompletion(), QString("command1"));
QCOMPARE(emulatedCommandBarTextEdit()->text(), emulatedCommandBarCompleter()->currentCompletion());
TestPressKey("\\ctrl-c"); // Dismiss completer
TestPressKey("\\ctrl-c"); // Dismiss bar
FinishTest("");
// If we're at a place where command completions are not allowed, ctrl-p/n should go through history.
clearCommandHistory();
vi_global->commandHistory()->append("s/command1");
vi_global->commandHistory()->append("s/command2");
BeginTest("");
TestPressKey(":s/\\ctrl-p");
verifyCommandBarCompletionVisible();
QCOMPARE(emulatedCommandBarCompleter()->currentCompletion(), QString("s/command2"));
QCOMPARE(emulatedCommandBarTextEdit()->text(), emulatedCommandBarCompleter()->currentCompletion());
TestPressKey("\\ctrl-c"); // Dismiss completer
TestPressKey("\\ctrl-c"); // Dismiss bar
FinishTest("");
clearCommandHistory();
vi_global->commandHistory()->append("s/command1");
vi_global->commandHistory()->append("s/command2");
BeginTest("");
TestPressKey(":s/\\ctrl-n");
verifyCommandBarCompletionVisible();
QCOMPARE(emulatedCommandBarCompleter()->currentCompletion(), QString("s/command1"));
QCOMPARE(emulatedCommandBarTextEdit()->text(), emulatedCommandBarCompleter()->currentCompletion());
TestPressKey("\\ctrl-c"); // Dismiss completer
TestPressKey("\\ctrl-c"); // Dismiss bar
FinishTest("");
// Cancelling word-from-document completion should revert the whole text to what it was before.
BeginTest("sausage bacon");
TestPressKey(":s/b\\ctrl- \\ctrl-p");
QCOMPARE(emulatedCommandBarTextEdit()->text(), QString("s/bacon"));
verifyCommandBarCompletionVisible();
TestPressKey("\\ctrl-c"); // Dismiss completer
QCOMPARE(emulatedCommandBarTextEdit()->text(), QString("s/b"));
TestPressKey("\\ctrl-c"); // Dismiss bar
FinishTest("sausage bacon");
// "Replace" history tests.
clearReplaceHistory();
QVERIFY(replaceHistory().isEmpty());
vi_global->replaceHistory()->append("foo");
vi_global->replaceHistory()->append("bar");
QCOMPARE(replaceHistory(), QStringList() << "foo" << "bar");
clearReplaceHistory();
QVERIFY(replaceHistory().isEmpty());
// If we add something to the history, remove any earliest occurrences (this is what Vim appears to do)
// and append to the end.
clearReplaceHistory();
vi_global->replaceHistory()->append("bar");
vi_global->replaceHistory()->append("xyz");
vi_global->replaceHistory()->append("foo");
vi_global->replaceHistory()->append("xyz");
QCOMPARE(replaceHistory(), QStringList() << "bar" << "foo" << "xyz");
// Push out older entries if we have too many replace items in the history.
clearReplaceHistory();
for (int i = 1; i <= HISTORY_SIZE_LIMIT; i++)
{
vi_global->replaceHistory()->append(QString("replacehistoryitem %1").arg(i));
}
QCOMPARE(replaceHistory().size(), HISTORY_SIZE_LIMIT);
QCOMPARE(replaceHistory().first(), QString("replacehistoryitem 1"));
QCOMPARE(replaceHistory().last(), QString("replacehistoryitem 100"));
vi_global->replaceHistory()->append(QString("replacehistoryitem %1").arg(HISTORY_SIZE_LIMIT + 1));
QCOMPARE(replaceHistory().size(), HISTORY_SIZE_LIMIT);
QCOMPARE(replaceHistory().first(), QString("replacehistoryitem 2"));
QCOMPARE(replaceHistory().last(), QString("replacehistoryitem %1").arg(HISTORY_SIZE_LIMIT + 1));
// Don't add empty replaces to the history.
clearReplaceHistory();
vi_global->replaceHistory()->append("");
QVERIFY(replaceHistory().isEmpty());
// Some misc SedReplace tests.
DoTest("x\\/y", ":s/\\\\//replace/g\\enter", "x\\replacey");
DoTest("x\\/y", ":s/\\\\\\\\\\\\//replace/g\\enter", "xreplacey");
DoTest("x\\/y", ":s:/:replace:g\\enter", "x\\replacey");
DoTest("foo\nbar\nxyz", ":%delete\\enter", "");
DoTest("foo\nbar\nxyz\nbaz", "jVj:delete\\enter", "foo\nbaz");
DoTest("foo\nbar\nxyz\nbaz", "j2:delete\\enter", "foo\nbaz");
// On ctrl-d, delete the "search" term in a s/search/replace/xx
BeginTest("foo bar");
TestPressKey(":s/x\\\\\\\\\\\\/yz/rep\\\\\\\\\\\\/lace/g\\ctrl-d");
QCOMPARE(emulatedCommandBarTextEdit()->text(), QString("s//rep\\\\\\/lace/g"));
TestPressKey("\\ctrl-c"); // Dismiss bar.
FinishTest("foo bar");
// Move cursor to position of deleted search term.
BeginTest("foo bar");
TestPressKey(":s/x\\\\\\\\\\\\/yz/rep\\\\\\\\\\\\/lace/g\\ctrl-dX");
QCOMPARE(emulatedCommandBarTextEdit()->text(), QString("s/X/rep\\\\\\/lace/g"));
TestPressKey("\\ctrl-c"); // Dismiss bar.
FinishTest("foo bar");
// Do nothing on ctrl-d in search mode.
BeginTest("foo bar");
TestPressKey("/s/search/replace/g\\ctrl-d");
QCOMPARE(emulatedCommandBarTextEdit()->text(), QString("s/search/replace/g"));
TestPressKey("\\ctrl-c?s/searchbackwards/replace/g\\ctrl-d");
QCOMPARE(emulatedCommandBarTextEdit()->text(), QString("s/searchbackwards/replace/g"));
TestPressKey("\\ctrl-c"); // Dismiss bar.
FinishTest("foo bar");
// On ctrl-f, delete "replace" term in a s/search/replace/xx
BeginTest("foo bar");
TestPressKey(":s/a\\\\\\\\\\\\/bc/rep\\\\\\\\\\\\/lace/g\\ctrl-f");
QCOMPARE(emulatedCommandBarTextEdit()->text(), QString("s/a\\\\\\/bc//g"));
TestPressKey("\\ctrl-c"); // Dismiss bar.
FinishTest("foo bar");
// Move cursor to position of deleted replace term.
BeginTest("foo bar");
TestPressKey(":s:a/bc:replace:g\\ctrl-fX");
QCOMPARE(emulatedCommandBarTextEdit()->text(), QString("s:a/bc:X:g"));
TestPressKey("\\ctrl-c"); // Dismiss bar.
FinishTest("foo bar");
// Do nothing on ctrl-d in search mode.
BeginTest("foo bar");
TestPressKey("/s/search/replace/g\\ctrl-f");
QCOMPARE(emulatedCommandBarTextEdit()->text(), QString("s/search/replace/g"));
TestPressKey("\\ctrl-c?s/searchbackwards/replace/g\\ctrl-f");
QCOMPARE(emulatedCommandBarTextEdit()->text(), QString("s/searchbackwards/replace/g"));
TestPressKey("\\ctrl-c"); // Dismiss bar.
FinishTest("foo bar");
// Do nothing on ctrl-d / ctrl-f if the current expression is not a sed expression.
BeginTest("foo bar");
TestPressKey(":s/notasedreplaceexpression::gi\\ctrl-f\\ctrl-dX");
QCOMPARE(emulatedCommandBarTextEdit()->text(), QString("s/notasedreplaceexpression::giX"));
TestPressKey("\\ctrl-c"); // Dismiss bar.
FinishTest("foo bar");
// Need to convert Vim-style regex's to Qt one's in Sed Replace.
DoTest("foo xbacba(boo)|[y", ":s/x[abc]\\\\+(boo)|[y/boo/g\\enter", "foo boo");
DoTest("foo xbacba(boo)|[y\nfoo xbacba(boo)|[y", "Vj:s/x[abc]\\\\+(boo)|[y/boo/g\\enter", "foo boo\nfoo boo");
// Just convert the search term, please :)
DoTest("foo xbacba(boo)|[y", ":s/x[abc]\\\\+(boo)|[y/boo()/g\\enter", "foo boo()");
// With an empty search expression, ctrl-d should still position the cursor correctly.
BeginTest("foo bar");
TestPressKey(":s//replace/g\\ctrl-dX");
QCOMPARE(emulatedCommandBarTextEdit()->text(), QString("s/X/replace/g"));
TestPressKey("\\ctrl-c"); // Dismiss bar.
TestPressKey(":s::replace:g\\ctrl-dX");
QCOMPARE(emulatedCommandBarTextEdit()->text(), QString("s:X:replace:g"));
TestPressKey("\\ctrl-c"); // Dismiss bar.
FinishTest("foo bar");
// With an empty replace expression, ctrl-f should still position the cursor correctly.
BeginTest("foo bar");
TestPressKey(":s/sear\\\\/ch//g\\ctrl-fX");
QCOMPARE(emulatedCommandBarTextEdit()->text(), QString("s/sear\\/ch/X/g"));
TestPressKey("\\ctrl-c"); // Dismiss bar.
TestPressKey(":s:sear\\\\:ch::g\\ctrl-fX");
QCOMPARE(emulatedCommandBarTextEdit()->text(), QString("s:sear\\:ch:X:g"));
TestPressKey("\\ctrl-c"); // Dismiss bar.
FinishTest("foo bar");
// With both empty search *and* replace expressions, ctrl-f should still position the cursor correctly.
BeginTest("foo bar");
TestPressKey(":s///g\\ctrl-fX");
QCOMPARE(emulatedCommandBarTextEdit()->text(), QString("s//X/g"));
TestPressKey("\\ctrl-c"); // Dismiss bar.
TestPressKey(":s:::g\\ctrl-fX");
QCOMPARE(emulatedCommandBarTextEdit()->text(), QString("s::X:g"));
TestPressKey("\\ctrl-c"); // Dismiss bar.
FinishTest("foo bar");
// Should be able to undo ctrl-f or ctrl-d.
BeginTest("foo bar");
TestPressKey(":s/find/replace/g\\ctrl-d");
emulatedCommandBarTextEdit()->undo();
QCOMPARE(emulatedCommandBarTextEdit()->text(), QString("s/find/replace/g"));
TestPressKey("\\ctrl-f");
emulatedCommandBarTextEdit()->undo();
QCOMPARE(emulatedCommandBarTextEdit()->text(), QString("s/find/replace/g"));
TestPressKey("\\ctrl-c"); // Dismiss bar.
FinishTest("foo bar");
// ctrl-f / ctrl-d should cleanly finish sed find/ replace history completion.
clearReplaceHistory();
clearSearchHistory();
vi_global->searchHistory()->append("searchxyz");
vi_global->replaceHistory()->append("replacexyz");
TestPressKey(":s///g\\ctrl-d\\ctrl-p");
QVERIFY(emulatedCommandBarCompleter()->popup()->isVisible());
TestPressKey("\\ctrl-f");
QCOMPARE(emulatedCommandBarTextEdit()->text(), QString("s/searchxyz//g"));
QVERIFY(!emulatedCommandBarCompleter()->popup()->isVisible());
TestPressKey("\\ctrl-p");
QVERIFY(emulatedCommandBarCompleter()->popup()->isVisible());
TestPressKey("\\ctrl-d");
QCOMPARE(emulatedCommandBarTextEdit()->text(), QString("s//replacexyz/g"));
QVERIFY(!emulatedCommandBarCompleter()->popup()->isVisible());
TestPressKey("\\ctrl-c"); // Dismiss bar.
FinishTest("foo bar");
// Don't hang if we execute a sed replace with empty search term.
DoTest("foo bar", ":s//replace/g\\enter", "foo bar");
// ctrl-f & ctrl-d should work even when there is a range expression at the beginning of the sed replace.
BeginTest("foo bar");
TestPressKey(":'<,'>s/search/replace/g\\ctrl-d");
QCOMPARE(emulatedCommandBarTextEdit()->text(), QString("'<,'>s//replace/g"));
TestPressKey("\\ctrl-c:.,.+6s/search/replace/g\\ctrl-f");
QCOMPARE(emulatedCommandBarTextEdit()->text(), QString(".,.+6s/search//g"));
TestPressKey("\\ctrl-c:%s/search/replace/g\\ctrl-f");
QCOMPARE(emulatedCommandBarTextEdit()->text(), QString("%s/search//g"));
// Place the cursor in the right place even when there is a range expression.
TestPressKey("\\ctrl-c:.,.+6s/search/replace/g\\ctrl-fX");
QCOMPARE(emulatedCommandBarTextEdit()->text(), QString(".,.+6s/search/X/g"));
TestPressKey("\\ctrl-c:%s/search/replace/g\\ctrl-fX");
QCOMPARE(emulatedCommandBarTextEdit()->text(), QString("%s/search/X/g"));
TestPressKey("\\ctrl-c"); // Dismiss bar.
FinishTest("foo bar");
// Don't crash on ctrl-f/d if we have an empty command.
DoTest("", ":\\ctrl-f\\ctrl-d\\ctrl-c", "");
// Parser regression test: Don't crash on ctrl-f/d with ".,.+".
DoTest("", ":.,.+\\ctrl-f\\ctrl-d\\ctrl-c", "");
// Command-completion should be invoked on the command being typed even when preceded by a range expression.
BeginTest("");
TestPressKey(":0,'>so");
verifyCommandBarCompletionVisible();
TestPressKey("\\ctrl-c"); // Dismiss completer
TestPressKey("\\ctrl-c"); // Dismiss bar.
FinishTest("");
// Command-completion should ignore the range expression.
BeginTest("");
TestPressKey(":.,.+6so");
verifyCommandBarCompletionVisible();
TestPressKey("\\ctrl-c"); // Dismiss completer
TestPressKey("\\ctrl-c"); // Dismiss bar.
FinishTest("");
// A sed-replace should immediately add the search term to the search history.
clearSearchHistory();
BeginTest("");
TestPressKey(":s/search/replace/g\\enter");
QCOMPARE(searchHistory(), QStringList() << "search");
FinishTest("");
// An aborted sed-replace should not add the search term to the search history.
clearSearchHistory();
BeginTest("");
TestPressKey(":s/search/replace/g\\ctrl-c");
QCOMPARE(searchHistory(), QStringList());
FinishTest("");
// A non-sed-replace should leave the search history unchanged.
clearSearchHistory();
BeginTest("");
TestPressKey(":s,search/replace/g\\enter");
QCOMPARE(searchHistory(), QStringList());
FinishTest("");
// A sed-replace should immediately add the replace term to the replace history.
clearReplaceHistory();
BeginTest("");
TestPressKey(":s/search/replace/g\\enter");
QCOMPARE(replaceHistory(), QStringList() << "replace");
clearReplaceHistory();
TestPressKey(":'<,'>s/search/replace1/g\\enter");
QCOMPARE(replaceHistory(), QStringList() << "replace1");
FinishTest("");
// An aborted sed-replace should not add the replace term to the replace history.
clearReplaceHistory();
BeginTest("");
TestPressKey(":s/search/replace/g\\ctrl-c");
QCOMPARE(replaceHistory(), QStringList());
FinishTest("");
// A non-sed-replace should leave the replace history unchanged.
clearReplaceHistory();
BeginTest("");
TestPressKey(":s,search/replace/g\\enter");
QCOMPARE(replaceHistory(), QStringList());
FinishTest("");
// Misc tests for sed replace. These are for the *generic* Kate sed replace; they should all
// use EmulatedCommandBarTests' built-in command execution stuff (\\:\\\) rather than
// invoking a EmulatedCommandBar and potentially doing some Vim-specific transforms to
// the command.
DoTest("foo foo foo", "\\:s/foo/bar/\\", "bar foo foo");
DoTest("foo foo xyz foo", "\\:s/foo/bar/g\\", "bar bar xyz bar");
DoTest("foofooxyzfoo", "\\:s/foo/bar/g\\", "barbarxyzbar");
DoTest("foofooxyzfoo", "\\:s/foo/b/g\\", "bbxyzb");
DoTest("ffxyzf", "\\:s/f/b/g\\", "bbxyzb");
DoTest("ffxyzf", "\\:s/f/bar/g\\", "barbarxyzbar");
DoTest("foo Foo fOO FOO foo", "\\:s/foo/bar/\\", "bar Foo fOO FOO foo");
DoTest("Foo foo fOO FOO foo", "\\:s/foo/bar/\\", "Foo bar fOO FOO foo");
DoTest("Foo foo fOO FOO foo", "\\:s/foo/bar/g\\", "Foo bar fOO FOO bar");
DoTest("foo Foo fOO FOO foo", "\\:s/foo/bar/i\\", "bar Foo fOO FOO foo");
DoTest("Foo foo fOO FOO foo", "\\:s/foo/bar/i\\", "bar foo fOO FOO foo");
DoTest("Foo foo fOO FOO foo", "\\:s/foo/bar/gi\\", "bar bar bar bar bar");
DoTest("Foo foo fOO FOO foo", "\\:s/foo/bar/ig\\", "bar bar bar bar bar");
// There are some oddities to do with how EmulatedCommandBarTest's "execute command directly" stuff works with selected ranges:
// basically, we need to do our selection in Visual mode, then exit back to Normal mode before running the
//command.
DoTest("foo foo\nbar foo foo\nxyz foo foo\nfoo bar foo", "jVj\\esc\\:'<,'>s/foo/bar/\\", "foo foo\nbar bar foo\nxyz bar foo\nfoo bar foo");
DoTest("foo foo\nbar foo foo\nxyz foo foo\nfoo bar foo", "jVj\\esc\\:'<,'>s/foo/bar/g\\", "foo foo\nbar bar bar\nxyz bar bar\nfoo bar foo");
DoTest("Foo foo fOO FOO foo", "\\:s/foo/barfoo/g\\", "Foo barfoo fOO FOO barfoo");
DoTest("Foo foo fOO FOO foo", "\\:s/foo/foobar/g\\", "Foo foobar fOO FOO foobar");
DoTest("axyzb", "\\:s/a(.*)b/d\\\\1f/\\", "dxyzf");
DoTest("ayxzzyxzfddeefdb", "\\:s/a([xyz]+)([def]+)b/<\\\\1|\\\\2>/\\", "");
DoTest("foo", "\\:s/.*//g\\", "");
DoTest("foo", "\\:s/.*/f/g\\", "f");
DoTest("foo/bar", "\\:s/foo\\\\/bar/123\\\\/xyz/g\\", "123/xyz");
DoTest("foo:bar", "\\:s:foo\\\\:bar:123\\\\:xyz:g\\", "123:xyz");
const bool oldReplaceTabsDyn = kate_document->config()->replaceTabsDyn();
kate_document->config()->setReplaceTabsDyn(false);
DoTest("foo\tbar", "\\:s/foo\\\\tbar/replace/g\\", "replace");
DoTest("foo\tbar", "\\:s/foo\\\\tbar/rep\\\\tlace/g\\", "rep\tlace");
kate_document->config()->setReplaceTabsDyn(oldReplaceTabsDyn);
DoTest("foo", "\\:s/foo/replaceline1\\\\nreplaceline2/g\\", "replaceline1\nreplaceline2");
DoTest("foofoo", "\\:s/foo/replaceline1\\\\nreplaceline2/g\\", "replaceline1\nreplaceline2replaceline1\nreplaceline2");
DoTest("foofoo\nfoo", "\\:s/foo/replaceline1\\\\nreplaceline2/g\\", "replaceline1\nreplaceline2replaceline1\nreplaceline2\nfoo");
DoTest("fooafoob\nfooc\nfood", "Vj\\esc\\:'<,'>s/foo/replaceline1\\\\nreplaceline2/g\\", "replaceline1\nreplaceline2areplaceline1\nreplaceline2b\nreplaceline1\nreplaceline2c\nfood");
DoTest("fooafoob\nfooc\nfood", "Vj\\esc\\:'<,'>s/foo/replaceline1\\\\nreplaceline2/\\", "replaceline1\nreplaceline2afoob\nreplaceline1\nreplaceline2c\nfood");
DoTest("fooafoob\nfooc\nfood", "Vj\\esc\\:'<,'>s/foo/replaceline1\\\\nreplaceline2\\\\nreplaceline3/g\\", "replaceline1\nreplaceline2\nreplaceline3areplaceline1\nreplaceline2\nreplaceline3b\nreplaceline1\nreplaceline2\nreplaceline3c\nfood");
DoTest("foofoo", "\\:s/foo/replace\\\\nfoo/g\\", "replace\nfooreplace\nfoo");
DoTest("foofoo", "\\:s/foo/replacefoo\\\\nfoo/g\\", "replacefoo\nfooreplacefoo\nfoo");
DoTest("foofoo", "\\:s/foo/replacefoo\\\\n/g\\", "replacefoo\nreplacefoo\n");
DoTest("ff", "\\:s/f/f\\\\nf/g\\", "f\nff\nf");
DoTest("ff", "\\:s/f/f\\\\n/g\\", "f\nf\n");
DoTest("foo\nbar", "\\:s/foo\\\\n//g\\", "bar");
DoTest("foo\n\n\nbar", "\\:s/foo(\\\\n)*bar//g\\", "");
DoTest("foo\n\n\nbar", "\\:s/foo(\\\\n*)bar/123\\\\1456/g\\", "123\n\n\n456");
DoTest("xAbCy", "\\:s/x(.)(.)(.)y/\\\\L\\\\1\\\\U\\\\2\\\\3/g\\", "aBC");
DoTest("foo", "\\:s/foo/\\\\a/g\\", "\x07");
// End "generic" (i.e. not involving any Vi mode tricks/ transformations) sed replace tests: the remaining
// ones should go via the EmulatedCommandBar.
BeginTest("foo foo\nxyz\nfoo");
TestPressKey(":%s/foo/bar/g\\enter");
verifyShowsNumberOfReplacementsAcrossNumberOfLines(3, 2);
FinishTest("bar bar\nxyz\nbar");
// ctrl-p on the first character of the search term in a sed-replace should
// invoke search history completion.
clearSearchHistory();
vi_global->searchHistory()->append("search");
BeginTest("");
TestPressKey(":s/search/replace/g\\ctrl-b\\right\\right\\ctrl-p");
verifyCommandBarCompletionVisible();
TestPressKey("\\ctrl-c"); // Dismiss completer
TestPressKey("\\ctrl-c"); // Dismiss bar.
TestPressKey(":'<,'>s/search/replace/g\\ctrl-b\\right\\right\\right\\right\\right\\right\\right\\ctrl-p");
verifyCommandBarCompletionVisible();
TestPressKey("\\ctrl-c"); // Dismiss completer
TestPressKey("\\ctrl-c"); // Dismiss bar.
FinishTest("");
// ctrl-p on the last character of the search term in a sed-replace should
// invoke search history completion.
clearSearchHistory();
vi_global->searchHistory()->append("xyz");
BeginTest("");
TestPressKey(":s/xyz/replace/g\\ctrl-b\\right\\right\\right\\right\\ctrl-p");
verifyCommandBarCompletionVisible();
TestPressKey("\\ctrl-c"); // Dismiss completer
TestPressKey("\\ctrl-c"); // Dismiss bar.
QVERIFY(!emulatedCommandBar->isVisible());
TestPressKey(":'<,'>s/xyz/replace/g\\ctrl-b\\right\\right\\right\\right\\right\\right\\right\\right\\right\\ctrl-p");
verifyCommandBarCompletionVisible();
TestPressKey("\\ctrl-c"); // Dismiss completer
TestPressKey("\\ctrl-c"); // Dismiss bar.
FinishTest("");
// ctrl-p on some arbitrary character of the search term in a sed-replace should
// invoke search history completion.
clearSearchHistory();
vi_global->searchHistory()->append("xyzaaaaaa");
BeginTest("");
TestPressKey(":s/xyzaaaaaa/replace/g\\ctrl-b\\right\\right\\right\\right\\right\\right\\right\\ctrl-p");
verifyCommandBarCompletionVisible();
TestPressKey("\\ctrl-c"); // Dismiss completer
TestPressKey("\\ctrl-c"); // Dismiss bar.
TestPressKey(":'<,'>s/xyzaaaaaa/replace/g\\ctrl-b\\right\\right\\right\\right\\right\\right\\right\\right\\right\\right\\right\\right\\ctrl-p");
verifyCommandBarCompletionVisible();
TestPressKey("\\ctrl-c"); // Dismiss completer
TestPressKey("\\ctrl-c"); // Dismiss bar.
FinishTest("");
// ctrl-p on some character *after" the search term should
// *not* invoke search history completion.
// Note: in s/xyz/replace/g, the "/" after the "z" is counted as part of the find term;
// this allows us to do xyz