diff --git a/autotests/src/variable_test.h b/autotests/src/variable_test.h --- a/autotests/src/variable_test.h +++ b/autotests/src/variable_test.h @@ -36,6 +36,7 @@ void testExactMatch(); void testPrefixMatch(); void testRecursiveMatch(); + void testBuiltins(); }; #endif // KTEXTEDITOR_VARIABLE_TEST_H diff --git a/autotests/src/variable_test.cpp b/autotests/src/variable_test.cpp --- a/autotests/src/variable_test.cpp +++ b/autotests/src/variable_test.cpp @@ -277,9 +277,10 @@ 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(QFileInfo(out).canonicalFilePath(), QFileInfo(QDir::homePath()).canonicalFilePath()); + // ENV:KTE_ENV_VAR_TEST + qputenv("KTE_ENV_VAR_TEST", "KTE_ENV_VAR_TEST_VALUE"); + editor->expandText(QStringLiteral("%{ENV:KTE_ENV_VAR_TEST}"), view, out); + QCOMPARE(out, QStringLiteral("KTE_ENV_VAR_TEST_VALUE")); // JS: editor->expandText(QStringLiteral("%{JS:3 + %{JS:2 + 1}}"), view, out); diff --git a/src/utils/kateglobal.cpp b/src/utils/kateglobal.cpp --- a/src/utils/kateglobal.cpp +++ b/src/utils/kateglobal.cpp @@ -56,13 +56,129 @@ #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; @@ -226,6 +342,9 @@ // tap to QApplication object for color palette changes qApp->installEventFilter(this); + + // register default variables for expansion + registerVariables(this); } KTextEditor::EditorPrivate::~EditorPrivate()