diff --git a/autotests/src/variable_test.cpp b/autotests/src/variable_test.cpp index 1092cfd6..8a8f4d1a 100644 --- a/autotests/src/variable_test.cpp +++ b/autotests/src/variable_test.cpp @@ -1,164 +1,292 @@ /* This file is part of the KDE project * * Copyright 2019 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 "variable_test.h" #include "moc_variable_test.cpp" #include #include #include #include #include +#include using namespace KTextEditor; QTEST_MAIN(VariableTest) VariableTest::VariableTest() : QObject() { KTextEditor::EditorPrivate::enableUnitTestMode(); } VariableTest::~VariableTest() { } void VariableTest::testReturnValues() { auto editor = KTextEditor::Editor::instance(); const QString name = QStringLiteral("Document:"); auto func = [](const QStringView&, KTextEditor::View*) { return QString(); }; // exact matches QVERIFY(!editor->unregisterVariableMatch(name)); QVERIFY(editor->registerVariableMatch(name, "Document Text", func)); QVERIFY(!editor->registerVariableMatch(name, "Document Text", func)); QVERIFY(editor->unregisterVariableMatch(name)); QVERIFY(!editor->unregisterVariableMatch(name)); // prefix matches QVERIFY(!editor->unregisterVariablePrefix(name)); QVERIFY(editor->registerVariablePrefix(name, "Document Text", func)); QVERIFY(!editor->registerVariablePrefix(name, "Document Text", func)); QVERIFY(editor->unregisterVariablePrefix(name)); QVERIFY(!editor->unregisterVariablePrefix(name)); } void VariableTest::testExactMatch_data() { QTest::addColumn("text"); QTest::addColumn("expected"); QTest::addColumn("expectedText"); QTest::newRow("World") << "World" << "World" << "World"; QTest::newRow("Smart World") << "Smart World" << "Smart World" << "Smart World"; } void VariableTest::testExactMatch() { QFETCH(QString, text); QFETCH(QString, expected); QFETCH(QString, expectedText); auto editor = KTextEditor::Editor::instance(); auto doc = editor->createDocument(nullptr); auto view = doc->createView(nullptr); doc->setText(text); const QString name = QStringLiteral("Doc:Text"); auto func = [](const QStringView&, KTextEditor::View* view) { return view->document()->text(); }; QVERIFY(editor->registerVariableMatch(name, "Document Text", func)); // expandVariable QString output; QVERIFY(editor->expandVariable(QStringLiteral("Doc:Text"), view, output)); QCOMPARE(output, expected); // expandText editor->expandText(QStringLiteral("Hello %{Doc:Text}!"), view, output); QCOMPARE(output, QStringLiteral("Hello ") + expectedText + QLatin1Char('!')); editor->expandText(QStringLiteral("Hello %{Doc:Text} %{Doc:Text}!"), view, output); QCOMPARE(output, QStringLiteral("Hello ") + expectedText + QLatin1Char(' ') + expectedText + QLatin1Char('!')); QVERIFY(editor->unregisterVariableMatch("Doc:Text")); delete doc; } void VariableTest::testPrefixMatch() { auto editor = KTextEditor::Editor::instance(); const QString prefix = QStringLiteral("Mirror:"); auto func = [](const QStringView& text, KTextEditor::View*) { QStringView rest = text.right(text.size() - 7); QString out; for (auto it = rest.rbegin(); it != rest.rend(); ++it) { out += *it; } return out; }; QVERIFY(editor->registerVariablePrefix(prefix, "Reverse text", func)); QString output; QVERIFY(editor->expandVariable(QStringLiteral("Mirror:12345"), nullptr, output)); QCOMPARE(output, QStringLiteral("54321")); editor->expandText(QStringLiteral("Countdown: %{Mirror:12345}"), nullptr, output); QCOMPARE(output, QStringLiteral("Countdown: 54321")); // Test recursive expansion editor->expandText(QStringLiteral("Countup: %{Mirror:%{Mirror:12345}}"), nullptr, output); QCOMPARE(output, QStringLiteral("Countup: 12345")); QVERIFY(editor->unregisterVariablePrefix(prefix)); } void VariableTest::testRecursiveMatch() { auto editor = KTextEditor::Editor::instance(); auto doc = editor->createDocument(nullptr); auto view = doc->createView(nullptr); doc->setText(QStringLiteral("Text")); const QString name = QStringLiteral("Doc:Text"); auto func = [](const QStringView&, KTextEditor::View* view) { return view->document()->text(); }; QVERIFY(editor->registerVariableMatch(name, "Document Text", func)); // Test recursive expansion doc->setText(QStringLiteral("Text")); QString output; editor->expandText(QStringLiteral("Hello %{Doc:%{Doc:Text}}!"), view, output); QCOMPARE(output, QStringLiteral("Hello Text!")); QVERIFY(editor->unregisterVariableMatch(name)); delete doc; } +void VariableTest::testBuiltins() +{ + auto editor = KTextEditor::Editor::instance(); + auto doc = editor->createDocument(nullptr); + doc->openUrl(QUrl::fromLocalFile(QDir::homePath() + QStringLiteral("/kate-v5.tar.gz"))); + doc->setText(QStringLiteral("get an edge in editing\n:-)")); + auto view = doc->createView(nullptr); + view->setCursorPosition(KTextEditor::Cursor(1, 2)); + view->show(); + + QString out; + + // Document:FileBaseName + editor->expandText(QStringLiteral("%{Document:FileBaseName}"), view, out); + QCOMPARE(out, QStringLiteral("kate-v5")); + + // Document:FileExtension + editor->expandText(QStringLiteral("%{Document:FileExtension}"), view, out); + QCOMPARE(out, QStringLiteral("tar.gz")); + + // Document:FileName + editor->expandText(QStringLiteral("%{Document:FileName}"), view, out); + QCOMPARE(out, QStringLiteral("kate-v5.tar.gz")); + + // Document:FilePath + editor->expandText(QStringLiteral("%{Document:FilePath}"), view, out); + QCOMPARE(out, QFileInfo(view->document()->url().toLocalFile()).absoluteFilePath()); + + // Document:Text + editor->expandText(QStringLiteral("%{Document:Text}"), view, out); + QCOMPARE(out, QStringLiteral("get an edge in editing\n:-)")); + + // Document:Path + editor->expandText(QStringLiteral("%{Document:Path}"), view, out); + QCOMPARE(out, QFileInfo(doc->url().toLocalFile()).absolutePath()); + + // Document:NativeFilePath + editor->expandText(QStringLiteral("%{Document:NativeFilePath}"), view, out); + QCOMPARE(out, QDir::toNativeSeparators(QFileInfo(doc->url().toLocalFile()).absoluteFilePath())); + + // Document:NativePath + editor->expandText(QStringLiteral("%{Document:NativePath}"), view, out); + QCOMPARE(out, QDir::toNativeSeparators(QFileInfo(doc->url().toLocalFile()).absolutePath())); + + // Document:NativePath + editor->expandText(QStringLiteral("%{Document:NativePath}"), view, out); + QCOMPARE(out, QDir::toNativeSeparators(QFileInfo(doc->url().toLocalFile()).absolutePath())); + + // Document:Cursor:Line + editor->expandText(QStringLiteral("%{Document:Cursor:Line}"), view, out); + QCOMPARE(out, QStringLiteral("1")); + + // Document:Cursor:Column + editor->expandText(QStringLiteral("%{Document:Cursor:Column}"), view, out); + QCOMPARE(out, QStringLiteral("2")); + + // Document:Cursor:XPos + editor->expandText(QStringLiteral("%{Document:Cursor:XPos}"), view, out); + QVERIFY(out.toInt() > 0); + + // Document:Cursor:YPos + editor->expandText(QStringLiteral("%{Document:Cursor:YPos}"), view, out); + QVERIFY(out.toInt() > 0); + + + view->setSelection(KTextEditor::Range(1, 0, 1, 3)); + // Document:Selection:Text + editor->expandText(QStringLiteral("%{Document:Selection:Text}"), view, out); + QCOMPARE(out, QStringLiteral(":-)")); + + // Document:Selection:StartLine + editor->expandText(QStringLiteral("%{Document:Selection:StartLine}"), view, out); + QCOMPARE(out, QStringLiteral("1")); + + // Document:Selection:StartColumn + editor->expandText(QStringLiteral("%{Document:Selection:StartColumn}"), view, out); + QCOMPARE(out, QStringLiteral("0")); + + // Document:Selection:EndLine + editor->expandText(QStringLiteral("%{Document:Selection:EndLine}"), view, out); + QCOMPARE(out, QStringLiteral("1")); + + // Document:Selection:EndColumn + editor->expandText(QStringLiteral("%{Document:Selection:EndColumn}"), view, out); + QCOMPARE(out, QStringLiteral("3")); + + // Document:RowCount + editor->expandText(QStringLiteral("%{Document:RowCount}"), view, out); + QCOMPARE(out, QStringLiteral("2")); + + // Date:Locale + editor->expandText(QStringLiteral("%{Date:Locale}"), view, out); + QVERIFY(!out.isEmpty()); + + // Date:ISO + editor->expandText(QStringLiteral("%{Date:ISO}"), view, out); + QVERIFY(!out.isEmpty()); + + // Date:yyyy-MM-dd + editor->expandText(QStringLiteral("%{Date:yyyy-MM-dd}"), view, out); + QVERIFY(QDate::fromString(out, QStringLiteral("yyyy-MM-dd")).isValid()); + + // Time:Locale + editor->expandText(QStringLiteral("%{Time:Locale}"), view, out); + QVERIFY(!out.isEmpty()); + + // Time:ISO + editor->expandText(QStringLiteral("%{Time:ISO}"), view, out); + QVERIFY(!out.isEmpty()); + + // Time:hh-mm-ss + editor->expandText(QStringLiteral("%{Time:hh-mm-ss}"), view, out); + QVERIFY(QTime::fromString(out, QStringLiteral("hh-mm-ss")).isValid()); + + // ENV:HOME + editor->expandText(QStringLiteral("%{ENV:HOME}"), view, out); + QCOMPARE(out, QDir::homePath()); + + // JS: + editor->expandText(QStringLiteral("%{JS:3 + %{JS:2 + 1}}"), view, out); + QCOMPARE(out, QStringLiteral("6")); + + // UUID + editor->expandText(QStringLiteral("%{UUID}"), view, out); + QCOMPARE(out.count(QLatin1Char('-')), 4); +} + // kate: indent-mode cstyle; indent-width 4; replace-tabs on; diff --git a/autotests/src/variable_test.h b/autotests/src/variable_test.h index 1b6058c8..e154f5ea 100644 --- a/autotests/src/variable_test.h +++ b/autotests/src/variable_test.h @@ -1,41 +1,42 @@ /* This file is part of the KDE project * * Copyright 2019 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_VARIABLE_TEST_H #define KTEXTEDITOR_VARIABLE_TEST_H #include class VariableTest : public QObject { Q_OBJECT public: VariableTest(); ~VariableTest(); private Q_SLOTS: void testReturnValues(); void testExactMatch_data(); void testExactMatch(); void testPrefixMatch(); void testRecursiveMatch(); + void testBuiltins(); }; #endif // KTEXTEDITOR_VARIABLE_TEST_H diff --git a/src/utils/kateglobal.cpp b/src/utils/kateglobal.cpp index 4cb9a8b8..5f5ac430 100644 --- a/src/utils/kateglobal.cpp +++ b/src/utils/kateglobal.cpp @@ -1,540 +1,659 @@ /* This file is part of the KDE libraries and the Kate part. * * Copyright (C) 2001-2010 Christoph Cullmann * Copyright (C) 2009 Erlend Hamberg * * 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 "kateglobal.h" #include "config.h" #include #include "katedocument.h" #include "kateview.h" #include "katerenderer.h" #include "katecmd.h" #include "katecmds.h" #include "katesedcmd.h" #include "katehighlightingcmds.h" #include "katemodemanager.h" #include "kateschema.h" #include "kateschemaconfig.h" #include "kateconfig.h" #include "katescriptmanager.h" #include "katebuffer.h" #include "katewordcompletion.h" #include "katekeywordcompletion.h" #include "spellcheck/spellcheck.h" #include "katepartdebug.h" #include "katedefaultcolors.h" #include "katenormalinputmodefactory.h" #include "kateviinputmodefactory.h" #include #include #include #include #include #include #include #include #include +#include +#include +#include #include #include +#include #if LIBGIT2_FOUND #include #endif +namespace { + +void registerVariables(KTextEditor::Editor * editor) +{ + editor->registerVariableMatch(QStringLiteral("Document:FileBaseName"), i18n("File base name without path and suffix of the current document."), [](const QStringView&, KTextEditor::View* view) { + const auto url = view ? view->document()->url().toLocalFile() : QString(); + return QFileInfo(url).baseName(); + }); + editor->registerVariableMatch(QStringLiteral("Document:FileExtension"), i18n("File extension of the current document."), [](const QStringView&, KTextEditor::View* view) { + const auto url = view ? view->document()->url().toLocalFile() : QString(); + return QFileInfo(url).completeSuffix(); + }); + editor->registerVariableMatch(QStringLiteral("Document:FileName"), i18n("File name without path of the current document."), [](const QStringView&, KTextEditor::View* view) { + const auto url = view ? view->document()->url().toLocalFile() : QString(); + return QFileInfo(url).fileName(); + }); + editor->registerVariableMatch(QStringLiteral("Document:FilePath"), i18n("Full path of the current document including the file name."), [](const QStringView&, KTextEditor::View* view) { + const auto url = view ? view->document()->url().toLocalFile() : QString(); + return QFileInfo(url).absoluteFilePath(); + }); + editor->registerVariableMatch(QStringLiteral("Document:Text"), i18n("Contents of the current document."), [](const QStringView&, KTextEditor::View* view) { + return view ? view->document()->text() : QString(); + }); + editor->registerVariableMatch(QStringLiteral("Document:Path"), i18n("Full path of the current document excluding the file name."), [](const QStringView&, KTextEditor::View* view) { + const auto url = view ? view->document()->url().toLocalFile() : QString(); + return QFileInfo(url).absolutePath(); + }); + editor->registerVariableMatch(QStringLiteral("Document:NativeFilePath"), i18n("Full document path including file name, with native path separator (backslash on Windows)."), [](const QStringView&, KTextEditor::View* view) { + const auto url = view ? view->document()->url().toLocalFile() : QString(); + return url.isEmpty() ? QString() : QDir::toNativeSeparators(QFileInfo(url).absoluteFilePath()); + }); + editor->registerVariableMatch(QStringLiteral("Document:NativePath"), i18n("Full document path excluding file name, with native path separator (backslash on Windows)."), [](const QStringView&, KTextEditor::View* view) { + const auto url = view ? view->document()->url().toLocalFile() : QString(); + return url.isEmpty() ? QString() : QDir::toNativeSeparators(QFileInfo(url).absolutePath()); + }); + editor->registerVariableMatch(QStringLiteral("Document:Cursor:Line"), i18n("Line number of the text cursor position in current document (starts with 0)."), [](const QStringView&, KTextEditor::View* view) { + return view ? QString::number(view->cursorPosition().line()) : QString(); + }); + editor->registerVariableMatch(QStringLiteral("Document:Cursor:Column"), i18n("Column number of the text cursor position in current document (starts with 0)."), [](const QStringView&, KTextEditor::View* view) { + return view ? QString::number(view->cursorPosition().column()) : QString(); + }); + editor->registerVariableMatch(QStringLiteral("Document:Cursor:XPos"), i18n("X component in global screen coordinates of the cursor position."), [](const QStringView&, KTextEditor::View* view) { + return view ? QString::number(view->mapToGlobal(view->cursorPositionCoordinates()).x()) : QString(); + }); + editor->registerVariableMatch(QStringLiteral("Document:Cursor:YPos"), i18n("Y component in global screen coordinates of the cursor position."), [](const QStringView&, KTextEditor::View* view) { + return view ? QString::number(view->mapToGlobal(view->cursorPositionCoordinates()).y()) : QString(); + }); + editor->registerVariableMatch(QStringLiteral("Document:Selection:Text"), i18n("Text selection of the current document."), [](const QStringView&, KTextEditor::View* view) { + return (view && view->selection()) ? view->selectionText() : QString(); + }); + editor->registerVariableMatch(QStringLiteral("Document:Selection:StartLine"), i18n("Start line of selected text of the current document."), [](const QStringView&, KTextEditor::View* view) { + return (view && view->selection()) ? QString::number(view->selectionRange().start().line()) : QString(); + }); + editor->registerVariableMatch(QStringLiteral("Document:Selection:StartColumn"), i18n("Start column of selected text of the current document."), [](const QStringView&, KTextEditor::View* view) { + return (view && view->selection()) ? QString::number(view->selectionRange().start().column()) : QString(); + }); + editor->registerVariableMatch(QStringLiteral("Document:Selection:EndLine"), i18n("End line of selected text of the current document."), [](const QStringView&, KTextEditor::View* view) { + return (view && view->selection()) ? QString::number(view->selectionRange().end().line()) : QString(); + }); + editor->registerVariableMatch(QStringLiteral("Document:Selection:EndColumn"), i18n("End column of selected text of the current document."), [](const QStringView&, KTextEditor::View* view) { + return (view && view->selection()) ? QString::number(view->selectionRange().end().column()) : QString(); + }); + editor->registerVariableMatch(QStringLiteral("Document:RowCount"), i18n("Number of rows of the current document."), [](const QStringView&, KTextEditor::View* view) { + return view ? QString::number(view->document()->lines()) : QString(); + }); + + editor->registerVariableMatch(QStringLiteral("Date:Locale"), i18n("The current date in current locale format."), [](const QStringView&, KTextEditor::View*) { + return QDate::currentDate().toString(Qt::DefaultLocaleShortDate); + }); + editor->registerVariableMatch(QStringLiteral("Date:ISO"), i18n("The current date (ISO)."), [](const QStringView&, KTextEditor::View*) { + return QDate::currentDate().toString(Qt::ISODate); + }); + editor->registerVariablePrefix(QStringLiteral("Date:"), i18n("The current date (QDate formatstring)."), [](const QStringView& str, KTextEditor::View*) { + return QDate::currentDate().toString(str.right(str.length() - 5)); + }); + + editor->registerVariableMatch(QStringLiteral("Time:Locale"), i18n("The current time in current locale format."), [](const QStringView&, KTextEditor::View*) { + return QTime::currentTime().toString(Qt::DefaultLocaleShortDate); + }); + editor->registerVariableMatch(QStringLiteral("Time:ISO"), i18n("The current time (ISO)."), [](const QStringView&, KTextEditor::View*) { + return QTime::currentTime().toString(Qt::ISODate); + }); + editor->registerVariablePrefix(QStringLiteral("Time:"), i18n("The current time (QTime formatstring)."), [](const QStringView& str, KTextEditor::View*) { + return QTime::currentTime().toString(str.right(str.length() - 5)); + }); + + editor->registerVariablePrefix(QStringLiteral("ENV:"), i18n("Access to environment variables."), [](const QStringView& str, KTextEditor::View*) { + return QString::fromLocal8Bit(qgetenv(str.right(str.size() - 4).toLocal8Bit().constData())); + }); + + editor->registerVariablePrefix(QStringLiteral("JS:"), i18n("Evaluate simple JavaScript statements."), [](const QStringView& str, KTextEditor::View*) { + QJSEngine jsEngine; + const QJSValue out = jsEngine.evaluate(str.toString()); + return out.toString(); + }); + + editor->registerVariableMatch(QStringLiteral("UUID"), i18n("Generate a new UUID."), [](const QStringView&, KTextEditor::View*) { +#if QT_VERSION >= QT_VERSION_CHECK(5, 11, 0) + return QUuid::createUuid().toString(QUuid::WithoutBraces); +#else + // LEGACY + QString uuid = QUuid::createUuid().toString(); + if (uuid.startsWith(QLatin1Char('{'))) + uuid.remove(0, 1); + if (uuid.endsWith(QLatin1Char('}'))) + uuid.chop(1); + return uuid; +#endif + }); +} +} + //BEGIN unit test mode static bool kateUnitTestMode = false; void KTextEditor::EditorPrivate::enableUnitTestMode() { kateUnitTestMode = true; } bool KTextEditor::EditorPrivate::unitTestMode() { return kateUnitTestMode; } //END unit test mode KTextEditor::EditorPrivate::EditorPrivate(QPointer &staticInstance) : KTextEditor::Editor (this) , m_aboutData(QStringLiteral("katepart"), i18n("Kate Part"), QStringLiteral(KTEXTEDITOR_VERSION_STRING), i18n("Embeddable editor component"), KAboutLicense::LGPL_V2, i18n("(c) 2000-2019 The Kate Authors"), QString(), QStringLiteral("https://kate-editor.org")) , m_dummyApplication(nullptr) , m_application(&m_dummyApplication) , m_dummyMainWindow(nullptr) , m_defaultColors(new KateDefaultColors()) , m_searchHistoryModel(nullptr) , m_replaceHistoryModel(nullptr) { // remember this staticInstance = this; // init libgit2, we require at least 0.22 which has this function! #if LIBGIT2_FOUND git_libgit2_init(); #endif /** * register some datatypes */ qRegisterMetaType("KTextEditor::Cursor"); qRegisterMetaType("KTextEditor::Document*"); qRegisterMetaType("KTextEditor::View*"); // // fill about data // m_aboutData.addAuthor(i18n("Christoph Cullmann"), i18n("Maintainer"), QStringLiteral("cullmann@kde.org"), QStringLiteral("https://cullmann.io")); m_aboutData.addAuthor(i18n("Dominik Haumann"), i18n("Core Developer"), QStringLiteral("dhaumann@kde.org")); m_aboutData.addAuthor(i18n("Milian Wolff"), i18n("Core Developer"), QStringLiteral("mail@milianw.de"), QStringLiteral("http://milianw.de")); m_aboutData.addAuthor(i18n("Joseph Wenninger"), i18n("Core Developer"), QStringLiteral("jowenn@kde.org"), QStringLiteral("http://stud3.tuwien.ac.at/~e9925371")); m_aboutData.addAuthor(i18n("Erlend Hamberg"), i18n("Vi Input Mode"), QStringLiteral("ehamberg@gmail.com"), QStringLiteral("https://hamberg.no/erlend")); m_aboutData.addAuthor(i18n("Bernhard Beschow"), i18n("Developer"), QStringLiteral("bbeschow@cs.tu-berlin.de"), QStringLiteral("https://user.cs.tu-berlin.de/~bbeschow")); m_aboutData.addAuthor(i18n("Anders Lund"), i18n("Core Developer"), QStringLiteral("anders@alweb.dk"), QStringLiteral("https://alweb.dk")); m_aboutData.addAuthor(i18n("Michel Ludwig"), i18n("On-the-fly spell checking"), QStringLiteral("michel.ludwig@kdemail.net")); m_aboutData.addAuthor(i18n("Pascal Létourneau"), i18n("Large scale bug fixing"), QStringLiteral("pascal.letourneau@gmail.com")); m_aboutData.addAuthor(i18n("Hamish Rodda"), i18n("Core Developer"), QStringLiteral("rodda@kde.org")); m_aboutData.addAuthor(i18n("Waldo Bastian"), i18n("The cool buffersystem"), QStringLiteral("bastian@kde.org")); m_aboutData.addAuthor(i18n("Charles Samuels"), i18n("The Editing Commands"), QStringLiteral("charles@kde.org")); m_aboutData.addAuthor(i18n("Matt Newell"), i18n("Testing, ..."), QStringLiteral("newellm@proaxis.com")); m_aboutData.addAuthor(i18n("Michael Bartl"), i18n("Former Core Developer"), QStringLiteral("michael.bartl1@chello.at")); m_aboutData.addAuthor(i18n("Michael McCallum"), i18n("Core Developer"), QStringLiteral("gholam@xtra.co.nz")); m_aboutData.addAuthor(i18n("Michael Koch"), i18n("KWrite port to KParts"), QStringLiteral("koch@kde.org")); m_aboutData.addAuthor(i18n("Christian Gebauer"), QString(), QStringLiteral("gebauer@kde.org")); m_aboutData.addAuthor(i18n("Simon Hausmann"), QString(), QStringLiteral("hausmann@kde.org")); m_aboutData.addAuthor(i18n("Glen Parker"), i18n("KWrite Undo History, Kspell integration"), QStringLiteral("glenebob@nwlink.com")); m_aboutData.addAuthor(i18n("Scott Manson"), i18n("KWrite XML Syntax highlighting support"), QStringLiteral("sdmanson@alltel.net")); m_aboutData.addAuthor(i18n("John Firebaugh"), i18n("Patches and more"), QStringLiteral("jfirebaugh@kde.org")); m_aboutData.addAuthor(i18n("Andreas Kling"), i18n("Developer"), QStringLiteral("kling@impul.se")); m_aboutData.addAuthor(i18n("Mirko Stocker"), i18n("Various bugfixes"), QStringLiteral("me@misto.ch"), QStringLiteral("https://misto.ch/")); m_aboutData.addAuthor(i18n("Matthew Woehlke"), i18n("Selection, KColorScheme integration"), QStringLiteral("mw_triad@users.sourceforge.net")); m_aboutData.addAuthor(i18n("Sebastian Pipping"), i18n("Search bar back- and front-end"), QStringLiteral("webmaster@hartwork.org"), QStringLiteral("https://hartwork.org/")); m_aboutData.addAuthor(i18n("Jochen Wilhelmy"), i18n("Original KWrite Author"), QStringLiteral("digisnap@cs.tu-berlin.de")); m_aboutData.addAuthor(i18n("Gerald Senarclens de Grancy"), i18n("QA and Scripting"), QStringLiteral("oss@senarclens.eu"), QStringLiteral("http://find-santa.eu/")); m_aboutData.addCredit(i18n("Matteo Merli"), i18n("Highlighting for RPM Spec-Files, Perl, Diff and more"), QStringLiteral("merlim@libero.it")); m_aboutData.addCredit(i18n("Rocky Scaletta"), i18n("Highlighting for VHDL"), QStringLiteral("rocky@purdue.edu")); m_aboutData.addCredit(i18n("Yury Lebedev"), i18n("Highlighting for SQL"), QString()); m_aboutData.addCredit(i18n("Chris Ross"), i18n("Highlighting for Ferite"), QString()); m_aboutData.addCredit(i18n("Nick Roux"), i18n("Highlighting for ILERPG"), QString()); m_aboutData.addCredit(i18n("Carsten Niehaus"), i18n("Highlighting for LaTeX"), QString()); m_aboutData.addCredit(i18n("Per Wigren"), i18n("Highlighting for Makefiles, Python"), QString()); m_aboutData.addCredit(i18n("Jan Fritz"), i18n("Highlighting for Python"), QString()); m_aboutData.addCredit(i18n("Daniel Naber")); m_aboutData.addCredit(i18n("Roland Pabel"), i18n("Highlighting for Scheme"), QString()); m_aboutData.addCredit(i18n("Cristi Dumitrescu"), i18n("PHP Keyword/Datatype list"), QString()); m_aboutData.addCredit(i18n("Carsten Pfeiffer"), i18n("Very nice help"), QString()); m_aboutData.addCredit(i18n("Bruno Massa"), i18n("Highlighting for Lua"), QStringLiteral("brmassa@gmail.com")); m_aboutData.addCredit(i18n("All people who have contributed and I have forgotten to mention")); m_aboutData.setTranslator(i18nc("NAME OF TRANSLATORS", "Your names"), i18nc("EMAIL OF TRANSLATORS", "Your emails")); /** * set the new Kate mascot */ m_aboutData.setProgramLogo (QImage(QStringLiteral(":/ktexteditor/mascot.png"))); // // dir watch // m_dirWatch = new KDirWatch(); // // command manager // m_cmdManager = new KateCmd(); // // hl manager // m_hlManager = new KateHlManager(); // // mode man // m_modeManager = new KateModeManager(); // // schema man // m_schemaManager = new KateSchemaManager(); // // input mode factories // KateAbstractInputModeFactory *fact; fact = new KateNormalInputModeFactory(); m_inputModeFactories.insert(KTextEditor::View::NormalInputMode, fact); #if BUILD_VIMODE fact = new KateViInputModeFactory(); m_inputModeFactories.insert(KTextEditor::View::ViInputMode, fact); #endif // // spell check manager // m_spellCheckManager = new KateSpellCheckManager(); // config objects m_globalConfig = new KateGlobalConfig(); m_documentConfig = new KateDocumentConfig(); m_viewConfig = new KateViewConfig(); m_rendererConfig = new KateRendererConfig(); // create script manager (search scripts) m_scriptManager = KateScriptManager::self(); // // init the cmds // m_cmds.push_back(KateCommands::CoreCommands::self()); m_cmds.push_back(KateCommands::Character::self()); m_cmds.push_back(KateCommands::Date::self()); m_cmds.push_back(KateCommands::SedReplace::self()); m_cmds.push_back(KateCommands::Highlighting::self()); // global word completion model m_wordCompletionModel = new KateWordCompletionModel(this); // global keyword completion model m_keywordCompletionModel = new KateKeywordCompletionModel (this); // tap to QApplication object for color palette changes qApp->installEventFilter(this); + + // register default variables for expansion + registerVariables(this); } KTextEditor::EditorPrivate::~EditorPrivate() { delete m_globalConfig; delete m_documentConfig; delete m_viewConfig; delete m_rendererConfig; delete m_modeManager; delete m_schemaManager; delete m_dirWatch; // cu managers delete m_scriptManager; delete m_hlManager; delete m_spellCheckManager; // cu model delete m_wordCompletionModel; // delete the commands before we delete the cmd manager qDeleteAll(m_cmds); delete m_cmdManager; qDeleteAll(m_inputModeFactories); // shutdown libgit2, we require at least 0.22 which has this function! #if LIBGIT2_FOUND git_libgit2_shutdown(); #endif } KTextEditor::Document *KTextEditor::EditorPrivate::createDocument(QObject *parent) { KTextEditor::DocumentPrivate *doc = new KTextEditor::DocumentPrivate(false, false, nullptr, parent); emit documentCreated(this, doc); return doc; } //END KTextEditor::Editor config stuff void KTextEditor::EditorPrivate::configDialog(QWidget *parent) { QPointer kd = new KPageDialog(parent); kd->setWindowTitle(i18n("Configure")); kd->setFaceType(KPageDialog::List); kd->setStandardButtons(QDialogButtonBox::Ok | QDialogButtonBox::Cancel | QDialogButtonBox::Apply | QDialogButtonBox::Help); QList editorPages; for (int i = 0; i < configPages(); ++i) { QFrame *page = new QFrame(); KTextEditor::ConfigPage *cp = configPage(i, page); KPageWidgetItem *item = kd->addPage(page, cp->name()); item->setHeader(cp->fullName()); item->setIcon(cp->icon()); QVBoxLayout *topLayout = new QVBoxLayout(page); topLayout->setContentsMargins(0, 0, 0, 0); connect(kd->button(QDialogButtonBox::Apply), SIGNAL(clicked()), cp, SLOT(apply())); topLayout->addWidget(cp); editorPages.append(cp); } if (kd->exec() && kd) { KateGlobalConfig::global()->configStart(); KateDocumentConfig::global()->configStart(); KateViewConfig::global()->configStart(); KateRendererConfig::global()->configStart(); for (int i = 0; i < editorPages.count(); ++i) { editorPages.at(i)->apply(); } KateGlobalConfig::global()->configEnd(); KateDocumentConfig::global()->configEnd(); KateViewConfig::global()->configEnd(); KateRendererConfig::global()->configEnd(); } delete kd; } int KTextEditor::EditorPrivate::configPages() const { return 4; } KTextEditor::ConfigPage *KTextEditor::EditorPrivate::configPage(int number, QWidget *parent) { switch (number) { case 0: return new KateViewDefaultsConfig(parent); case 1: return new KateSchemaConfigPage(parent); case 2: return new KateEditConfigTab(parent); case 3: return new KateSaveConfigTab(parent); default: break; } return nullptr; } /** * Cleanup the KTextEditor::EditorPrivate during QCoreApplication shutdown */ static void cleanupGlobal() { /** * delete if there */ delete KTextEditor::EditorPrivate::self(); } KTextEditor::EditorPrivate *KTextEditor::EditorPrivate::self() { /** * remember the static instance in a QPointer */ static bool inited = false; static QPointer staticInstance; /** * just return it, if already inited */ if (inited) { return staticInstance.data(); } /** * start init process */ inited = true; /** * now create the object and store it */ new KTextEditor::EditorPrivate(staticInstance); /** * register cleanup * let use be deleted during QCoreApplication shutdown */ qAddPostRoutine(cleanupGlobal); /** * return instance */ return staticInstance.data(); } void KTextEditor::EditorPrivate::registerDocument(KTextEditor::DocumentPrivate *doc) { Q_ASSERT (!m_documents.contains(doc)); m_documents.insert(doc, doc); } void KTextEditor::EditorPrivate::deregisterDocument(KTextEditor::DocumentPrivate *doc) { Q_ASSERT (m_documents.contains(doc)); m_documents.remove(doc); } void KTextEditor::EditorPrivate::registerView(KTextEditor::ViewPrivate *view) { Q_ASSERT (!m_views.contains(view)); m_views.insert(view); } void KTextEditor::EditorPrivate::deregisterView(KTextEditor::ViewPrivate *view) { Q_ASSERT (m_views.contains(view)); m_views.remove(view); } KTextEditor::Command *KTextEditor::EditorPrivate::queryCommand(const QString &cmd) const { return m_cmdManager->queryCommand(cmd); } QList KTextEditor::EditorPrivate::commands() const { return m_cmdManager->commands(); } QStringList KTextEditor::EditorPrivate::commandList() const { return m_cmdManager->commandList(); } void KTextEditor::EditorPrivate::updateColorPalette() { // update default color cache m_defaultColors.reset(new KateDefaultColors()); // reload the global schema (triggers reload for every view as well) m_rendererConfig->reloadSchema(); // force full update of all view caches and colors m_rendererConfig->updateConfig(); } void KTextEditor::EditorPrivate::copyToClipboard(const QString &text) { /** * empty => nop */ if (text.isEmpty()) { return; } /** * move to clipboard */ QApplication::clipboard()->setText(text, QClipboard::Clipboard); /** * LRU, kill potential duplicated, move new entry to top * cut after 10 entries */ m_clipboardHistory.removeOne(text); m_clipboardHistory.prepend(text); if (m_clipboardHistory.size() > 10) { m_clipboardHistory.removeLast(); } /** * notify about change */ emit clipboardHistoryChanged(); } bool KTextEditor::EditorPrivate::eventFilter(QObject *obj, QEvent *event) { if (obj == qApp && event->type() == QEvent::ApplicationPaletteChange) { // only update the color once for the event that belongs to the qApp updateColorPalette(); } return false; // always continue processing } QList< KateAbstractInputModeFactory *> KTextEditor::EditorPrivate::inputModeFactories() { return m_inputModeFactories.values(); } QStringListModel *KTextEditor::EditorPrivate::searchHistoryModel() { if (!m_searchHistoryModel) { KConfigGroup cg(KSharedConfig::openConfig(), "KTextEditor::Search"); const QStringList history = cg.readEntry(QStringLiteral("Search History"), QStringList()); m_searchHistoryModel = new QStringListModel(history, this); } return m_searchHistoryModel; } QStringListModel *KTextEditor::EditorPrivate::replaceHistoryModel() { if (!m_replaceHistoryModel) { KConfigGroup cg(KSharedConfig::openConfig(), "KTextEditor::Search"); const QStringList history = cg.readEntry(QStringLiteral("Replace History"), QStringList()); m_replaceHistoryModel = new QStringListModel(history, this); } return m_replaceHistoryModel; } void KTextEditor::EditorPrivate::saveSearchReplaceHistoryModels() { KConfigGroup cg(KSharedConfig::openConfig(), "KTextEditor::Search"); if (m_searchHistoryModel) { cg.writeEntry(QStringLiteral("Search History"), m_searchHistoryModel->stringList()); } if (m_replaceHistoryModel) { cg.writeEntry(QStringLiteral("Replace History"), m_replaceHistoryModel->stringList()); } } KSharedConfigPtr KTextEditor::EditorPrivate::config() { // use dummy config for unit tests! if (KTextEditor::EditorPrivate::unitTestMode()) { return KSharedConfig::openConfig(QStringLiteral("katepartrc-unittest"), KConfig::SimpleConfig, QStandardPaths::TempLocation); } // else: use application configuration, but try to transfer global settings on first use auto applicationConfig = KSharedConfig::openConfig(); if (!KConfigGroup(applicationConfig, QStringLiteral("KTextEditor Editor")).exists()) { auto globalConfig = KSharedConfig::openConfig(QStringLiteral("katepartrc")); for (auto group : {QStringLiteral("Editor"), QStringLiteral("Document"), QStringLiteral("View"), QStringLiteral("Renderer")}) { KConfigGroup origin(globalConfig, group); KConfigGroup destination(applicationConfig, QStringLiteral("KTextEditor ") + group); origin.copyTo(&destination); } } return applicationConfig; }