From 2ceb1e2ad7be8b4d6ec2856da97530723cde7eb8 Mon Sep 17 00:00:00 2001 From: David Schulz Date: Tue, 13 Feb 2024 05:18:33 +0100 Subject: TextEditor: update ksyntaxhighlighting engine to v5.249.0 Task-number: QTCREATORBUG-22558 Change-Id: I0f75fd00828992df37f596148fac98069794248e Reviewed-by: Christian Stenger --- .../syntax-highlighting/src/CMakeLists.txt | 4 +- .../3rdparty/syntax-highlighting/src/Messages.sh | 2 +- .../syntax-highlighting/src/cli/CMakeLists.txt | 8 +- .../src/cli/kate-syntax-highlighter.cpp | 226 ------------- .../src/cli/ksyntaxhighlighter.cpp | 236 +++++++++++++ .../syntax-highlighting/src/indexer/CMakeLists.txt | 19 +- .../src/indexer/katehighlightingindexer.cpp | 366 +++++++++++++++------ .../syntax-highlighting/src/lib/CMakeLists.txt | 50 ++- .../src/lib/abstracthighlighter.cpp | 123 ++++--- .../src/lib/abstracthighlighter.h | 24 +- .../src/lib/abstracthighlighter_p.h | 3 +- .../src/lib/ansihighlighter.cpp | 107 +++--- .../syntax-highlighting/src/lib/ansihighlighter.h | 34 +- .../syntax-highlighting/src/lib/context.cpp | 13 +- .../syntax-highlighting/src/lib/context_p.h | 19 +- .../syntax-highlighting/src/lib/definition.cpp | 85 +++-- .../syntax-highlighting/src/lib/definition.h | 22 +- .../syntax-highlighting/src/lib/definition_p.h | 26 +- .../src/lib/definitiondownloader.cpp | 6 +- .../syntax-highlighting/src/lib/definitionref_p.h | 6 +- .../src/lib/dynamicregexpcache_p.h | 39 +++ .../syntax-highlighting/src/lib/foldingregion.cpp | 31 +- .../syntax-highlighting/src/lib/foldingregion.h | 19 +- .../syntax-highlighting/src/lib/format.cpp | 2 +- .../3rdparty/syntax-highlighting/src/lib/format.h | 10 +- .../syntax-highlighting/src/lib/format_p.h | 11 +- .../src/lib/highlightingdata.cpp | 1 + .../src/lib/highlightingdata_p.hpp | 1 + .../src/lib/htmlhighlighter.cpp | 153 +++++---- .../syntax-highlighting/src/lib/htmlhighlighter.h | 7 +- .../syntax-highlighting/src/lib/keywordlist.cpp | 7 +- .../syntax-highlighting/src/lib/matchresult_p.h | 6 +- .../syntax-highlighting/src/lib/repository.cpp | 76 ++--- .../syntax-highlighting/src/lib/repository.h | 66 ++-- .../syntax-highlighting/src/lib/repository_p.h | 26 +- .../3rdparty/syntax-highlighting/src/lib/rule.cpp | 105 +++--- .../3rdparty/syntax-highlighting/src/lib/rule_p.h | 55 ++-- .../3rdparty/syntax-highlighting/src/lib/state.cpp | 77 ++--- .../3rdparty/syntax-highlighting/src/lib/state.h | 14 +- .../3rdparty/syntax-highlighting/src/lib/state_p.h | 56 +++- .../src/lib/syntaxhighlighter.cpp | 141 ++++++-- .../src/lib/syntaxhighlighter.h | 1 + .../3rdparty/syntax-highlighting/src/lib/theme.cpp | 2 + .../3rdparty/syntax-highlighting/src/lib/theme.h | 9 +- .../syntax-highlighting/src/lib/themedata.cpp | 54 ++- .../syntax-highlighting/src/lib/themedata_p.h | 11 +- .../syntax-highlighting/src/lib/worddelimiters.cpp | 6 + .../syntax-highlighting/src/lib/worddelimiters_p.h | 5 + .../syntax-highlighting/src/quick/CMakeLists.txt | 5 +- .../src/quick/kquicksyntaxhighlighter.cpp | 14 +- .../src/quick/kquicksyntaxhighlighter.h | 10 +- .../src/quick/kquicksyntaxhighlightingplugin.cpp | 20 +- .../src/quick/repositorywrapper.cpp | 65 ---- .../src/quick/repositorywrapper.h | 45 --- 54 files changed, 1426 insertions(+), 1103 deletions(-) delete mode 100644 src/libs/3rdparty/syntax-highlighting/src/cli/kate-syntax-highlighter.cpp create mode 100644 src/libs/3rdparty/syntax-highlighting/src/cli/ksyntaxhighlighter.cpp create mode 100644 src/libs/3rdparty/syntax-highlighting/src/lib/dynamicregexpcache_p.h delete mode 100644 src/libs/3rdparty/syntax-highlighting/src/quick/repositorywrapper.cpp delete mode 100644 src/libs/3rdparty/syntax-highlighting/src/quick/repositorywrapper.h (limited to 'src/libs/3rdparty/syntax-highlighting/src') diff --git a/src/libs/3rdparty/syntax-highlighting/src/CMakeLists.txt b/src/libs/3rdparty/syntax-highlighting/src/CMakeLists.txt index 419b8ed5b7c..9d53a5bc3d5 100644 --- a/src/libs/3rdparty/syntax-highlighting/src/CMakeLists.txt +++ b/src/libs/3rdparty/syntax-highlighting/src/CMakeLists.txt @@ -1,9 +1,9 @@ add_subdirectory(indexer) -if(TARGET Qt${QT_MAJOR_VERSION}::Gui) +if(TARGET Qt6::Gui) add_subdirectory(lib) add_subdirectory(cli) endif() -if(TARGET Qt${QT_MAJOR_VERSION}::Quick) +if(TARGET Qt6::Quick) add_subdirectory(quick) endif() diff --git a/src/libs/3rdparty/syntax-highlighting/src/Messages.sh b/src/libs/3rdparty/syntax-highlighting/src/Messages.sh index 6fb605ddf08..4024d9b74d4 100644 --- a/src/libs/3rdparty/syntax-highlighting/src/Messages.sh +++ b/src/libs/3rdparty/syntax-highlighting/src/Messages.sh @@ -8,4 +8,4 @@ sed -i -e 's/^i18nc/QT_TRANSLATE_NOOP/' rc.cpp grep --no-filename '"name"' ../data/themes/*.theme | \ sed -r -e 's/"name"/QT_TRANSLATE_NOOP("Theme", /; s/://; s/,?$/);/' >> rc.cpp -$EXTRACT_TR_STRINGS `find . -name \*.cpp -o -name \*.h -o -name \*.ui -o -name \*.qml` -o $podir/syntaxhighlighting5_qt.pot +$EXTRACT_TR_STRINGS `find . -name \*.cpp -o -name \*.h -o -name \*.ui -o -name \*.qml` -o $podir/syntaxhighlighting6_qt.pot diff --git a/src/libs/3rdparty/syntax-highlighting/src/cli/CMakeLists.txt b/src/libs/3rdparty/syntax-highlighting/src/cli/CMakeLists.txt index 1a4d24d8284..3aa3a8afc3f 100644 --- a/src/libs/3rdparty/syntax-highlighting/src/cli/CMakeLists.txt +++ b/src/libs/3rdparty/syntax-highlighting/src/cli/CMakeLists.txt @@ -1,5 +1,5 @@ -add_executable(kate-syntax-highlighter kate-syntax-highlighter.cpp) -ecm_mark_nongui_executable(kate-syntax-highlighter) -target_link_libraries(kate-syntax-highlighter KF5SyntaxHighlighting) +add_executable(ksyntaxhighlighter6 ksyntaxhighlighter.cpp) +ecm_mark_nongui_executable(ksyntaxhighlighter6) +target_link_libraries(ksyntaxhighlighter6 KF6SyntaxHighlighting) -install(TARGETS kate-syntax-highlighter ${KDE_INSTALL_TARGETS_DEFAULT_ARGS}) +install(TARGETS ksyntaxhighlighter6 ${KDE_INSTALL_TARGETS_DEFAULT_ARGS}) diff --git a/src/libs/3rdparty/syntax-highlighting/src/cli/kate-syntax-highlighter.cpp b/src/libs/3rdparty/syntax-highlighting/src/cli/kate-syntax-highlighter.cpp deleted file mode 100644 index 5ce90e00530..00000000000 --- a/src/libs/3rdparty/syntax-highlighting/src/cli/kate-syntax-highlighter.cpp +++ /dev/null @@ -1,226 +0,0 @@ -/* - SPDX-FileCopyrightText: 2016 Volker Krause - - SPDX-License-Identifier: MIT -*/ - -#include "ksyntaxhighlighting_version.h" - -#include -#include -#include -#include -#include -#include - -#include -#include -#include - -#include - -using namespace KSyntaxHighlighting; - -template -static void applyHighlighter(Highlighter &highlighter, - QCommandLineParser &parser, - bool fromFileName, - const QString &inFileName, - const QCommandLineOption &stdinOption, - const QCommandLineOption &outputName, - const Ts &...highlightParams) -{ - if (parser.isSet(outputName)) { - highlighter.setOutputFile(parser.value(outputName)); - } else { - highlighter.setOutputFile(stdout); - } - - if (fromFileName) { - highlighter.highlightFile(inFileName, highlightParams...); - } else if (parser.isSet(stdinOption)) { - QFile inFile; - inFile.open(stdin, QIODevice::ReadOnly); - highlighter.highlightData(&inFile, highlightParams...); - } else { - parser.showHelp(1); - } -} - -int main(int argc, char **argv) -{ - QCoreApplication app(argc, argv); - QCoreApplication::setApplicationName(QStringLiteral("kate-syntax-highlighter")); - QCoreApplication::setOrganizationDomain(QStringLiteral("kde.org")); - QCoreApplication::setOrganizationName(QStringLiteral("KDE")); - QCoreApplication::setApplicationVersion(QStringLiteral(SyntaxHighlighting_VERSION_STRING)); - - Repository repo; - - QCommandLineParser parser; - parser.setApplicationDescription(app.translate("SyntaxHighlightingCLI", "Command line syntax highlighter using Kate syntax definitions.")); - parser.addHelpOption(); - parser.addVersionOption(); - parser.addPositionalArgument(app.translate("SyntaxHighlightingCLI", "source"), app.translate("SyntaxHighlightingCLI", "The source file to highlight.")); - - QCommandLineOption listDefs(QStringList() << QStringLiteral("l") << QStringLiteral("list"), - app.translate("SyntaxHighlightingCLI", "List all available syntax definitions.")); - parser.addOption(listDefs); - QCommandLineOption listThemes(QStringList() << QStringLiteral("list-themes"), app.translate("SyntaxHighlightingCLI", "List all available themes.")); - parser.addOption(listThemes); - - QCommandLineOption updateDefs(QStringList() << QStringLiteral("u") << QStringLiteral("update"), - app.translate("SyntaxHighlightingCLI", "Download new/updated syntax definitions.")); - parser.addOption(updateDefs); - - QCommandLineOption outputName(QStringList() << QStringLiteral("o") << QStringLiteral("output"), - app.translate("SyntaxHighlightingCLI", "File to write HTML output to (default: stdout)."), - app.translate("SyntaxHighlightingCLI", "output")); - parser.addOption(outputName); - - QCommandLineOption syntaxName(QStringList() << QStringLiteral("s") << QStringLiteral("syntax"), - app.translate("SyntaxHighlightingCLI", "Highlight using this syntax definition (default: auto-detect based on input file)."), - app.translate("SyntaxHighlightingCLI", "syntax")); - parser.addOption(syntaxName); - - QCommandLineOption themeName(QStringList() << QStringLiteral("t") << QStringLiteral("theme"), - app.translate("SyntaxHighlightingCLI", "Color theme to use for highlighting."), - app.translate("SyntaxHighlightingCLI", "theme"), - repo.defaultTheme(Repository::LightTheme).name()); - parser.addOption(themeName); - - QCommandLineOption outputFormatOption( - QStringList() << QStringLiteral("f") << QStringLiteral("output-format"), - app.translate("SyntaxHighlightingCLI", "Use the specified format instead of html. Must be html, ansi or ansi256Colors."), - app.translate("SyntaxHighlightingCLI", "format"), - QStringLiteral("html")); - parser.addOption(outputFormatOption); - - QCommandLineOption traceOption(QStringList() << QStringLiteral("syntax-trace"), - app.translate("SyntaxHighlightingCLI", - "Add information to debug a syntax file. Only works with --output-format=ansi or ansi256Colors. Possible " - "values are format, region, context and stackSize."), - app.translate("SyntaxHighlightingCLI", "type")); - parser.addOption(traceOption); - - QCommandLineOption noAnsiEditorBg(QStringList() << QStringLiteral("b") << QStringLiteral("no-ansi-background"), - app.translate("SyntaxHighlightingCLI", "Disable ANSI background for the default color.")); - parser.addOption(noAnsiEditorBg); - - QCommandLineOption titleOption( - QStringList() << QStringLiteral("T") << QStringLiteral("title"), - app.translate("SyntaxHighlightingCLI", "Set HTML page's title\n(default: the filename or \"Kate Syntax Highlighter\" if reading from stdin)."), - app.translate("SyntaxHighlightingCLI", "title")); - parser.addOption(titleOption); - - QCommandLineOption stdinOption(QStringList() << QStringLiteral("stdin"), - app.translate("SyntaxHighlightingCLI", "Read file from stdin. The -s option must also be used.")); - parser.addOption(stdinOption); - - parser.process(app); - - if (parser.isSet(listDefs)) { - for (const auto &def : repo.definitions()) { - std::cout << qPrintable(def.name()) << std::endl; - } - return 0; - } - - if (parser.isSet(listThemes)) { - for (const auto &theme : repo.themes()) { - std::cout << qPrintable(theme.name()) << std::endl; - } - return 0; - } - - if (parser.isSet(updateDefs)) { - DefinitionDownloader downloader(&repo); - QObject::connect(&downloader, &DefinitionDownloader::informationMessage, [](const QString &msg) { - std::cout << qPrintable(msg) << std::endl; - }); - QObject::connect(&downloader, &DefinitionDownloader::done, &app, &QCoreApplication::quit); - downloader.start(); - return app.exec(); - } - - bool fromFileName = false; - QString inFileName; - if (parser.positionalArguments().size() == 1) { - fromFileName = true; - inFileName = parser.positionalArguments().at(0); - } - - Definition def; - if (parser.isSet(syntaxName)) { - const QString syntax = parser.value(syntaxName); - def = repo.definitionForName(syntax); - if (!def.isValid()) { - /* see if it's a mimetype instead */ - def = repo.definitionForMimeType(syntax); - if (!def.isValid()) { - /* see if it's a extension instead */ - def = repo.definitionForFileName(QLatin1String("f.") + syntax); - if (!def.isValid()) { - /* see if it's a filename instead */ - def = repo.definitionForFileName(syntax); - } - } - } - } else if (fromFileName) { - def = repo.definitionForFileName(inFileName); - } else { - parser.showHelp(1); - } - - if (!def.isValid()) { - std::cerr << "Unknown syntax." << std::endl; - return 1; - } - - QString outputFormat = parser.value(outputFormatOption); - if (0 == outputFormat.compare(QLatin1String("html"), Qt::CaseInsensitive)) { - QString title; - if (parser.isSet(titleOption)) { - title = parser.value(titleOption); - } - - HtmlHighlighter highlighter; - highlighter.setDefinition(def); - highlighter.setTheme(repo.theme(parser.value(themeName))); - applyHighlighter(highlighter, parser, fromFileName, inFileName, stdinOption, outputName, title); - } else { - auto AnsiFormat = AnsiHighlighter::AnsiFormat::TrueColor; - if (0 == outputFormat.compare(QLatin1String("ansi256Colors"), Qt::CaseInsensitive)) { - AnsiFormat = AnsiHighlighter::AnsiFormat::XTerm256Color; - } else if (0 != outputFormat.compare(QLatin1String("ansi"), Qt::CaseInsensitive)) { - std::cerr << "Unknown output format." << std::endl; - return 2; - } - - auto debugOptions = AnsiHighlighter::TraceOptions(); - if (parser.isSet(traceOption)) { - const auto options = parser.values(traceOption); - for (auto const &option : options) { - if (option == QStringLiteral("format")) { - debugOptions |= AnsiHighlighter::TraceOption::Format; - } else if (option == QStringLiteral("region")) { - debugOptions |= AnsiHighlighter::TraceOption::Region; - } else if (option == QStringLiteral("context")) { - debugOptions |= AnsiHighlighter::TraceOption::Context; - } else if (option == QStringLiteral("stackSize")) { - debugOptions |= AnsiHighlighter::TraceOption::StackSize; - } else { - std::cerr << "Unknown trace name." << std::endl; - return 2; - } - } - } - - AnsiHighlighter highlighter; - highlighter.setDefinition(def); - highlighter.setTheme(repo.theme(parser.value(themeName))); - applyHighlighter(highlighter, parser, fromFileName, inFileName, stdinOption, outputName, AnsiFormat, !parser.isSet(noAnsiEditorBg), debugOptions); - } - - return 0; -} diff --git a/src/libs/3rdparty/syntax-highlighting/src/cli/ksyntaxhighlighter.cpp b/src/libs/3rdparty/syntax-highlighting/src/cli/ksyntaxhighlighter.cpp new file mode 100644 index 00000000000..681410cb706 --- /dev/null +++ b/src/libs/3rdparty/syntax-highlighting/src/cli/ksyntaxhighlighter.cpp @@ -0,0 +1,236 @@ +/* + SPDX-FileCopyrightText: 2016 Volker Krause + + SPDX-License-Identifier: MIT +*/ + +#include "ksyntaxhighlighting_version.h" + +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include + +using namespace KSyntaxHighlighting; + +template +static void applyHighlighter(Highlighter &highlighter, + QCommandLineParser &parser, + bool fromFileName, + const QString &inFileName, + const QCommandLineOption &outputName, + const Ts &...highlightParams) +{ + if (parser.isSet(outputName)) { + highlighter.setOutputFile(parser.value(outputName)); + } else { + highlighter.setOutputFile(stdout); + } + + if (fromFileName) { + highlighter.highlightFile(inFileName, highlightParams...); + } else { + QFile inFile; + inFile.open(stdin, QIODevice::ReadOnly); + highlighter.highlightData(&inFile, highlightParams...); + } +} + +static Theme theme(const Repository &repo, const QString &themeName, Repository::DefaultTheme t) +{ + if (themeName.isEmpty()) { + return repo.defaultTheme(t); + } + return repo.theme(themeName); +} + +int main(int argc, char **argv) +{ + QCoreApplication app(argc, argv); + QCoreApplication::setApplicationName(QStringLiteral("ksyntaxhighlighter")); + QCoreApplication::setOrganizationDomain(QStringLiteral("kde.org")); + QCoreApplication::setOrganizationName(QStringLiteral("KDE")); + QCoreApplication::setApplicationVersion(QStringLiteral(KSYNTAXHIGHLIGHTING_VERSION_STRING)); + + QCommandLineParser parser; + parser.setApplicationDescription(app.translate("SyntaxHighlightingCLI", "Command line syntax highlighter using KSyntaxHighlighting syntax definitions.")); + parser.addHelpOption(); + parser.addVersionOption(); + parser.addPositionalArgument( + app.translate("SyntaxHighlightingCLI", "source"), + app.translate("SyntaxHighlightingCLI", "The source file to highlight. If absent, read the file from stdin and the --syntax option must be used.")); + + QCommandLineOption listDefs(QStringList() << QStringLiteral("l") << QStringLiteral("list"), + app.translate("SyntaxHighlightingCLI", "List all available syntax definitions.")); + parser.addOption(listDefs); + QCommandLineOption listThemes(QStringList() << QStringLiteral("list-themes"), app.translate("SyntaxHighlightingCLI", "List all available themes.")); + parser.addOption(listThemes); + + QCommandLineOption updateDefs(QStringList() << QStringLiteral("u") << QStringLiteral("update"), + app.translate("SyntaxHighlightingCLI", "Download new/updated syntax definitions.")); + parser.addOption(updateDefs); + + QCommandLineOption outputName(QStringList() << QStringLiteral("o") << QStringLiteral("output"), + app.translate("SyntaxHighlightingCLI", "File to write HTML output to (default: stdout)."), + app.translate("SyntaxHighlightingCLI", "output")); + parser.addOption(outputName); + + QCommandLineOption syntaxName(QStringList() << QStringLiteral("s") << QStringLiteral("syntax"), + app.translate("SyntaxHighlightingCLI", "Highlight using this syntax definition (default: auto-detect based on input file)."), + app.translate("SyntaxHighlightingCLI", "syntax")); + parser.addOption(syntaxName); + + QCommandLineOption themeName(QStringList() << QStringLiteral("t") << QStringLiteral("theme"), + app.translate("SyntaxHighlightingCLI", "Color theme to use for highlighting."), + app.translate("SyntaxHighlightingCLI", "theme")); + parser.addOption(themeName); + + QCommandLineOption outputFormatOption( + QStringList() << QStringLiteral("f") << QStringLiteral("output-format"), + app.translate("SyntaxHighlightingCLI", "Use the specified format instead of html. Must be html, ansi or ansi256Colors."), + app.translate("SyntaxHighlightingCLI", "format"), + QStringLiteral("html")); + parser.addOption(outputFormatOption); + + QCommandLineOption traceOption(QStringList() << QStringLiteral("syntax-trace"), + app.translate("SyntaxHighlightingCLI", + "Add information to debug a syntax file. Only works with --output-format=ansi or ansi256Colors. Possible " + "values are format, region, context, stackSize and all."), + app.translate("SyntaxHighlightingCLI", "type")); + parser.addOption(traceOption); + + QCommandLineOption noAnsiEditorBg(QStringList() << QStringLiteral("b") << QStringLiteral("no-ansi-background"), + app.translate("SyntaxHighlightingCLI", "Disable ANSI background for the default color.")); + parser.addOption(noAnsiEditorBg); + + QCommandLineOption unbufferedAnsi(QStringList() << QStringLiteral("U") << QStringLiteral("unbuffered"), + app.translate("SyntaxHighlightingCLI", "For ansi and ansi256Colors formats, flush the output buffer on each line.")); + parser.addOption(unbufferedAnsi); + + QCommandLineOption titleOption( + QStringList() << QStringLiteral("T") << QStringLiteral("title"), + app.translate("SyntaxHighlightingCLI", "Set HTML page's title\n(default: the filename or \"KSyntaxHighlighter\" if reading from stdin)."), + app.translate("SyntaxHighlightingCLI", "title")); + parser.addOption(titleOption); + + parser.process(app); + + Repository repo; + + if (parser.isSet(listDefs)) { + for (const auto &def : repo.definitions()) { + std::cout << qPrintable(def.name()) << std::endl; + } + return 0; + } + + if (parser.isSet(listThemes)) { + for (const auto &theme : repo.themes()) { + std::cout << qPrintable(theme.name()) << std::endl; + } + return 0; + } + + if (parser.isSet(updateDefs)) { + DefinitionDownloader downloader(&repo); + QObject::connect(&downloader, &DefinitionDownloader::informationMessage, [](const QString &msg) { + std::cout << qPrintable(msg) << std::endl; + }); + QObject::connect(&downloader, &DefinitionDownloader::done, &app, &QCoreApplication::quit); + downloader.start(); + return app.exec(); + } + + bool fromFileName = false; + QString inFileName; + if (parser.positionalArguments().size() == 1) { + fromFileName = true; + inFileName = parser.positionalArguments().at(0); + } + + Definition def; + if (parser.isSet(syntaxName)) { + const QString syntax = parser.value(syntaxName); + def = repo.definitionForName(syntax); + if (!def.isValid()) { + /* see if it's a mimetype instead */ + def = repo.definitionForMimeType(syntax); + if (!def.isValid()) { + /* see if it's a extension instead */ + def = repo.definitionForFileName(QLatin1String("f.") + syntax); + if (!def.isValid()) { + /* see if it's a filename instead */ + def = repo.definitionForFileName(syntax); + } + } + } + } else if (fromFileName) { + def = repo.definitionForFileName(inFileName); + } else { + parser.showHelp(1); + } + + if (!def.isValid()) { + std::cerr << "Unknown syntax." << std::endl; + return 1; + } + + const QString outputFormat = parser.value(outputFormatOption); + if (0 == outputFormat.compare(QLatin1String("html"), Qt::CaseInsensitive)) { + QString title; + if (parser.isSet(titleOption)) { + title = parser.value(titleOption); + } + + HtmlHighlighter highlighter; + highlighter.setDefinition(def); + highlighter.setTheme(theme(repo, parser.value(themeName), Repository::LightTheme)); + applyHighlighter(highlighter, parser, fromFileName, inFileName, outputName, title); + } else { + auto AnsiFormat = AnsiHighlighter::AnsiFormat::TrueColor; + if (0 == outputFormat.compare(QLatin1String("ansi256Colors"), Qt::CaseInsensitive)) { + AnsiFormat = AnsiHighlighter::AnsiFormat::XTerm256Color; + } else if (0 != outputFormat.compare(QLatin1String("ansi"), Qt::CaseInsensitive)) { + std::cerr << "Unknown output format." << std::endl; + return 2; + } + + AnsiHighlighter::Options options{}; + options |= parser.isSet(noAnsiEditorBg) ? AnsiHighlighter::Option::NoOptions : AnsiHighlighter::Option::UseEditorBackground; + options |= parser.isSet(unbufferedAnsi) ? AnsiHighlighter::Option::Unbuffered : AnsiHighlighter::Option::NoOptions; + if (parser.isSet(traceOption)) { + const auto traceOptions = parser.values(traceOption); + for (auto const &option : traceOptions) { + if (option == QStringLiteral("format")) { + options |= AnsiHighlighter::Option::TraceFormat; + } else if (option == QStringLiteral("region")) { + options |= AnsiHighlighter::Option::TraceRegion; + } else if (option == QStringLiteral("context")) { + options |= AnsiHighlighter::Option::TraceContext; + } else if (option == QStringLiteral("stackSize")) { + options |= AnsiHighlighter::Option::TraceStackSize; + } else if (option == QStringLiteral("all")) { + options |= AnsiHighlighter::Option::TraceAll; + } else { + std::cerr << "Unknown trace name." << std::endl; + return 2; + } + } + } + + AnsiHighlighter highlighter; + highlighter.setDefinition(def); + highlighter.setTheme(theme(repo, parser.value(themeName), Repository::DarkTheme)); + applyHighlighter(highlighter, parser, fromFileName, inFileName, outputName, AnsiFormat, options); + } + + return 0; +} diff --git a/src/libs/3rdparty/syntax-highlighting/src/indexer/CMakeLists.txt b/src/libs/3rdparty/syntax-highlighting/src/indexer/CMakeLists.txt index 77a16faf22e..cf6940b7bd5 100644 --- a/src/libs/3rdparty/syntax-highlighting/src/indexer/CMakeLists.txt +++ b/src/libs/3rdparty/syntax-highlighting/src/indexer/CMakeLists.txt @@ -4,13 +4,8 @@ if(CMAKE_CROSSCOMPILING AND KATEHIGHLIGHTINGINDEXER_EXECUTABLE) add_executable(katehighlightingindexer IMPORTED GLOBAL) set_target_properties(katehighlightingindexer PROPERTIES IMPORTED_LOCATION ${KATEHIGHLIGHTINGINDEXER_EXECUTABLE}) elseif(CMAKE_CROSSCOMPILING) - if (NOT KF5_HOST_TOOLING) - message(FATAL_ERROR "Please provide a prefix with a native Qt build and pass -DKF5_HOST_TOOLING=path") - endif() - - # search native tooling prefix - string(FIND ${KF5_HOST_TOOLING} /lib idx) - string(SUBSTRING ${KF5_HOST_TOOLING} 0 ${idx} NATIVE_PREFIX) + include(ECMQueryQt) + ecm_query_qt(NATIVE_PREFIX QT_HOST_PREFIX) message(STATUS "Building katehighlightingindexer against ${NATIVE_PREFIX}") include(ExternalProject) @@ -19,7 +14,7 @@ elseif(CMAKE_CROSSCOMPILING) CMAKE_ARGS -DKSYNTAXHIGHLIGHTING_USE_GUI=OFF -DECM_DIR=${ECM_DIR} -DCMAKE_PREFIX_PATH=${NATIVE_PREFIX} -DCMAKE_INSTALL_PREFIX=${CMAKE_CURRENT_BINARY_DIR} - -DQT_MAJOR_VERSION=${QT_MAJOR_VERSION} + -DQT_MAJOR_VERSION=6 INSTALL_COMMAND "" BUILD_BYPRODUCTS ${CMAKE_CURRENT_BINARY_DIR}/native_katehighlightingindexer-prefix/src/native_katehighlightingindexer-build/bin/katehighlightingindexer ) @@ -31,9 +26,11 @@ else() # host build add_executable(katehighlightingindexer katehighlightingindexer.cpp ../lib/worddelimiters.cpp) ecm_mark_nongui_executable(katehighlightingindexer) - if(Qt5XmlPatterns_FOUND AND NOT ECM_ENABLE_SANITIZERS) - target_link_libraries(katehighlightingindexer Qt5::XmlPatterns) + if(XercesC_FOUND) + add_definitions(-DHAS_XERCESC) + kde_target_enable_exceptions(katehighlightingindexer PRIVATE) + target_link_libraries(katehighlightingindexer Qt6::Core XercesC::XercesC) else() - target_link_libraries(katehighlightingindexer Qt${QT_MAJOR_VERSION}::Core) + target_link_libraries(katehighlightingindexer Qt6::Core) endif() endif() diff --git a/src/libs/3rdparty/syntax-highlighting/src/indexer/katehighlightingindexer.cpp b/src/libs/3rdparty/syntax-highlighting/src/indexer/katehighlightingindexer.cpp index 9c541ef1b42..787747e21c0 100644 --- a/src/libs/3rdparty/syntax-highlighting/src/indexer/katehighlightingindexer.cpp +++ b/src/libs/3rdparty/syntax-highlighting/src/indexer/katehighlightingindexer.cpp @@ -12,12 +12,167 @@ #include #include #include +#include #include #include -#ifdef QT_XMLPATTERNS_LIB -#include -#include +#ifdef HAS_XERCESC + +#include + +#include + +#include +#include + +#include +#include +#include + +#include +#include + +using namespace xercesc; + +/* + * Ideas taken from: + * + * author : Boris Kolpackov + * copyright : not copyrighted - public domain + * + * This program uses Xerces-C++ SAX2 parser to load a set of schema files + * and then to validate a set of XML documents against these schemas. To + * build this program you will need Xerces-C++ 3.0.0 or later. For more + * information, see: + * + * http://www.codesynthesis.com/~boris/blog/2010/03/15/validating-external-schemas-xerces-cxx/ + */ + +/** + * Error handler object used during xml schema validation. + */ +class CustomErrorHandler : public ErrorHandler +{ +public: + /** + * Constructor + * @param messages Pointer to the error message string to fill. + */ + CustomErrorHandler(QString *messages) + : m_messages(messages) + { + } + + /** + * Check global success/fail state. + * @return True if there was a failure, false otherwise. + */ + bool failed() const + { + return m_failed; + } + +private: + /** + * Severity classes for error messages. + */ + enum severity { s_warning, s_error, s_fatal }; + + /** + * Wrapper for warning exceptions. + * @param e Exception to handle. + */ + void warning(const SAXParseException &e) override + { + m_failed = true; // be strict, warnings are evil, too! + handle(e, s_warning); + } + + /** + * Wrapper for error exceptions. + * @param e Exception to handle. + */ + void error(const SAXParseException &e) override + { + m_failed = true; + handle(e, s_error); + } + + /** + * Wrapper for fatal error exceptions. + * @param e Exception to handle. + */ + void fatalError(const SAXParseException &e) override + { + m_failed = true; + handle(e, s_fatal); + } + + /** + * Reset the error status to "no error". + */ + void resetErrors() override + { + m_failed = false; + } + + /** + * Generic handler for error/warning/fatal error message exceptions. + * @param e Exception to handle. + * @param s Enum value encoding the message severtity. + */ + void handle(const SAXParseException &e, severity s) + { + // get id to print + const XMLCh *xid(e.getPublicId()); + if (!xid) + xid = e.getSystemId(); + + m_messages << QString::fromUtf16(xid) << ":" << e.getLineNumber() << ":" << e.getColumnNumber() << " " << (s == s_warning ? "warning: " : "error: ") + << QString::fromUtf16(e.getMessage()) << Qt::endl; + } + +private: + /** + * Storage for created error messages in this handler. + */ + QTextStream m_messages; + + /** + * Global error state. True if there was an error, false otherwise. + */ + bool m_failed = false; +}; + +void init_parser(SAX2XMLReaderImpl &parser) +{ + // Commonly useful configuration. + // + parser.setFeature(XMLUni::fgSAX2CoreNameSpaces, true); + parser.setFeature(XMLUni::fgSAX2CoreNameSpacePrefixes, true); + parser.setFeature(XMLUni::fgSAX2CoreValidation, true); + + // Enable validation. + // + parser.setFeature(XMLUni::fgXercesSchema, true); + parser.setFeature(XMLUni::fgXercesSchemaFullChecking, true); + parser.setFeature(XMLUni::fgXercesValidationErrorAsFatal, true); + + // Use the loaded grammar during parsing. + // + parser.setFeature(XMLUni::fgXercesUseCachedGrammarInParse, true); + + // Don't load schemas from any other source (e.g., from XML document's + // xsi:schemaLocation attributes). + // + parser.setFeature(XMLUni::fgXercesLoadSchema, false); + + // Xerces-C++ 3.1.0 is the first version with working multi import + // support. + // + parser.setFeature(XMLUni::fgXercesHandleMultipleImports, true); +} + #endif #include "../lib/worddelimiters_p.h" @@ -152,12 +307,10 @@ public: success = false; } - QSet referencedKeywords; QSet usedAttributeNames; QSet ignoredAttributeNames; - success = checkKeywordsList(definition, referencedKeywords) && success; - success = - checkContexts(definition, referencedKeywords, usedAttributeNames, ignoredAttributeNames, usedContexts, unreachableIncludedRules) && success; + success = checkKeywordsList(definition) && success; + success = checkContexts(definition, usedAttributeNames, ignoredAttributeNames, usedContexts, unreachableIncludedRules) && success; // search for non-existing itemDatas. const auto invalidNames = usedAttributeNames - definition.itemDatas.styleNames; @@ -362,7 +515,7 @@ private: QString content; int line; - friend uint qHash(const Item &item, uint seed = 0) + friend size_t qHash(const Item &item, size_t seed = 0) { return qHash(item.content, seed); } @@ -373,7 +526,7 @@ private: } }; - QVector keywords; + QList keywords; QSet includes; bool parseElement(const QString &filename, QXmlStreamReader &xml) @@ -486,7 +639,7 @@ private: QString weakDeliminator; // rules included by IncludeRules (without IncludeRule) - QVector includedRules; + QList includedRules; // IncludeRules included by IncludeRules QSet includedIncludeRules; @@ -683,9 +836,10 @@ private: ContextName lineEndContext; ContextName lineEmptyContext; ContextName fallthroughContext; - QVector rules; + QList rules; XmlBool dynamic{}; XmlBool fallthrough{}; + XmlBool stopEmptyLineContextSwitchLoop{}; bool parseElement(const QString &filename, QXmlStreamReader &xml) { @@ -697,12 +851,17 @@ private: Parser parser{filename, xml, attr, success}; XmlBool noIndentationBasedFolding{}; - const bool isExtracted = parser.extractString(name, QStringLiteral("name")) || parser.extractString(attribute, QStringLiteral("attribute")) + // clang-format off + const bool isExtracted = parser.extractString(name, QStringLiteral("name")) + || parser.extractString(attribute, QStringLiteral("attribute")) || parser.extractString(lineEndContext.name, QStringLiteral("lineEndContext")) || parser.extractString(lineEmptyContext.name, QStringLiteral("lineEmptyContext")) || parser.extractString(fallthroughContext.name, QStringLiteral("fallthroughContext")) - || parser.extractXmlBool(dynamic, QStringLiteral("dynamic")) || parser.extractXmlBool(fallthrough, QStringLiteral("fallthrough")) + || parser.extractXmlBool(dynamic, QStringLiteral("dynamic")) + || parser.extractXmlBool(fallthrough, QStringLiteral("fallthrough")) + || parser.extractXmlBool(stopEmptyLineContextSwitchLoop, QStringLiteral("stopEmptyLineContextSwitchLoop")) || parser.extractXmlBool(noIndentationBasedFolding, QStringLiteral("noIndentationBasedFolding")); + // clang-format on success = parser.checkIfExtracted(isExtracted); } @@ -717,11 +876,6 @@ private: success = false; } - if (lineEndContext.name.isEmpty()) { - qWarning() << filename << "line" << xml.lineNumber() << "missing attribute: lineEndContext"; - success = false; - } - return success; } }; @@ -747,7 +901,7 @@ private: QString name; int line; - friend uint qHash(const Style &style, uint seed = 0) + friend size_t qHash(const Style &style, size_t seed = 0) { return qHash(style.name, seed); } @@ -802,7 +956,6 @@ private: const Context *firstContext = nullptr; QString filename; WordDelimiters wordDelimiters; - XmlBool casesensitive{}; Version kateVersion{}; QString kateVersionStr; QString languageName; @@ -865,7 +1018,7 @@ private: void resolveIncludeRules() { QSet usedContexts; - QVector contexts; + QList contexts; QMutableMapIterator def(m_definitions); while (def.hasNext()) { @@ -936,7 +1089,7 @@ private: QSet extractUsedContexts() const { QSet usedContexts; - QVector contexts; + QList contexts; QMapIterator def(m_definitions); while (def.hasNext()) { @@ -982,13 +1135,12 @@ private: }; struct IncludedRuleUnreachableBy { - QVector unreachableBy; + QList unreachableBy; bool alwaysUnreachable = true; }; //! Check contexts and rules bool checkContexts(const Definition &definition, - QSet &referencedKeywords, QSet &usedAttributeNames, QSet &ignoredAttributeNames, const QSet &usedContexts, @@ -1018,7 +1170,7 @@ private: usedAttributeNames.insert({context.attribute, context.line}); } - success = checkfallthrough(definition, context) && success; + success = checkContextAttribute(definition, context) && success; success = checkUreachableRules(definition.filename, context, unreachableIncludedRules) && success; success = suggestRuleMerger(definition.filename, context) && success; @@ -1032,7 +1184,7 @@ private: } success = checkLookAhead(rule) && success; success = checkStringDetect(rule) && success; - success = checkKeyword(definition, rule, referencedKeywords) && success; + success = checkKeyword(definition, rule) && success; success = checkRegExpr(filename, rule, context) && success; success = checkDelimiters(definition, rule) && success; } @@ -1047,12 +1199,13 @@ private: //! - dynamic=true but no place holder used? //! - is not . with lookAhead="1" //! - is not ^... without column ou firstNonSpace attribute - //! - is not equivalent to DetectSpaces, DetectChar, Detect2Chars, StringDetect, DetectIdentifier, RangeDetect + //! - is not equivalent to DetectSpaces, DetectChar, Detect2Chars, StringDetect, DetectIdentifier, RangeDetect, LineContinue or AnyChar //! - has no unused captures //! - has no unnecessary quantifier with lookAhead bool checkRegExpr(const QString &filename, const Context::Rule &rule, const Context &context) const { - if (rule.type == Context::Rule::Type::RegExpr) { + // ignore empty regex because the error is raised during xml parsing + if (rule.type == Context::Rule::Type::RegExpr && !rule.string.isEmpty()) { const QRegularExpression regexp(rule.string); if (!checkRegularExpression(rule.filename, regexp, rule.line)) { return false; @@ -1092,13 +1245,21 @@ private: // is RangeDetect static const QRegularExpression isRange(QStringLiteral("^\\^?" REG_CHAR "(?:" - "\\.\\*[?*]?" REG_CHAR "|" - "\\[\\^(" REG_ESCAPE_CHAR "|.)\\]\\*[?*]?\\1" + "\\.\\*[?+]?" REG_CHAR "|" + "\\[\\^(" REG_ESCAPE_CHAR "|.)\\]\\*[?+]?\\1" ")$")); if ((rule.lookAhead == XmlBool::True || rule.minimal == XmlBool::True || rule.string.contains(QStringLiteral(".*?")) || rule.string.contains(QStringLiteral("[^"))) && reg.contains(isRange)) { - qWarning() << filename << "line" << rule.line << "RegExpr should be replaced by RangeDetect:" << rule.string; + qWarning() << rule.filename << "line" << rule.line << "RegExpr should be replaced by RangeDetect:" << rule.string; + return false; + } + + // is AnyChar + static const QRegularExpression isAnyChar(QStringLiteral(R"(^(\^|\((\?:)?)*\[(?!\^)[-\]]?(\\[^0BDPSWbdpswoux]|[^-\]\\])*\]\)*$)")); + if (rule.string.contains(isAnyChar)) { + auto extra = (reg[0] == QLatin1Char('^') || reg[1] == QLatin1Char('^')) ? "with column=\"0\"" : ""; + qWarning() << rule.filename << "line" << rule.line << "RegExpr should be replaced by AnyChar:" << rule.string << extra; return false; } @@ -1106,7 +1267,7 @@ private: static const QRegularExpression isLineContinue(QStringLiteral("^\\^?" REG_CHAR "\\$$")); if (reg.contains(isLineContinue)) { auto extra = (reg[0] == QLatin1Char('^')) ? "with column=\"0\"" : ""; - qWarning() << filename << "line" << rule.line << "RegExpr should be replaced by LineContinue:" << rule.string << extra; + qWarning() << rule.filename << "line" << rule.line << "RegExpr should be replaced by LineContinue:" << rule.string << extra; return false; } @@ -1124,7 +1285,7 @@ private: if (rule.lookAhead == XmlBool::True && rule.minimal != XmlBool::True && reg.contains(isMinimal) && !reg.contains(hasNotGreedy) && (!rule.context.context || !rule.context.context->hasDynamicRule || regexp.captureCount() == 0) && (reg.back() != QLatin1Char('$') || reg.contains(QLatin1Char('|')))) { - qWarning() << filename << "line" << rule.line + qWarning() << rule.filename << "line" << rule.line << "RegExpr should be have minimal=\"1\" or use lazy operator (i.g, '.*' -> '.*?'):" << rule.string; return false; } @@ -1160,8 +1321,8 @@ private: return false; } - // column="0" or firstNonSpace="1" - if (rule.column == -1 && rule.firstNonSpace != XmlBool::True) { + // column="0" + if (rule.column == -1) { // ^ without | // (^sas*) -> ok // (^sa|s*) -> ko @@ -1204,7 +1365,7 @@ private: } if (replace) { - qWarning() << rule.filename << "line" << rule.line << "column=\"0\" or firstNonSpace=\"1\" missing with RegExpr:" << rule.string; + qWarning() << rule.filename << "line" << rule.line << "column=\"0\" missing with RegExpr:" << rule.string; return false; } } @@ -1306,11 +1467,8 @@ private: if (!useCapture) { // is DetectIdentifier - static const QRegularExpression isInsensitiveDetectIdentifier( - QStringLiteral(R"(^(\((\?:)?)?\[((a-z|_){2}|(A-Z|_){2})\]([+][*?]?)?\[((0-9|a-z|_){3}|(0-9|A-Z|_){3})\][*][*?]?(\))?$)")); - static const QRegularExpression isSensitiveDetectIdentifier( - QStringLiteral(R"(^(\((\?:)?)?\[(a-z|A-Z|_){3}\]([+][*?]?)?\[(0-9|a-z|A-Z|_){4}\][*][*?]?(\))?$)")); - auto &isDetectIdentifier = (rule.insensitive == XmlBool::True) ? isInsensitiveDetectIdentifier : isSensitiveDetectIdentifier; + static const QRegularExpression isDetectIdentifier( + QStringLiteral(R"(^(\((\?:)?|\^)*\[(\\p\{L\}|_){2}\]([+][?+]?)?\[(\\p\{N\}|\\p\{L\}|_){3}\][*][?+]?\)*$)")); if (rule.string.contains(isDetectIdentifier)) { qWarning() << rule.filename << "line" << rule.line << "RegExpr should be replaced by DetectIdentifier:" << rule.string; return false; @@ -1357,7 +1515,7 @@ private: static const QRegularExpression unnecessaryQuantifier2(QStringLiteral(R"([*+?]([.][*+?]{0,2})?[)]*$)")); auto &unnecessaryQuantifier = useCapture ? unnecessaryQuantifier1 : unnecessaryQuantifier2; if (rule.lookAhead == XmlBool::True && rule.minimal != XmlBool::True && reg.contains(unnecessaryQuantifier)) { - qWarning() << filename << "line" << rule.line + qWarning() << rule.filename << "line" << rule.line << "Last quantifier is not necessary (i.g., 'xyz*' -> 'xy', 'xyz+.' -> 'xyz.'):" << rule.string; return false; } @@ -1418,19 +1576,13 @@ private: return true; } - //! Search for rules with lookAhead="true" and context="#stay". - //! This would cause an infinite loop. - bool checkfallthrough(const Definition &definition, const Context &context) const + //! Check fallthrough and fallthroughContext. + //! Check kateversion for stopEmptyLineContextSwitchLoop. + bool checkContextAttribute(const Definition &definition, const Context &context) const { bool success = true; if (!context.fallthroughContext.name.isEmpty()) { - if (context.fallthroughContext.stay) { - qWarning() << definition.filename << "line" << context.line << "possible infinite loop due to fallthroughContext=\"#stay\" in context " - << context.name; - success = false; - } - const bool mandatoryFallthroughAttribute = definition.kateVersion < Version{5, 62}; if (context.fallthrough == XmlBool::True && !mandatoryFallthroughAttribute) { qWarning() << definition.filename << "line" << context.line << "fallthrough attribute is unnecessary with kateversion >= 5.62 in context" @@ -1444,6 +1596,12 @@ private: } } + if (context.stopEmptyLineContextSwitchLoop != XmlBool::Unspecified && definition.kateVersion < Version{5, 103}) { + qWarning() << definition.filename << "line" << context.line + << "stopEmptyLineContextSwitchLoop attribute is only valid with kateversion >= 5.103 in context" << context.name; + success = false; + } + return success; } @@ -1478,15 +1636,12 @@ private: return false; } - //! Search for rules with lookAhead="true" and context="#stay". - //! This would cause an infinite loop. - bool checkKeyword(const Definition &definition, const Context::Rule &rule, QSet &referencedKeywords) const + //! Check that keyword rule reference an existing keyword list. + bool checkKeyword(const Definition &definition, const Context::Rule &rule) const { if (rule.type == Context::Rule::Type::keyword) { auto it = definition.keywordsList.find(rule.string); - if (it != definition.keywordsList.end()) { - referencedKeywords.insert(&*it); - } else { + if (it == definition.keywordsList.end()) { qWarning() << rule.filename << "line" << rule.line << "reference of non-existing keyword list:" << rule.string; return false; } @@ -1504,13 +1659,7 @@ private: return true; } - //! Check that StringDetect contains more that 2 characters - //! Fix with following command: - //! \code - //! sed -E - //! '/StringDetect/{/dynamic="(1|true)|insensitive="(1|true)/!{s/StringDetect(.*)String="(.|<|>|"|&)(.|<|>|"|&)"/Detect2Chars\1char="\2" - //! char1="\3"/;t;s/StringDetect(.*)String="(.|<|>|"|&)"/DetectChar\1char="\2"/}}' -i file.xml... - //! \endcode + //! Check that StringDetect contains a placeHolder when dynamic="1" bool checkStringDetect(const Context::Rule &rule) const { if (rule.type == Context::Rule::Type::StringDetect) { @@ -1527,7 +1676,7 @@ private: } //! Check \ and delimiter in a keyword list - bool checkKeywordsList(const Definition &definition, QSet &referencedKeywords) const + bool checkKeywordsList(const Definition &definition) const { bool success = true; @@ -1542,7 +1691,7 @@ private: << " is only available since version \"5.53\". Please, increase kateversion."; success = false; } - success = checkKeywordInclude(definition, include, referencedKeywords) && success; + success = checkKeywordInclude(definition, include) && success; } // Check that keyword list items do not have deliminator character @@ -1562,16 +1711,13 @@ private: } //! Search for non-existing keyword include. - bool checkKeywordInclude(const Definition &definition, const Keywords::Items::Item &include, QSet &referencedKeywords) const + bool checkKeywordInclude(const Definition &definition, const Keywords::Items::Item &include) const { bool containsKeywordName = true; int const idx = include.content.indexOf(QStringLiteral("##")); if (idx == -1) { auto it = definition.keywordsList.find(include.content); containsKeywordName = (it != definition.keywordsList.end()); - if (containsKeywordName) { - referencedKeywords.insert(&*it); - } } else { auto defName = include.content.mid(idx + 2); auto listName = include.content.left(idx); @@ -1644,10 +1790,10 @@ private: } /// Search RuleAndInclude associated with the characters of @p s. - /// \return an empty QVector when at least one character is not found. - QVector find(QStringView s) const + /// \return an empty QList when at least one character is not found. + QList find(QStringView s) const { - QVector result; + QList result; for (QChar c : s) { if (!find(c)) { @@ -1731,8 +1877,8 @@ private: } /// Search RuleAndInclude associated with the characters of @p s. - /// \return an empty QVector when at least one character is not found. - QVector find(QStringView s) const + /// \return an empty QList when at least one character is not found. + QList find(QStringView s) const { for (int i = 0; i < m_size; ++i) { auto result = m_charTables[i]->find(s); @@ -1743,7 +1889,7 @@ private: return result; } } - return QVector(); + return QList(); } /// Associates @p c with a rule. @@ -1785,7 +1931,7 @@ private: // Iterates over all the rules, including those in includedRules struct RuleIterator { - RuleIterator(const QVector &rules, const ObservableRule &endRule) + RuleIterator(const QList &rules, const ObservableRule &endRule) : m_end(&endRule - rules.data()) , m_rules(rules) { @@ -1830,10 +1976,10 @@ private: private: int m_i = 0; - int m_i2; - int m_end; - const QVector &m_rules; - const QVector *m_includedRules = nullptr; + int m_i2 = 0; + const int m_end; + const QList &m_rules; + const QList *m_includedRules = nullptr; }; // Dot regex container that satisfies firstNonSpace and column. @@ -1915,7 +2061,7 @@ private: DotRegex dotRegex; - QVector observedRules; + QList observedRules; observedRules.reserve(context.rules.size()); for (const Context::Rule &rule : context.rules) { const Context::Rule *includeRule = nullptr; @@ -1937,7 +2083,7 @@ private: for (auto &observedRule : observedRules) { const Context::Rule &rule = *observedRule.rule; bool isUnreachable = false; - QVector unreachableBy; + QList unreachableBy; // declare rule as unreachable if ruleAndInclude is not empty auto updateUnreachable1 = [&](RuleAndInclude ruleAndInclude) { @@ -1948,7 +2094,7 @@ private: }; // declare rule as unreachable if ruleAndIncludes is not empty - auto updateUnreachable2 = [&](const QVector &ruleAndIncludes) { + auto updateUnreachable2 = [&](const QList &ruleAndIncludes) { if (!ruleAndIncludes.isEmpty()) { isUnreachable = true; unreachableBy.append(ruleAndIncludes); @@ -2030,6 +2176,8 @@ private: case Context::Rule::Type::Float: updateUnreachable2(CharTableArray(detectChars, rule).find(QStringLiteral("0123456789."))); updateUnreachable1(floatRule.setRule(rule)); + // check that Float is before Int + updateUnreachable1(Rule4(intRule).setRule(rule)); break; // check if hidden by another DetectIdentifier rule @@ -2629,12 +2777,32 @@ int main(int argc, char *argv[]) return 1; } -#ifdef QT_XMLPATTERNS_LIB - // open schema - QXmlSchema schema; - if (!schema.load(QUrl::fromLocalFile(app.arguments().at(2)))) { +#ifdef HAS_XERCESC + // care for proper init and cleanup + XMLPlatformUtils::Initialize(); + auto cleanup = qScopeGuard(XMLPlatformUtils::Terminate); + + /* + * parse XSD first time and cache it + */ + XMLGrammarPoolImpl xsd(XMLPlatformUtils::fgMemoryManager); + + // create parser for the XSD + SAX2XMLReaderImpl parser(XMLPlatformUtils::fgMemoryManager, &xsd); + init_parser(parser); + QString messages; + CustomErrorHandler eh(&messages); + parser.setErrorHandler(&eh); + + // load grammar into the pool, on error just abort + const auto xsdFile = app.arguments().at(2); + if (!parser.loadGrammar((const char16_t *)xsdFile.utf16(), Grammar::SchemaGrammarType, true) || eh.failed()) { + qWarning("Failed to parse XSD %s: %s", qPrintable(xsdFile), qPrintable(messages)); return 2; } + + // lock the pool, no later modifications wanted! + xsd.lockPool(); #endif const QString hlFilenamesListing = app.arguments().value(3); @@ -2665,10 +2833,20 @@ int main(int argc, char *argv[]) continue; } -#ifdef QT_XMLPATTERNS_LIB - // validate against schema - QXmlSchemaValidator validator(schema); - if (!validator.validate(&hlFile, QUrl::fromLocalFile(hlFile.fileName()))) { +#ifdef HAS_XERCESC + // create parser + SAX2XMLReaderImpl parser(XMLPlatformUtils::fgMemoryManager, &xsd); + init_parser(parser); + QString messages; + CustomErrorHandler eh(&messages); + parser.setErrorHandler(&eh); + + // parse the XML file + parser.parse((const char16_t *)hlFile.fileName().utf16()); + + // report issues + if (eh.failed()) { + qWarning("Failed to validate XML %s: %s", qPrintable(hlFile.fileName()), qPrintable(messages)); anyError = 4; continue; } @@ -2708,6 +2886,10 @@ int main(int argc, char *argv[]) // add boolean one hl[QStringLiteral("hidden")] = attrToBool(xml.attributes().value(QLatin1String("hidden"))); + // keep some strings as UTF-8 for faster translations + hl[QStringLiteral("nameUtf8")] = hl[QStringLiteral("name")].toString().toUtf8(); + hl[QStringLiteral("sectionUtf8")] = hl[QStringLiteral("section")].toString().toUtf8(); + // remember hl hls[QFileInfo(hlFile).fileName()] = hl; diff --git a/src/libs/3rdparty/syntax-highlighting/src/lib/CMakeLists.txt b/src/libs/3rdparty/syntax-highlighting/src/lib/CMakeLists.txt index fe89fdd715e..2b2845eba4d 100644 --- a/src/libs/3rdparty/syntax-highlighting/src/lib/CMakeLists.txt +++ b/src/libs/3rdparty/syntax-highlighting/src/lib/CMakeLists.txt @@ -1,8 +1,14 @@ -add_library(KF5SyntaxHighlighting) +add_library(KF6SyntaxHighlighting) -ecm_create_qm_loader(syntax_highlighting_QM_LOADER syntaxhighlighting5_qt) +set_target_properties(KF6SyntaxHighlighting PROPERTIES + VERSION ${KSYNTAXHIGHLIGHTING_VERSION} + SOVERSION ${KSYNTAXHIGHLIGHTING_SOVERSION} + EXPORT_NAME SyntaxHighlighting +) + +ecm_create_qm_loader(syntax_highlighting_QM_LOADER syntaxhighlighting6_qt) -target_sources(KF5SyntaxHighlighting PRIVATE +target_sources(KF6SyntaxHighlighting PRIVATE abstracthighlighter.cpp context.cpp contextswitch.cpp @@ -25,7 +31,7 @@ target_sources(KF5SyntaxHighlighting PRIVATE ${syntax_highlighting_QM_LOADER} $ ) -ecm_qt_declare_logging_category(KF5SyntaxHighlighting +ecm_qt_declare_logging_category(KF6SyntaxHighlighting HEADER ksyntaxhighlighting_logging.h IDENTIFIER KSyntaxHighlighting::Log CATEGORY_NAME kf.syntaxhighlighting @@ -34,25 +40,21 @@ ecm_qt_declare_logging_category(KF5SyntaxHighlighting EXPORT KSYNTAXHIGHLIGHTING ) -ecm_generate_export_header(KF5SyntaxHighlighting +ecm_generate_export_header(KF6SyntaxHighlighting BASE_NAME KSyntaxHighlighting GROUP_BASE_NAME KF VERSION ${KF_VERSION} + USE_VERSION_HEADER DEPRECATED_BASE_VERSION 0 - DEPRECATION_VERSIONS 5.87 + DEPRECATION_VERSIONS EXCLUDE_DEPRECATED_BEFORE_AND_AT ${EXCLUDE_DEPRECATED_BEFORE_AND_AT} ) -set_target_properties(KF5SyntaxHighlighting PROPERTIES - VERSION ${SyntaxHighlighting_VERSION} - SOVERSION ${SyntaxHighlighting_SOVERSION} - EXPORT_NAME SyntaxHighlighting -) -target_link_libraries(KF5SyntaxHighlighting +target_link_libraries(KF6SyntaxHighlighting PUBLIC - Qt${QT_MAJOR_VERSION}::Gui + Qt6::Gui PRIVATE - Qt${QT_MAJOR_VERSION}::Network + Qt6::Network ) set(Forwarding_Header_Names @@ -74,12 +76,12 @@ ecm_generate_headers(CamelCase_HEADERS OUTPUT_DIR ${CMAKE_BINARY_DIR}/KSyntaxHighlighting/KSyntaxHighlighting ) -target_include_directories(KF5SyntaxHighlighting +target_include_directories(KF6SyntaxHighlighting INTERFACE "$" PUBLIC "$" ) -install(TARGETS KF5SyntaxHighlighting EXPORT KF5SyntaxHighlightingTargets ${KDE_INSTALL_TARGETS_DEFAULT_ARGS}) +install(TARGETS KF6SyntaxHighlighting EXPORT KF6SyntaxHighlightingTargets ${KDE_INSTALL_TARGETS_DEFAULT_ARGS}) install(FILES ${CamelCase_HEADERS} @@ -90,17 +92,17 @@ install(FILES if(BUILD_QCH) ecm_add_qch( - KF5SyntaxHighlighting_QCH + KF6SyntaxHighlighting_QCH NAME KSyntaxHighlighting - BASE_NAME KF5SyntaxHighlighting + BASE_NAME KF6SyntaxHighlighting VERSION ${KF_VERSION} ORG_DOMAIN org.kde SOURCES # using only public headers, to cover only public API ${SyntaxHighlighting_HEADERS} MD_MAINPAGE "${CMAKE_SOURCE_DIR}/README.md" LINK_QCHS - Qt5Core_QCH - Qt5Gui_QCH + Qt6Core_QCH + Qt6Gui_QCH INCLUDE_DIRS ${CMAKE_CURRENT_BINARY_DIR} BLANK_MACROS @@ -111,11 +113,3 @@ if(BUILD_QCH) COMPONENT Devel ) endif() -ecm_generate_pri_file( - BASE_NAME KSyntaxHighlighting LIB_NAME - KF5SyntaxHighlighting - DEPS "gui" - FILENAME_VAR PRI_FILENAME - INCLUDE_INSTALL_DIR ${KDE_INSTALL_INCLUDEDIR_KF}/KSyntaxHighlighting -) -install(FILES ${PRI_FILENAME} DESTINATION ${ECM_MKSPECS_INSTALL_DIR}) diff --git a/src/libs/3rdparty/syntax-highlighting/src/lib/abstracthighlighter.cpp b/src/libs/3rdparty/syntax-highlighting/src/lib/abstracthighlighter.cpp index ac5d98abfb3..87dabadc7b1 100644 --- a/src/libs/3rdparty/syntax-highlighting/src/lib/abstracthighlighter.cpp +++ b/src/libs/3rdparty/syntax-highlighting/src/lib/abstracthighlighter.cpp @@ -12,6 +12,7 @@ #include "format.h" #include "ksyntaxhighlighting_logging.h" #include "repository.h" +#include "repository_p.h" #include "rule_p.h" #include "state.h" #include "state_p.h" @@ -97,13 +98,6 @@ static inline int firstNonSpaceChar(QStringView text) return text.size(); } -#if KSYNTAXHIGHLIGHTING_BUILD_DEPRECATED_SINCE(5, 87) -State AbstractHighlighter::highlightLine(const QString &text, const State &state) -{ - return highlightLine(QStringView(text), state); -} -#endif - State AbstractHighlighter::highlightLine(QStringView text, const State &state) { Q_D(AbstractHighlighter); @@ -116,43 +110,47 @@ State AbstractHighlighter::highlightLine(QStringView text, const State &state) return State(); } + // limit the cache for unification to some reasonable size + // we use here at the moment 64k elements to not hog too much memory + // and to make the clearing no big stall + if (defData->unify.size() > 64 * 1024) + defData->unify.clear(); + // verify/initialize state auto newState = state; auto stateData = StateData::get(newState); - const auto definitionId = DefinitionData::get(d->m_definition)->id; - if (!stateData->isEmpty() && stateData->m_defId != definitionId) { + bool isSharedData = true; + if (Q_UNLIKELY(stateData && stateData->m_defId != defData->id)) { qCDebug(Log) << "Got invalid state, resetting."; - stateData->clear(); + stateData = nullptr; } - if (stateData->isEmpty()) { + if (Q_UNLIKELY(!stateData)) { + stateData = StateData::reset(newState); stateData->push(defData->initialContext(), QStringList()); - stateData->m_defId = definitionId; + stateData->m_defId = defData->id; + isSharedData = false; } // process empty lines - if (text.isEmpty()) { + if (Q_UNLIKELY(text.isEmpty())) { /** * handle line empty context switches * guard against endless loops * see https://phabricator.kde.org/D18509 */ int endlessLoopingCounter = 0; - while (!stateData->topContext()->lineEmptyContext().isStay() || !stateData->topContext()->lineEndContext().isStay()) { + while (!stateData->topContext()->lineEmptyContext().isStay()) { /** * line empty context switches */ - if (!stateData->topContext()->lineEmptyContext().isStay()) { - if (!d->switchContext(stateData, stateData->topContext()->lineEmptyContext(), QStringList())) { - /** - * end when trying to #pop the main context - */ - break; - } + if (!d->switchContext(stateData, stateData->topContext()->lineEmptyContext(), QStringList(), newState, isSharedData)) { /** - * line end context switches only when lineEmptyContext is #stay. This avoids - * skipping empty lines after a line continuation character (see bug 405903) + * end when trying to #pop the main context */ - } else if (!d->switchContext(stateData, stateData->topContext()->lineEndContext(), QStringList())) { + break; + } + + if (stateData->topContext()->stopEmptyLineContextSwitchLoop()) { break; } @@ -165,9 +163,11 @@ State AbstractHighlighter::highlightLine(QStringView text, const State &state) } auto context = stateData->topContext(); applyFormat(0, 0, context->attributeFormat()); - return newState; + return *defData->unify.insert(newState); } + auto &dynamicRegexpCache = RepositoryPrivate::get(defData->repo)->m_dynamicRegexpCache; + int offset = 0; int beginOffset = 0; bool lineContinuation = false; @@ -178,10 +178,10 @@ State AbstractHighlighter::highlightLine(QStringView text, const State &state) * - store the result of the first position that matches (or -1 for no match in the full line) in the skipOffsets hash for re-use * - have capturesForLastDynamicSkipOffset as guard for dynamic regexes to invalidate the cache if they might have changed */ - QVarLengthArray, 8> skipOffsets; + QVarLengthArray, 8> skipOffsets; QStringList capturesForLastDynamicSkipOffset; - auto getSkipOffsetValue = [&skipOffsets](Rule *r) -> int { + auto getSkipOffsetValue = [&skipOffsets](const Rule *r) -> int { auto i = std::find_if(skipOffsets.begin(), skipOffsets.end(), [r](const auto &v) { return v.first == r; }); @@ -190,7 +190,7 @@ State AbstractHighlighter::highlightLine(QStringView text, const State &state) return i->second; }; - auto insertSkipOffset = [&skipOffsets](Rule *r, int i) { + auto insertSkipOffset = [&skipOffsets](const Rule *r, int i) { auto it = std::find_if(skipOffsets.begin(), skipOffsets.end(), [r](const auto &v) { return v.first == r; }); @@ -237,7 +237,8 @@ State AbstractHighlighter::highlightLine(QStringView text, const State &state) bool isLookAhead = false; int newOffset = 0; const Format *newFormat = nullptr; - for (const auto &rule : stateData->topContext()->rules()) { + for (const auto &ruleShared : stateData->topContext()->rules()) { + auto rule = ruleShared.get(); /** * filter out rules that require a specific column */ @@ -265,29 +266,33 @@ State AbstractHighlighter::highlightLine(QStringView text, const State &state) } } - /** - * shall we skip application of this rule? two cases: - * - rule can't match at all => currentSkipOffset < 0 - * - rule will only match for some higher offset => currentSkipOffset > offset - * - * we need to invalidate this if we are dynamic and have different captures then last time - */ - if (rule->isDynamic() && (capturesForLastDynamicSkipOffset != stateData->topCaptures())) { - skipOffsets.clear(); - } - const auto currentSkipOffset = getSkipOffsetValue(rule.get()); - if (currentSkipOffset < 0 || currentSkipOffset > offset) { - continue; + int currentSkipOffset = 0; + if (Q_UNLIKELY(rule->hasSkipOffset())) { + /** + * shall we skip application of this rule? two cases: + * - rule can't match at all => currentSkipOffset < 0 + * - rule will only match for some higher offset => currentSkipOffset > offset + * + * we need to invalidate this if we are dynamic and have different captures then last time + */ + if (rule->isDynamic() && (capturesForLastDynamicSkipOffset != stateData->topCaptures())) { + skipOffsets.clear(); + } else { + currentSkipOffset = getSkipOffsetValue(rule); + if (currentSkipOffset < 0 || currentSkipOffset > offset) { + continue; + } + } } - const auto newResult = rule->doMatch(text, offset, stateData->topCaptures()); + auto newResult = rule->doMatch(text, offset, stateData->topCaptures(), dynamicRegexpCache); newOffset = newResult.offset(); /** * update skip offset if new one rules out any later match or is larger than current one */ if (newResult.skipOffset() < 0 || newResult.skipOffset() > currentSkipOffset) { - insertSkipOffset(rule.get(), newResult.skipOffset()); + insertSkipOffset(rule, newResult.skipOffset()); // remember new captures, if dynamic to enforce proper reset above on change! if (rule->isDynamic()) { @@ -316,12 +321,12 @@ State AbstractHighlighter::highlightLine(QStringView text, const State &state) if (rule->isLookAhead()) { Q_ASSERT(!rule->context().isStay()); - d->switchContext(stateData, rule->context(), newResult.captures()); + d->switchContext(stateData, rule->context(), std::move(newResult.captures()), newState, isSharedData); isLookAhead = true; break; } - d->switchContext(stateData, rule->context(), newResult.captures()); + d->switchContext(stateData, rule->context(), std::move(newResult.captures()), newState, isSharedData); newFormat = rule->attributeFormat().isValid() ? &rule->attributeFormat() : &stateData->topContext()->attributeFormat(); if (newOffset == text.size() && rule->isLineContinue()) { lineContinuation = true; @@ -334,7 +339,7 @@ State AbstractHighlighter::highlightLine(QStringView text, const State &state) if (newOffset <= offset) { // no matching rule if (stateData->topContext()->fallthrough()) { - d->switchContext(stateData, stateData->topContext()->fallthroughContext(), QStringList()); + d->switchContext(stateData, stateData->topContext()->fallthroughContext(), QStringList(), newState, isSharedData); continue; } @@ -381,7 +386,7 @@ State AbstractHighlighter::highlightLine(QStringView text, const State &state) { int endlessLoopingCounter = 0; while (!stateData->topContext()->lineEndContext().isStay() && !lineContinuation) { - if (!d->switchContext(stateData, stateData->topContext()->lineEndContext(), QStringList())) { + if (!d->switchContext(stateData, stateData->topContext()->lineEndContext(), QStringList(), newState, isSharedData)) { break; } @@ -394,18 +399,30 @@ State AbstractHighlighter::highlightLine(QStringView text, const State &state) } } - return newState; + return *defData->unify.insert(newState); } -bool AbstractHighlighterPrivate::switchContext(StateData *data, const ContextSwitch &contextSwitch, const QStringList &captures) +bool AbstractHighlighterPrivate::switchContext(StateData *&data, const ContextSwitch &contextSwitch, QStringList &&captures, State &state, bool &isSharedData) { + const auto popCount = contextSwitch.popCount(); + const auto context = contextSwitch.context(); + if (popCount <= 0 && !context) { + return true; + } + + // a modified state must be detached before modification + if (isSharedData) { + data = StateData::detach(state); + isSharedData = false; + } + // kill as many items as requested from the stack, will always keep the initial context alive! - const bool initialContextSurvived = data->pop(contextSwitch.popCount()); + const bool initialContextSurvived = data->pop(popCount); // if we have a new context to add, push it // then we always "succeed" - if (contextSwitch.context()) { - data->push(contextSwitch.context(), captures); + if (context) { + data->push(context, std::move(captures)); return true; } diff --git a/src/libs/3rdparty/syntax-highlighting/src/lib/abstracthighlighter.h b/src/libs/3rdparty/syntax-highlighting/src/lib/abstracthighlighter.h index 49cfbf25303..676a0f522ab 100644 --- a/src/libs/3rdparty/syntax-highlighting/src/lib/abstracthighlighter.h +++ b/src/libs/3rdparty/syntax-highlighting/src/lib/abstracthighlighter.h @@ -7,20 +7,15 @@ #ifndef KSYNTAXHIGHLIGHTING_ABSTRACTHIGHLIGHTERM_H #define KSYNTAXHIGHLIGHTING_ABSTRACTHIGHLIGHTERM_H +#include "definition.h" #include "ksyntaxhighlighting_export.h" #include - -#include - -QT_BEGIN_NAMESPACE -class QString; -QT_END_NAMESPACE +#include namespace KSyntaxHighlighting { class AbstractHighlighterPrivate; -class Definition; class FoldingRegion; class Format; class State; @@ -106,21 +101,8 @@ public: protected: AbstractHighlighter(); - AbstractHighlighter(AbstractHighlighterPrivate *dd); + KSYNTAXHIGHLIGHTING_NO_EXPORT explicit AbstractHighlighter(AbstractHighlighterPrivate *dd); -#if KSYNTAXHIGHLIGHTING_ENABLE_DEPRECATED_SINCE(5, 87) - /** - * @copydoc highlightLine(QStringView,const State&) - * @deprecated since 5.87, use highlightLine(QStringView, const State&) instead. - */ - // no deprecation warning, as removal of this will automatically "port" the using code - State highlightLine(const QString &text, const State &state); -#endif - - // TODO KF6: add an optional void* context argument that is passed through - // to the applyX() calls, so highlighters dealing with some form of line object - // (such as QSyntaxHighlighter or KTextEditor) can avoid some ugly hacks to have - // this context available in their applyX methods /** * Highlight the given line. Call this from your derived class * where appropriate. This will result in any number of applyFormat() diff --git a/src/libs/3rdparty/syntax-highlighting/src/lib/abstracthighlighter_p.h b/src/libs/3rdparty/syntax-highlighting/src/lib/abstracthighlighter_p.h index 6128beccfa0..04ac9898f8c 100644 --- a/src/libs/3rdparty/syntax-highlighting/src/lib/abstracthighlighter_p.h +++ b/src/libs/3rdparty/syntax-highlighting/src/lib/abstracthighlighter_p.h @@ -14,6 +14,7 @@ namespace KSyntaxHighlighting { class ContextSwitch; class StateData; +class State; class AbstractHighlighterPrivate { @@ -22,7 +23,7 @@ public: virtual ~AbstractHighlighterPrivate(); void ensureDefinitionLoaded(); - bool switchContext(StateData *data, const ContextSwitch &contextSwitch, const QStringList &captures); + bool switchContext(StateData *&data, const ContextSwitch &contextSwitch, QStringList &&captures, State &state, bool &isSharedData); Definition m_definition; Theme m_theme; diff --git a/src/libs/3rdparty/syntax-highlighting/src/lib/ansihighlighter.cpp b/src/libs/3rdparty/syntax-highlighting/src/lib/ansihighlighter.cpp index 31678018f9f..e9bea02d1c7 100644 --- a/src/libs/3rdparty/syntax-highlighting/src/lib/ansihighlighter.cpp +++ b/src/libs/3rdparty/syntax-highlighting/src/lib/ansihighlighter.cpp @@ -5,6 +5,7 @@ */ #include "ansihighlighter.h" +#include "abstracthighlighter_p.h" #include "context_p.h" #include "definition.h" #include "definition_p.h" @@ -18,6 +19,7 @@ #include #include #include +#include #include #include @@ -783,7 +785,7 @@ GraphLine &lineAtOffset(std::vector &graphLines, int offset) } // disable bold, italic and underline on | -const QLatin1String graphSymbol("\x1b[21;23;24m|"); +const QLatin1String graphSymbol("\x1b[22;23;24m|"); // reverse video const QLatin1String nameStyle("\x1b[7m"); @@ -793,8 +795,8 @@ const QLatin1String nameStyle("\x1b[7m"); class DebugSyntaxHighlighter : public KSyntaxHighlighting::AbstractHighlighter { public: - using TraceOption = KSyntaxHighlighting::AnsiHighlighter::TraceOption; - using TraceOptions = KSyntaxHighlighting::AnsiHighlighter::TraceOptions; + using Option = KSyntaxHighlighting::AnsiHighlighter::Option; + using Options = KSyntaxHighlighting::AnsiHighlighter::Options; void setDefinition(const KSyntaxHighlighting::Definition &def) override { @@ -815,14 +817,14 @@ public: QLatin1String infoStyle, QLatin1String editorBackground, const std::vector> &ansiStyles, - TraceOptions traceOptions) + Options options) { initRegionStyles(ansiStyles); - m_hasFormatTrace = traceOptions.testFlag(TraceOption::Format); - m_hasRegionTrace = traceOptions.testFlag(TraceOption::Region); - m_hasStackSizeTrace = traceOptions.testFlag(TraceOption::StackSize); - m_hasContextTrace = traceOptions.testFlag(TraceOption::Context); + m_hasFormatTrace = options.testFlag(Option::TraceFormat); + m_hasRegionTrace = options.testFlag(Option::TraceRegion); + m_hasStackSizeTrace = options.testFlag(Option::TraceStackSize); + m_hasContextTrace = options.testFlag(Option::TraceContext); const bool hasFormatOrContextTrace = m_hasFormatTrace || m_hasContextTrace || m_hasStackSizeTrace; const bool hasSeparator = hasFormatOrContextTrace && m_hasRegionTrace; @@ -831,6 +833,7 @@ public: bool firstLine = true; State state; QString currentLine; + const bool isUnbuffered = options.testFlag(Option::Unbuffered); while (in.readLineInto(¤tLine)) { auto oldState = state; state = highlightLine(currentLine, state); @@ -864,6 +867,10 @@ public: } m_highlightedFragments.clear(); + + if (isUnbuffered) { + out.flush(); + } } } @@ -970,12 +977,14 @@ private: QString label; if (m_hasStackSizeTrace) { - label += QLatin1Char('(') % QString::number(stateData->size()) % QLatin1Char(')'); + // first state is empty + int stateSize = stateData ? stateData->size() : 0; + label = QLatin1Char('(') % QString::number(stateSize) % QLatin1Char(')'); } if (m_hasContextTrace) { // first state is empty - if (stateData->isEmpty()) { + if (!stateData) { return label + QStringLiteral("[???]"); } @@ -1138,7 +1147,7 @@ private: QString name; int offset; int length; - quint16 formatId; + int formatId; }; struct ContextCaptureHighlighter : KSyntaxHighlighting::AbstractHighlighter { @@ -1168,7 +1177,7 @@ private: int depth; int offset; int bindIndex; - quint16 regionId; + int regionId; State state; }; @@ -1190,7 +1199,7 @@ private: }; } // anonymous namespace -class KSyntaxHighlighting::AnsiHighlighterPrivate +class KSyntaxHighlighting::AnsiHighlighterPrivate : public AbstractHighlighterPrivate { public: QTextStream out; @@ -1201,7 +1210,7 @@ public: }; AnsiHighlighter::AnsiHighlighter() - : d(new AnsiHighlighterPrivate()) + : AbstractHighlighter(new AnsiHighlighterPrivate()) { } @@ -1209,6 +1218,7 @@ AnsiHighlighter::~AnsiHighlighter() = default; void AnsiHighlighter::setOutputFile(const QString &fileName) { + Q_D(AnsiHighlighter); if (d->file.isOpen()) { d->file.close(); } @@ -1218,21 +1228,16 @@ void AnsiHighlighter::setOutputFile(const QString &fileName) return; } d->out.setDevice(&d->file); -#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) - d->out.setCodec("UTF-8"); -#endif } void AnsiHighlighter::setOutputFile(FILE *fileHandle) { + Q_D(AnsiHighlighter); d->file.open(fileHandle, QIODevice::WriteOnly); d->out.setDevice(&d->file); -#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) - d->out.setCodec("UTF-8"); -#endif } -void AnsiHighlighter::highlightFile(const QString &fileName, AnsiFormat format, bool useEditorBackground, TraceOptions traceOptions) +void AnsiHighlighter::highlightFile(const QString &fileName, AnsiFormat format, Options options) { QFileInfo fi(fileName); QFile f(fileName); @@ -1241,19 +1246,21 @@ void AnsiHighlighter::highlightFile(const QString &fileName, AnsiFormat format, return; } - highlightData(&f, format, useEditorBackground, traceOptions); + highlightData(&f, format, options); } -void AnsiHighlighter::highlightData(QIODevice *dev, AnsiFormat format, bool useEditorBackground, TraceOptions traceOptions) +void AnsiHighlighter::highlightData(QIODevice *dev, AnsiFormat format, Options options) { + Q_D(AnsiHighlighter); + if (!d->out.device()) { qCWarning(Log) << "No output stream defined!"; return; } const auto is256Colors = (format == AnsiFormat::XTerm256Color); - const auto theme = this->theme(); - const auto definition = this->definition(); + const auto &theme = d->m_theme; + const auto &definition = d->m_definition; auto definitions = definition.includedDefinitions(); definitions.append(definition); @@ -1265,6 +1272,8 @@ void AnsiHighlighter::highlightData(QIODevice *dev, AnsiFormat format, bool useE QLatin1String foregroundDefaultColor; QLatin1String backgroundDefaultColor; + const bool useEditorBackground = options.testFlag(Option::UseEditorBackground); + // https://en.wikipedia.org/wiki/ANSI_escape_code#SGR_parameters if (useEditorBackground) { @@ -1277,23 +1286,19 @@ void AnsiHighlighter::highlightData(QIODevice *dev, AnsiFormat format, bool useE backgroundDefaultColor = backgroundColorBuffer.latin1().mid(2); } - // ansiStyles must not be empty for applyFormat to work even with a definition without any context - if (d->ansiStyles.empty()) { - d->ansiStyles.resize(32); - } else { - d->ansiStyles[0].first.clear(); - d->ansiStyles[0].second.clear(); + int maxId = 0; + for (const auto &definition : std::as_const(definitions)) { + for (const auto &format : std::as_const(DefinitionData::get(definition)->formats)) { + maxId = qMax(maxId, format.id()); + } } + d->ansiStyles.clear(); + // ansiStyles must not be empty for applyFormat to work even with a definition without any context + d->ansiStyles.resize(maxId + 1); // initialize ansiStyles - for (auto &&definition : std::as_const(definitions)) { - for (auto &&format : std::as_const(DefinitionData::get(definition)->formats)) { - const auto id = format.id(); - if (id >= d->ansiStyles.size()) { - // better than id + 1 to avoid successive allocations - d->ansiStyles.resize(id * 2); - } - + for (const auto &definition : std::as_const(definitions)) { + for (const auto &format : std::as_const(DefinitionData::get(definition)->formats)) { AnsiBuffer buffer; buffer.append(QLatin1String("\x1b[")); @@ -1329,7 +1334,8 @@ void AnsiHighlighter::highlightData(QIODevice *dev, AnsiFormat format, bool useE // if there is ANSI style if (buffer.latin1().size() > 2) { buffer.setFinalStyle(); - d->ansiStyles[id].first = buffer.latin1(); + auto &style = d->ansiStyles[format.id()]; + style.first = buffer.latin1(); if (useEditorBackground) { buffer.clear(); @@ -1338,11 +1344,11 @@ void AnsiHighlighter::highlightData(QIODevice *dev, AnsiFormat format, bool useE buffer.append(hasEffect ? QLatin1String("\x1b[0;") : QLatin1String("\x1b[")); buffer.append(backgroundDefaultColor); buffer.setFinalStyle(); - d->ansiStyles[id].second = buffer.latin1(); + style.second = buffer.latin1(); } else if (hasEffect) { buffer.append(QLatin1String("\x1b[")); if (hasBold) { - buffer.append(QLatin1String("21;")); + buffer.append(QLatin1String("22;")); } if (hasItalic) { buffer.append(QLatin1String("23;")); @@ -1354,10 +1360,10 @@ void AnsiHighlighter::highlightData(QIODevice *dev, AnsiFormat format, bool useE buffer.append(QLatin1String("29;")); } buffer.setFinalStyle(); - d->ansiStyles[id].second = buffer.latin1(); + style.second = buffer.latin1(); } } else { - d->ansiStyles[id].second = QStringLiteral("\x1b[0m"); + style.second = QStringLiteral("\x1b[0m"); } } } @@ -1370,13 +1376,11 @@ void AnsiHighlighter::highlightData(QIODevice *dev, AnsiFormat format, bool useE } QTextStream in(dev); -#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0) - in.setCodec("UTF-8"); -#endif - if (!traceOptions) { + if (!options.testAnyFlag(Option::TraceAll)) { State state; QString currentLine; + const bool isUnbuffered = options.testFlag(Option::Unbuffered); while (in.readLineInto(¤tLine)) { d->currentLine = currentLine; state = highlightLine(d->currentLine, state); @@ -1386,6 +1390,10 @@ void AnsiHighlighter::highlightData(QIODevice *dev, AnsiFormat format, bool useE } else { d->out << QLatin1Char('\n'); } + + if (isUnbuffered) { + d->out.flush(); + } } } else { AnsiBuffer buffer; @@ -1394,7 +1402,7 @@ void AnsiHighlighter::highlightData(QIODevice *dev, AnsiFormat format, bool useE buffer.setFinalStyle(); DebugSyntaxHighlighter debugHighlighter; debugHighlighter.setDefinition(definition); - debugHighlighter.highlightData(in, d->out, buffer.latin1(), backgroundDefaultColor, d->ansiStyles, traceOptions); + debugHighlighter.highlightData(in, d->out, buffer.latin1(), backgroundDefaultColor, d->ansiStyles, options); } if (useEditorBackground) { @@ -1408,6 +1416,7 @@ void AnsiHighlighter::highlightData(QIODevice *dev, AnsiFormat format, bool useE void AnsiHighlighter::applyFormat(int offset, int length, const Format &format) { + Q_D(AnsiHighlighter); auto const &ansiStyle = d->ansiStyles[format.id()]; d->out << ansiStyle.first << d->currentLine.mid(offset, length) << ansiStyle.second; } diff --git a/src/libs/3rdparty/syntax-highlighting/src/lib/ansihighlighter.h b/src/libs/3rdparty/syntax-highlighting/src/lib/ansihighlighter.h index ffb13f38f37..0942aa0242b 100644 --- a/src/libs/3rdparty/syntax-highlighting/src/lib/ansihighlighter.h +++ b/src/libs/3rdparty/syntax-highlighting/src/lib/ansihighlighter.h @@ -11,10 +11,11 @@ #include "ksyntaxhighlighting_export.h" #include -#include #include -#include +QT_BEGIN_NAMESPACE +class QIODevice; +QT_END_NAMESPACE namespace KSyntaxHighlighting { @@ -29,24 +30,25 @@ public: XTerm256Color, }; - enum class TraceOption { + enum class Option { NoOptions, - Format = 1 << 0, - Region = 1 << 1, - Context = 1 << 2, - StackSize = 1 << 3, + UseEditorBackground = 1 << 0, + Unbuffered = 1 << 1, + + // Options that displays a useful visual aid for syntax creation + TraceFormat = 1 << 2, + TraceRegion = 1 << 3, + TraceContext = 1 << 4, + TraceStackSize = 1 << 5, + TraceAll = TraceFormat | TraceRegion | TraceContext | TraceStackSize, }; - Q_DECLARE_FLAGS(TraceOptions, TraceOption) + Q_DECLARE_FLAGS(Options, Option) AnsiHighlighter(); ~AnsiHighlighter() override; - void highlightFile(const QString &fileName, - AnsiFormat format = AnsiFormat::TrueColor, - bool useEditorBackground = true, - TraceOptions traceOptions = TraceOptions()); - void - highlightData(QIODevice *device, AnsiFormat format = AnsiFormat::TrueColor, bool useEditorBackground = true, TraceOptions traceOptions = TraceOptions()); + void highlightFile(const QString &fileName, AnsiFormat format = AnsiFormat::TrueColor, Options options = Option::UseEditorBackground); + void highlightData(QIODevice *device, AnsiFormat format = AnsiFormat::TrueColor, Options options = Option::UseEditorBackground); void setOutputFile(const QString &fileName); void setOutputFile(FILE *fileHandle); @@ -55,10 +57,10 @@ protected: void applyFormat(int offset, int length, const Format &format) override; private: - std::unique_ptr d; + Q_DECLARE_PRIVATE(AnsiHighlighter) }; } -Q_DECLARE_OPERATORS_FOR_FLAGS(KSyntaxHighlighting::AnsiHighlighter::TraceOptions) +Q_DECLARE_OPERATORS_FOR_FLAGS(KSyntaxHighlighting::AnsiHighlighter::Options) #endif // KSYNTAXHIGHLIGHTING_ANSIHIGHLIGHTER_H diff --git a/src/libs/3rdparty/syntax-highlighting/src/lib/context.cpp b/src/libs/3rdparty/syntax-highlighting/src/lib/context.cpp index ff5254cb6e5..af269d14d03 100644 --- a/src/libs/3rdparty/syntax-highlighting/src/lib/context.cpp +++ b/src/libs/3rdparty/syntax-highlighting/src/lib/context.cpp @@ -38,7 +38,15 @@ void Context::resolveContexts(DefinitionData &def, const HighlightingContextData m_lineEndContext.resolve(def, data.lineEndContext); m_lineEmptyContext.resolve(def, data.lineEmptyContext); m_fallthroughContext.resolve(def, data.fallthroughContext); - m_fallthrough = !m_fallthroughContext.isStay(); + m_stopEmptyLineContextSwitchLoop = data.stopEmptyLineContextSwitchLoop; + + /** + * line end context switches only when lineEmptyContext is #stay. This avoids + * skipping empty lines after a line continuation character (see bug 405903) + */ + if (m_lineEmptyContext.isStay()) { + m_lineEmptyContext = m_lineEndContext; + } m_rules.reserve(data.rules.size()); for (const auto &ruleData : data.rules) { @@ -65,6 +73,7 @@ void Context::resolveIncludes(DefinitionData &def) for (auto it = m_rules.begin(); it != m_rules.end();) { const IncludeRules *includeRules = it->get()->castToIncludeRules(); if (!includeRules) { + m_hasDynamicRule = m_hasDynamicRule || it->get()->isDynamic(); ++it; continue; } @@ -111,6 +120,8 @@ void Context::resolveIncludes(DefinitionData &def) context->resolveIncludes(*defData); } + m_hasDynamicRule = m_hasDynamicRule || context->m_hasDynamicRule; + /** * handle included attribute * transitive closure: we might include attributes included from somewhere else diff --git a/src/libs/3rdparty/syntax-highlighting/src/lib/context_p.h b/src/libs/3rdparty/syntax-highlighting/src/lib/context_p.h index 7e077b5a244..8cf0f1bfaba 100644 --- a/src/libs/3rdparty/syntax-highlighting/src/lib/context_p.h +++ b/src/libs/3rdparty/syntax-highlighting/src/lib/context_p.h @@ -16,10 +16,6 @@ #include -QT_BEGIN_NAMESPACE -class QXmlStreamReader; -QT_END_NAMESPACE - namespace KSyntaxHighlighting { class DefinitionData; @@ -52,7 +48,17 @@ public: bool fallthrough() const { - return m_fallthrough; + return !m_fallthroughContext.isStay(); + } + + bool hasDynamicRule() const + { + return m_hasDynamicRule; + } + + bool stopEmptyLineContextSwitchLoop() const + { + return m_stopEmptyLineContextSwitchLoop; } const ContextSwitch &fallthroughContext() const @@ -96,7 +102,8 @@ private: Format m_attributeFormat; ResolveState m_resolveState = Unresolved; - bool m_fallthrough = false; + bool m_hasDynamicRule = false; + bool m_stopEmptyLineContextSwitchLoop = true; bool m_indentationBasedFolding; }; } diff --git a/src/libs/3rdparty/syntax-highlighting/src/lib/definition.cpp b/src/libs/3rdparty/syntax-highlighting/src/lib/definition.cpp index 670dfddedb6..e2cca6da712 100644 --- a/src/libs/3rdparty/syntax-highlighting/src/lib/definition.cpp +++ b/src/libs/3rdparty/syntax-highlighting/src/lib/definition.cpp @@ -26,8 +26,6 @@ #include #include #include -#include -#include #include #include @@ -43,13 +41,8 @@ DefinitionData::DefinitionData() DefinitionData::~DefinitionData() = default; -DefinitionData *DefinitionData::get(const Definition &def) -{ - return def.d.get(); -} - Definition::Definition() - : d(new DefinitionData) + : d(std::make_shared()) { d->q = *this; } @@ -63,6 +56,9 @@ Definition &Definition::operator=(const Definition &) = default; Definition::Definition(std::shared_ptr &&dd) : d(std::move(dd)) { + if (!d) { + Definition().d.swap(d); + } } bool Definition::operator==(const Definition &other) const @@ -92,7 +88,10 @@ QString Definition::name() const QString Definition::translatedName() const { - return QCoreApplication::instance()->translate("Language", d->name.toUtf8().constData()); + if (d->translatedName.isEmpty()) { + d->translatedName = QCoreApplication::instance()->translate("Language", d->nameUtf8.isEmpty() ? d->name.toUtf8().constData() : d->nameUtf8.constData()); + } + return d->translatedName; } QString Definition::section() const @@ -102,15 +101,19 @@ QString Definition::section() const QString Definition::translatedSection() const { - return QCoreApplication::instance()->translate("Language Section", d->section.toUtf8().constData()); + if (d->translatedSection.isEmpty()) { + d->translatedSection = QCoreApplication::instance()->translate("Language Section", + d->sectionUtf8.isEmpty() ? d->section.toUtf8().constData() : d->sectionUtf8.constData()); + } + return d->translatedSection; } -QVector Definition::mimeTypes() const +QList Definition::mimeTypes() const { return d->mimetypes; } -QVector Definition::extensions() const +QList Definition::extensions() const { return d->extensions; } @@ -218,12 +221,12 @@ bool Definition::setKeywordList(const QString &name, const QStringList &content) } } -QVector Definition::formats() const +QList Definition::formats() const { d->load(); // sort formats so that the order matches the order of the itemDatas in the xml files. - auto formatList = QVector::fromList(d->formats.values()); + auto formatList = d->formats.values(); std::sort(formatList.begin(), formatList.end(), [](const KSyntaxHighlighting::Format &lhs, const KSyntaxHighlighting::Format &rhs) { return lhs.id() < rhs.id(); }); @@ -231,13 +234,13 @@ QVector Definition::formats() const return formatList; } -QVector Definition::includedDefinitions() const +QList Definition::includedDefinitions() const { d->load(); // init worklist and result used as guard with this definition - QVector queue{d.get()}; - QVector definitions{*this}; + QList queue{d.get()}; + QList definitions{*this}; while (!queue.empty()) { const auto *def = queue.back(); queue.pop_back(); @@ -275,7 +278,7 @@ QPair Definition::multiLineCommentMarker() const return {d->multiLineCommentStartMarker, d->multiLineCommentEndMarker}; } -QVector> Definition::characterEncodings() const +QList> Definition::characterEncodings() const { d->load(); return d->characterEncodings; @@ -394,7 +397,11 @@ void DefinitionData::clear() characterEncodings.clear(); fileName.clear(); + nameUtf8.clear(); + translatedName.clear(); section.clear(); + sectionUtf8.clear(); + translatedSection.clear(); style.clear(); indenter.clear(); author.clear(); @@ -405,6 +412,9 @@ void DefinitionData::clear() version = 0.0f; priority = 0; hidden = false; + + // purge our cache that is used to unify states + unify.clear(); } bool DefinitionData::loadMetaData(const QString &definitionFileName) @@ -433,7 +443,9 @@ bool DefinitionData::loadMetaData(const QString &definitionFileName) bool DefinitionData::loadMetaData(const QString &file, const QCborMap &obj) { name = obj.value(QLatin1String("name")).toString(); + nameUtf8 = obj.value(QLatin1String("name")).toByteArray(); section = obj.value(QLatin1String("section")).toString(); + sectionUtf8 = obj.value(QLatin1String("section")).toByteArray(); version = obj.value(QLatin1String("version")).toInteger(); priority = obj.value(QLatin1String("priority")).toInteger(); style = obj.value(QLatin1String("style")).toString(); @@ -444,13 +456,10 @@ bool DefinitionData::loadMetaData(const QString &file, const QCborMap &obj) fileName = file; const auto exts = obj.value(QLatin1String("extensions")).toString(); - for (const auto &ext : exts.split(QLatin1Char(';'), Qt::SkipEmptyParts)) { - extensions.push_back(ext); - } + extensions = exts.split(QLatin1Char(';'), Qt::SkipEmptyParts); + const auto mts = obj.value(QLatin1String("mimetype")).toString(); - for (const auto &mt : mts.split(QLatin1Char(';'), Qt::SkipEmptyParts)) { - mimetypes.push_back(mt); - } + mimetypes = mts.split(QLatin1Char(';'), Qt::SkipEmptyParts); return true; } @@ -805,10 +814,10 @@ bool DefinitionData::checkKateVersion(QStringView verStr) qCWarning(Log) << "Skipping" << fileName << "due to having no valid kateversion attribute:" << verStr; return false; } - const auto major = verStr.left(idx).toString().toInt(); - const auto minor = verStr.mid(idx + 1).toString().toInt(); + const auto major = verStr.left(idx).toInt(); + const auto minor = verStr.mid(idx + 1).toInt(); - if (major > SyntaxHighlighting_VERSION_MAJOR || (major == SyntaxHighlighting_VERSION_MAJOR && minor > SyntaxHighlighting_VERSION_MINOR)) { + if (major > KSYNTAXHIGHLIGHTING_VERSION_MAJOR || (major == KSYNTAXHIGHLIGHTING_VERSION_MAJOR && minor > KSYNTAXHIGHLIGHTING_VERSION_MINOR)) { qCWarning(Log) << "Skipping" << fileName << "due to being too new, version:" << verStr; return false; } @@ -834,34 +843,20 @@ void DefinitionData::addImmediateIncludedDefinition(const Definition &def) DefinitionRef::DefinitionRef() = default; -DefinitionRef::DefinitionRef(const Definition &def) +DefinitionRef::DefinitionRef(const Definition &def) noexcept : d(def.d) { } -DefinitionRef::DefinitionRef(Definition &&def) - : d(std::move(def.d)) -{ -} - -DefinitionRef &DefinitionRef::operator=(const Definition &def) +DefinitionRef &DefinitionRef::operator=(const Definition &def) noexcept { d = def.d; return *this; } -DefinitionRef &DefinitionRef::operator=(Definition &&def) -{ - d = std::move(def.d); - return *this; -} - Definition DefinitionRef::definition() const { - if (!d.expired()) { - return Definition(d.lock()); - } - return Definition(); + return Definition(d.lock()); } bool DefinitionRef::operator==(const DefinitionRef &other) const @@ -873,3 +868,5 @@ bool DefinitionRef::operator==(const Definition &other) const { return !d.owner_before(other.d) && !other.d.owner_before(d); } + +#include "moc_definition.cpp" diff --git a/src/libs/3rdparty/syntax-highlighting/src/lib/definition.h b/src/libs/3rdparty/syntax-highlighting/src/lib/definition.h index 05757ea52a3..e69492bee42 100644 --- a/src/libs/3rdparty/syntax-highlighting/src/lib/definition.h +++ b/src/libs/3rdparty/syntax-highlighting/src/lib/definition.h @@ -10,16 +10,12 @@ #include "ksyntaxhighlighting_export.h" +#include #include -#include +#include #include #include -QT_BEGIN_NAMESPACE -class QChar; -class QString; -QT_END_NAMESPACE - namespace KSyntaxHighlighting { class Context; @@ -185,13 +181,13 @@ public: /** * Mime types associated with this syntax definition. */ - QVector mimeTypes() const; + QList mimeTypes() const; /** * File extensions associated with this syntax definition. * The returned list contains wildcards. */ - QVector extensions() const; + QList extensions() const; /** * Returns the definition version. @@ -360,7 +356,7 @@ public: * The order of the Format items equals the order of the itemDatas in the xml file. * @since 5.49 */ - QVector formats() const; + QList formats() const; /** * Returns a list of Definitions that are referenced with the IncludeRules rule. @@ -369,7 +365,7 @@ public: * * @since 5.49 */ - QVector includedDefinitions() const; + QList includedDefinitions() const; /** * Returns the marker that starts a single line comment. @@ -400,7 +396,7 @@ public: * the string \"{A} represents the character Ä. * @since 5.50 */ - QVector> characterEncodings() const; + QList> characterEncodings() const; /** * @} @@ -409,14 +405,14 @@ public: private: friend class DefinitionData; friend class DefinitionRef; - explicit Definition(std::shared_ptr &&dd); + KSYNTAXHIGHLIGHTING_NO_EXPORT explicit Definition(std::shared_ptr &&dd); std::shared_ptr d; }; } QT_BEGIN_NAMESPACE -Q_DECLARE_TYPEINFO(KSyntaxHighlighting::Definition, Q_MOVABLE_TYPE); +Q_DECLARE_TYPEINFO(KSyntaxHighlighting::Definition, Q_RELOCATABLE_TYPE); QT_END_NAMESPACE #endif diff --git a/src/libs/3rdparty/syntax-highlighting/src/lib/definition_p.h b/src/libs/3rdparty/syntax-highlighting/src/lib/definition_p.h index 542f255b321..ec00b318970 100644 --- a/src/libs/3rdparty/syntax-highlighting/src/lib/definition_p.h +++ b/src/libs/3rdparty/syntax-highlighting/src/lib/definition_p.h @@ -10,11 +10,13 @@ #include "definitionref_p.h" #include "highlightingdata_p.hpp" +#include "state.h" #include "worddelimiters_p.h" #include +#include +#include #include -#include #include @@ -36,7 +38,10 @@ public: DefinitionData(const DefinitionData &) = delete; DefinitionData &operator=(const DefinitionData &) = delete; - static DefinitionData *get(const Definition &def); + static DefinitionData *get(const Definition &def) + { + return def.d.get(); + } bool isLoaded() const; bool loadMetaData(const QString &definitionFileName); @@ -80,9 +85,9 @@ public: std::vector contexts; QHash formats; // data loaded from xml file and emptied after loading contexts - QVector contextDatas; + QList contextDatas; // Definition referenced by IncludeRules and ContextSwitch - QVector immediateIncludedDefinitions; + QList immediateIncludedDefinitions; WordDelimiters wordDelimiters; WordDelimiters wordWrapDelimiters; bool keywordIsLoaded = false; @@ -93,21 +98,28 @@ public: CommentPosition singleLineCommentPosition = CommentPosition::StartOfLine; QString multiLineCommentStartMarker; QString multiLineCommentEndMarker; - QVector> characterEncodings; + QList> characterEncodings; QString fileName; QString name = QStringLiteral(QT_TRANSLATE_NOOP("Language", "None")); + QByteArray nameUtf8; + mutable QString translatedName; QString section; + QByteArray sectionUtf8; + mutable QString translatedSection; QString style; QString indenter; QString author; QString license; - QVector mimetypes; - QVector extensions; + QList mimetypes; + QList extensions; Qt::CaseSensitivity caseSensitive = Qt::CaseSensitive; int version = 0; int priority = 0; bool hidden = false; + + // cache that is used to unify states in AbstractHighlighter::highlightLine + mutable QSet unify; }; } diff --git a/src/libs/3rdparty/syntax-highlighting/src/lib/definitiondownloader.cpp b/src/libs/3rdparty/syntax-highlighting/src/lib/definitiondownloader.cpp index c1335789dc9..88ba5d77591 100644 --- a/src/libs/3rdparty/syntax-highlighting/src/lib/definitiondownloader.cpp +++ b/src/libs/3rdparty/syntax-highlighting/src/lib/definitiondownloader.cpp @@ -169,8 +169,8 @@ DefinitionDownloader::~DefinitionDownloader() void DefinitionDownloader::start() { - const QString url = QLatin1String("https://www.kate-editor.org/syntax/update-") + QString::number(SyntaxHighlighting_VERSION_MAJOR) + QLatin1Char('.') - + QString::number(SyntaxHighlighting_VERSION_MINOR) + QLatin1String(".xml"); + const QString url = QLatin1String("https://www.kate-editor.org/syntax/update-") + QString::number(KSYNTAXHIGHLIGHTING_VERSION_MAJOR) + QLatin1Char('.') + + QString::number(KSYNTAXHIGHLIGHTING_VERSION_MINOR) + QLatin1String(".xml"); auto req = QNetworkRequest(QUrl(url)); req.setAttribute(QNetworkRequest::RedirectPolicyAttribute, QNetworkRequest::NoLessSafeRedirectPolicy); auto reply = d->nam->get(req); @@ -178,3 +178,5 @@ void DefinitionDownloader::start() d->definitionListDownloadFinished(reply); }); } + +#include "moc_definitiondownloader.cpp" diff --git a/src/libs/3rdparty/syntax-highlighting/src/lib/definitionref_p.h b/src/libs/3rdparty/syntax-highlighting/src/lib/definitionref_p.h index 0bd805624dd..a7ef08f614f 100644 --- a/src/libs/3rdparty/syntax-highlighting/src/lib/definitionref_p.h +++ b/src/libs/3rdparty/syntax-highlighting/src/lib/definitionref_p.h @@ -30,10 +30,8 @@ class DefinitionRef { public: DefinitionRef(); - explicit DefinitionRef(const Definition &def); - explicit DefinitionRef(Definition &&def); - DefinitionRef &operator=(const Definition &def); - DefinitionRef &operator=(Definition &&def); + explicit DefinitionRef(const Definition &def) noexcept; + DefinitionRef &operator=(const Definition &def) noexcept; Definition definition() const; diff --git a/src/libs/3rdparty/syntax-highlighting/src/lib/dynamicregexpcache_p.h b/src/libs/3rdparty/syntax-highlighting/src/lib/dynamicregexpcache_p.h new file mode 100644 index 00000000000..dcef97a8416 --- /dev/null +++ b/src/libs/3rdparty/syntax-highlighting/src/lib/dynamicregexpcache_p.h @@ -0,0 +1,39 @@ +/* + SPDX-FileCopyrightText: 2023 Jonathan Poelen + + SPDX-License-Identifier: MIT +*/ + +#ifndef KSYNTAXHIGHLIGHTING_DYNAMICREGEXPCACHE_P_H +#define KSYNTAXHIGHLIGHTING_DYNAMICREGEXPCACHE_P_H + +#include +#include +#include + +#include + +namespace KSyntaxHighlighting +{ + +class DynamicRegexpCache +{ +public: + const QRegularExpression &compileRegexp(QString &&pattern, QRegularExpression::PatternOptions patternOptions) + { + const auto key = std::pair{std::move(pattern), patternOptions}; + if (const auto regexp = m_cache.object(key)) { + return *regexp; + } + auto regexp = new QRegularExpression(key.first, patternOptions); + m_cache.insert(key, regexp); + return *regexp; + } + +private: + QCache, QRegularExpression> m_cache; +}; + +} + +#endif diff --git a/src/libs/3rdparty/syntax-highlighting/src/lib/foldingregion.cpp b/src/libs/3rdparty/syntax-highlighting/src/lib/foldingregion.cpp index 3bca63eecda..9ed625b12ed 100644 --- a/src/libs/3rdparty/syntax-highlighting/src/lib/foldingregion.cpp +++ b/src/libs/3rdparty/syntax-highlighting/src/lib/foldingregion.cpp @@ -8,36 +8,39 @@ using namespace KSyntaxHighlighting; -static_assert(sizeof(FoldingRegion) == 2, "FoldingRegion is size-sensitive to frequent use in KTextEditor!"); +static_assert(sizeof(FoldingRegion) == sizeof(int), "FoldingRegion is size-sensitive to frequent use in KTextEditor!"); -FoldingRegion::FoldingRegion() - : m_type(None) - , m_id(0) -{ -} +FoldingRegion::FoldingRegion() = default; -FoldingRegion::FoldingRegion(Type type, quint16 id) - : m_type(type) - , m_id(id) +FoldingRegion::FoldingRegion(Type type, int id) + : m_idWithType((type == End) ? -id : id) { } bool FoldingRegion::operator==(const FoldingRegion &other) const { - return m_id == other.m_id && m_type == other.m_type; + return m_idWithType == other.m_idWithType; } bool FoldingRegion::isValid() const { - return type() != None; + return m_idWithType != 0; } -quint16 FoldingRegion::id() const +int FoldingRegion::id() const { - return m_id; + return (m_idWithType < 0) ? -m_idWithType : m_idWithType; } FoldingRegion::Type FoldingRegion::type() const { - return static_cast(m_type); + if (isValid()) { + return (m_idWithType < 0) ? End : Begin; + } + return None; +} + +FoldingRegion FoldingRegion::sibling() const +{ + return isValid() ? FoldingRegion(type() ? End : Begin, id()) : FoldingRegion(); } diff --git a/src/libs/3rdparty/syntax-highlighting/src/lib/foldingregion.h b/src/libs/3rdparty/syntax-highlighting/src/lib/foldingregion.h index ca4cacafb25..e2a9e1fc680 100644 --- a/src/libs/3rdparty/syntax-highlighting/src/lib/foldingregion.h +++ b/src/libs/3rdparty/syntax-highlighting/src/lib/foldingregion.h @@ -22,7 +22,7 @@ public: * Defines whether a FoldingRegion starts or ends a folding region. */ enum Type { - //! Used internally as indicator for invalid FoldingRegion%s. + //! Used internally as indicator for an invalid FoldingRegion. None, //! Indicates the start of a FoldingRegion. Begin, @@ -64,7 +64,7 @@ public: * brace, you need to do kind of a reference counting to find the correct * closing brace. */ - quint16 id() const; + int id() const; /** * Returns whether this is the begin or end of a region. @@ -74,12 +74,21 @@ public: */ Type type() const; + /** + * Returns the matching start or end region. + * + * @note Will return invalid region for an invalid region. + * + * @since 6.0 + */ + FoldingRegion sibling() const; + private: friend class Rule; - FoldingRegion(Type type, quint16 id); + KSYNTAXHIGHLIGHTING_NO_EXPORT FoldingRegion(Type type, int id); - quint16 m_type : 2; - quint16 m_id : 14; + // 0 is invalid, positive begin, negative end + int m_idWithType = 0; }; } diff --git a/src/libs/3rdparty/syntax-highlighting/src/lib/format.cpp b/src/libs/3rdparty/syntax-highlighting/src/lib/format.cpp index 518a1e9ee9e..2259cd34115 100644 --- a/src/libs/3rdparty/syntax-highlighting/src/lib/format.cpp +++ b/src/libs/3rdparty/syntax-highlighting/src/lib/format.cpp @@ -98,7 +98,7 @@ QString Format::name() const return d->name; } -quint16 Format::id() const +int Format::id() const { return d->id; } diff --git a/src/libs/3rdparty/syntax-highlighting/src/lib/format.h b/src/libs/3rdparty/syntax-highlighting/src/lib/format.h index 496a54e42cb..397a1bab01c 100644 --- a/src/libs/3rdparty/syntax-highlighting/src/lib/format.h +++ b/src/libs/3rdparty/syntax-highlighting/src/lib/format.h @@ -13,12 +13,6 @@ #include -QT_BEGIN_NAMESPACE -class QColor; -class QString; -class QXmlStreamReader; -QT_END_NAMESPACE - namespace KSyntaxHighlighting { class FormatPrivate; @@ -54,7 +48,7 @@ public: * the repository is reloaded (which also invalidatess the corresponding * Definition anyway). */ - quint16 id() const; + int id() const; /** Returns the underlying TextStyle of this Format. * Every Theme::TextStyle is visually defined by a Theme. A Format uses one @@ -192,7 +186,7 @@ private: } QT_BEGIN_NAMESPACE -Q_DECLARE_TYPEINFO(KSyntaxHighlighting::Format, Q_MOVABLE_TYPE); +Q_DECLARE_TYPEINFO(KSyntaxHighlighting::Format, Q_RELOCATABLE_TYPE); QT_END_NAMESPACE #endif // KSYNTAXHIGHLIGHTING_FORMAT_H diff --git a/src/libs/3rdparty/syntax-highlighting/src/lib/format_p.h b/src/libs/3rdparty/syntax-highlighting/src/lib/format_p.h index d8770f1ef7c..ea74531445e 100644 --- a/src/libs/3rdparty/syntax-highlighting/src/lib/format_p.h +++ b/src/libs/3rdparty/syntax-highlighting/src/lib/format_p.h @@ -13,6 +13,10 @@ #include #include +QT_BEGIN_NAMESPACE +class QXmlStreamReader; +QT_END_NAMESPACE + namespace KSyntaxHighlighting { class FormatPrivate : public QSharedData @@ -21,6 +25,11 @@ public: FormatPrivate() = default; static FormatPrivate *detachAndGet(Format &format); + static std::intptr_t ptrId(const Format &format) + { + return std::intptr_t(format.d.data()); + } + TextStyleData styleOverride(const Theme &theme) const; void load(QXmlStreamReader &reader); @@ -33,7 +42,7 @@ public: QString name; TextStyleData style; Theme::TextStyle defaultStyle = Theme::Normal; - quint16 id = 0; + int id = 0; bool spellCheck = true; }; diff --git a/src/libs/3rdparty/syntax-highlighting/src/lib/highlightingdata.cpp b/src/libs/3rdparty/syntax-highlighting/src/lib/highlightingdata.cpp index adb1c346c13..d95ad43b7fe 100644 --- a/src/libs/3rdparty/syntax-highlighting/src/lib/highlightingdata.cpp +++ b/src/libs/3rdparty/syntax-highlighting/src/lib/highlightingdata.cpp @@ -379,6 +379,7 @@ void HighlightingContextData::load(const QString &defName, QXmlStreamReader &rea lineEmptyContext = reader.attributes().value(QLatin1String("lineEmptyContext")).toString(); fallthroughContext = reader.attributes().value(QLatin1String("fallthroughContext")).toString(); noIndentationBasedFolding = Xml::attrToBool(reader.attributes().value(QLatin1String("noIndentationBasedFolding"))); + stopEmptyLineContextSwitchLoop = Xml::attrToBool(reader.attributes().value(QLatin1String("stopEmptyLineContextSwitchLoop"))); rules.reserve(8); diff --git a/src/libs/3rdparty/syntax-highlighting/src/lib/highlightingdata_p.hpp b/src/libs/3rdparty/syntax-highlighting/src/lib/highlightingdata_p.hpp index 80aeaf49340..f49227dbf96 100644 --- a/src/libs/3rdparty/syntax-highlighting/src/lib/highlightingdata_p.hpp +++ b/src/libs/3rdparty/syntax-highlighting/src/lib/highlightingdata_p.hpp @@ -208,6 +208,7 @@ public: std::vector rules; + bool stopEmptyLineContextSwitchLoop = false; bool noIndentationBasedFolding = false; }; } diff --git a/src/libs/3rdparty/syntax-highlighting/src/lib/htmlhighlighter.cpp b/src/libs/3rdparty/syntax-highlighting/src/lib/htmlhighlighter.cpp index 1f68e33d3e4..928ae149d1b 100644 --- a/src/libs/3rdparty/syntax-highlighting/src/lib/htmlhighlighter.cpp +++ b/src/libs/3rdparty/syntax-highlighting/src/lib/htmlhighlighter.cpp @@ -6,7 +6,9 @@ */ #include "htmlhighlighter.h" +#include "abstracthighlighter_p.h" #include "definition.h" +#include "definition_p.h" #include "format.h" #include "ksyntaxhighlighting_logging.h" #include "state.h" @@ -14,21 +16,22 @@ #include #include +#include #include -#include using namespace KSyntaxHighlighting; -class KSyntaxHighlighting::HtmlHighlighterPrivate +class KSyntaxHighlighting::HtmlHighlighterPrivate : public AbstractHighlighterPrivate { public: std::unique_ptr out; std::unique_ptr file; QString currentLine; + std::vector htmlStyles; }; HtmlHighlighter::HtmlHighlighter() - : d(new HtmlHighlighterPrivate()) + : AbstractHighlighter(new HtmlHighlighterPrivate()) { } @@ -38,27 +41,21 @@ HtmlHighlighter::~HtmlHighlighter() void HtmlHighlighter::setOutputFile(const QString &fileName) { + Q_D(HtmlHighlighter); d->file.reset(new QFile(fileName)); if (!d->file->open(QFile::WriteOnly | QFile::Truncate)) { qCWarning(Log) << "Failed to open output file" << fileName << ":" << d->file->errorString(); return; } d->out.reset(new QTextStream(d->file.get())); -#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) d->out->setEncoding(QStringConverter::Utf8); -#else - d->out->setCodec("UTF-8"); -#endif } void HtmlHighlighter::setOutputFile(FILE *fileHandle) { + Q_D(HtmlHighlighter); d->out.reset(new QTextStream(fileHandle, QIODevice::WriteOnly)); -#if QT_VERSION >= QT_VERSION_CHECK(6, 0, 0) d->out->setEncoding(QStringConverter::Utf8); -#else - d->out->setCodec("UTF-8"); -#endif } void HtmlHighlighter::highlightFile(const QString &fileName, const QString &title) @@ -79,7 +76,7 @@ void HtmlHighlighter::highlightFile(const QString &fileName, const QString &titl /** * @brief toHtmlRgba - * Converts QColor -> rgba(r, g, b, a) if there is an alpha channel + * Converts QColor -> #RRGGBBAA if there is an alpha channel * otherwise it will just return the hexcode. This is because QColor * outputs #AARRGGBB, whereas browser support #RRGGBBAA. * @@ -91,22 +88,24 @@ static QString toHtmlRgbaString(const QColor &color) if (color.alpha() == 0xFF) { return color.name(); } - - QString rgba = QStringLiteral("rgba("); - rgba.append(QString::number(color.red())); - rgba.append(QLatin1Char(',')); - rgba.append(QString::number(color.green())); - rgba.append(QLatin1Char(',')); - rgba.append(QString::number(color.blue())); - rgba.append(QLatin1Char(',')); - // this must be alphaF - rgba.append(QString::number(color.alphaF())); - rgba.append(QLatin1Char(')')); - return rgba; + static const char16_t digits[]{'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'}; + QChar hexcode[9]; + hexcode[0] = QLatin1Char('#'); + hexcode[1] = digits[color.red() >> 4]; + hexcode[2] = digits[color.red() & 0xf]; + hexcode[3] = digits[color.green() >> 4]; + hexcode[4] = digits[color.green() & 0xf]; + hexcode[5] = digits[color.blue() >> 4]; + hexcode[6] = digits[color.blue() & 0xf]; + hexcode[7] = digits[color.alpha() >> 4]; + hexcode[8] = digits[color.alpha() & 0xf]; + return QString(hexcode, 9); } void HtmlHighlighter::highlightData(QIODevice *dev, const QString &title) { + Q_D(HtmlHighlighter); + if (!d->out) { qCWarning(Log) << "No output stream defined!"; return; @@ -114,29 +113,73 @@ void HtmlHighlighter::highlightData(QIODevice *dev, const QString &title) QString htmlTitle; if (title.isEmpty()) { - htmlTitle = QStringLiteral("Kate Syntax Highlighter"); + htmlTitle = QStringLiteral("KSyntaxHighlighter"); } else { htmlTitle = title.toHtmlEscaped(); } + const auto &theme = d->m_theme; + const auto &definition = d->m_definition; + + auto definitions = definition.includedDefinitions(); + definitions.append(definition); + + int maxId = 0; + for (const auto &definition : std::as_const(definitions)) { + for (const auto &format : std::as_const(DefinitionData::get(definition)->formats)) { + maxId = qMax(maxId, format.id()); + } + } + d->htmlStyles.clear(); + // htmlStyles must not be empty for applyFormat to work even with a definition without any context + d->htmlStyles.resize(maxId + 1); + + // initialize htmlStyles + for (const auto &definition : std::as_const(definitions)) { + for (const auto &format : std::as_const(DefinitionData::get(definition)->formats)) { + auto &buffer = d->htmlStyles[format.id()]; + if (format.hasTextColor(theme)) { + buffer += QStringLiteral("color:") + toHtmlRgbaString(format.textColor(theme)) + QStringLiteral(";"); + } + if (format.hasBackgroundColor(theme)) { + buffer += QStringLiteral("background-color:") + toHtmlRgbaString(format.backgroundColor(theme)) + QStringLiteral(";"); + } + if (format.isBold(theme)) { + buffer += QStringLiteral("font-weight:bold;"); + } + if (format.isItalic(theme)) { + buffer += QStringLiteral("font-style:italic;"); + } + if (format.isUnderline(theme)) { + buffer += QStringLiteral("text-decoration:underline;"); + } + if (format.isStrikeThrough(theme)) { + buffer += QStringLiteral("text-decoration:line-through;"); + } + + if (!buffer.isEmpty()) { + buffer.insert(0, QStringLiteral("'; + } + } + } + State state; *d->out << "\n"; *d->out << "\n"; *d->out << "\n"; *d->out << "" << htmlTitle << "\n"; - *d->out << "\n"; + *d->out << "\n"; *d->out << "out << " style=\"background-color:" << toHtmlRgbaString(QColor::fromRgba(theme().editorColor(Theme::BackgroundColor))); - if (theme().textColor(Theme::Normal)) { - *d->out << ";color:" << toHtmlRgbaString(QColor::fromRgba(theme().textColor(Theme::Normal))); + *d->out << " style=\"background-color:" << toHtmlRgbaString(QColor::fromRgba(theme.editorColor(Theme::BackgroundColor))); + if (theme.textColor(Theme::Normal)) { + *d->out << ";color:" << toHtmlRgbaString(QColor::fromRgba(theme.textColor(Theme::Normal))); } *d->out << "\">
\n";
 
     QTextStream in(dev);
-#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
-    in.setCodec("UTF-8");
-#endif
     while (in.readLineInto(&d->currentLine)) {
         state = highlightLine(d->currentLine, state);
         *d->out << "\n";
@@ -155,38 +198,24 @@ void HtmlHighlighter::applyFormat(int offset, int length, const Format &format)
         return;
     }
 
-    // collect potential output, cheaper than thinking about "is there any?"
-    QVarLengthArray formatOutput;
-    if (format.hasTextColor(theme())) {
-        formatOutput << QStringLiteral("color:") << toHtmlRgbaString(format.textColor(theme())) << QStringLiteral(";");
-    }
-    if (format.hasBackgroundColor(theme())) {
-        formatOutput << QStringLiteral("background-color:") << toHtmlRgbaString(format.backgroundColor(theme())) << QStringLiteral(";");
-    }
-    if (format.isBold(theme())) {
-        formatOutput << QStringLiteral("font-weight:bold;");
-    }
-    if (format.isItalic(theme())) {
-        formatOutput << QStringLiteral("font-style:italic;");
-    }
-    if (format.isUnderline(theme())) {
-        formatOutput << QStringLiteral("text-decoration:underline;");
-    }
-    if (format.isStrikeThrough(theme())) {
-        formatOutput << QStringLiteral("text-decoration:line-through;");
-    }
+    Q_D(HtmlHighlighter);
 
-    if (!formatOutput.isEmpty()) {
-        *d->out << "out << out;
-        }
-        *d->out << "\">";
+    auto const &htmlStyle = d->htmlStyles[format.id()];
+
+    if (!htmlStyle.isEmpty()) {
+        *d->out << htmlStyle;
     }
 
-    *d->out << d->currentLine.mid(offset, length).toHtmlEscaped();
+    for (QChar ch : QStringView(d->currentLine).mid(offset, length)) {
+        if (ch == u'<')
+            *d->out << QStringLiteral("<");
+        else if (ch == u'&')
+            *d->out << QStringLiteral("&");
+        else
+            *d->out << ch;
+    }
 
-    if (!formatOutput.isEmpty()) {
-        *d->out << "";
+    if (!htmlStyle.isEmpty()) {
+        *d->out << QStringLiteral("");
     }
 }
diff --git a/src/libs/3rdparty/syntax-highlighting/src/lib/htmlhighlighter.h b/src/libs/3rdparty/syntax-highlighting/src/lib/htmlhighlighter.h
index 8754057345d..741cb851031 100644
--- a/src/libs/3rdparty/syntax-highlighting/src/lib/htmlhighlighter.h
+++ b/src/libs/3rdparty/syntax-highlighting/src/lib/htmlhighlighter.h
@@ -10,10 +10,11 @@
 #include "abstracthighlighter.h"
 #include "ksyntaxhighlighting_export.h"
 
-#include 
 #include 
 
-#include 
+QT_BEGIN_NAMESPACE
+class QIODevice;
+QT_END_NAMESPACE
 
 namespace KSyntaxHighlighting
 {
@@ -35,7 +36,7 @@ protected:
     void applyFormat(int offset, int length, const Format &format) override;
 
 private:
-    std::unique_ptr d;
+    Q_DECLARE_PRIVATE(HtmlHighlighter)
 };
 }
 
diff --git a/src/libs/3rdparty/syntax-highlighting/src/lib/keywordlist.cpp b/src/libs/3rdparty/syntax-highlighting/src/lib/keywordlist.cpp
index 133b6d28ac5..847f6af6d46 100644
--- a/src/libs/3rdparty/syntax-highlighting/src/lib/keywordlist.cpp
+++ b/src/libs/3rdparty/syntax-highlighting/src/lib/keywordlist.cpp
@@ -47,7 +47,7 @@ bool KeywordList::contains(QStringView str, Qt::CaseSensitivity caseSensitive) c
     /**
      * search with right predicate
      */
-    return std::binary_search(vectorToSearch.begin(), vectorToSearch.end(), QStringView(str), KeywordComparator{caseSensitive});
+    return std::binary_search(vectorToSearch.begin(), vectorToSearch.end(), str, KeywordComparator{caseSensitive});
 }
 
 void KeywordList::load(QXmlStreamReader &reader)
@@ -103,10 +103,7 @@ void KeywordList::initLookupForCaseSensitivity(Qt::CaseSensitivity caseSensitive
     /**
      * fill vector with refs to keywords
      */
-    vectorToSort.reserve(m_keywords.size());
-    for (const auto &keyword : std::as_const(m_keywords)) {
-        vectorToSort.push_back(keyword);
-    }
+    vectorToSort.assign(m_keywords.constBegin(), m_keywords.constEnd());
 
     /**
      * sort with right predicate
diff --git a/src/libs/3rdparty/syntax-highlighting/src/lib/matchresult_p.h b/src/libs/3rdparty/syntax-highlighting/src/lib/matchresult_p.h
index 1e0f7c61027..7112d4e291b 100644
--- a/src/libs/3rdparty/syntax-highlighting/src/lib/matchresult_p.h
+++ b/src/libs/3rdparty/syntax-highlighting/src/lib/matchresult_p.h
@@ -41,9 +41,9 @@ public:
      * @param offset offset of match
      * @param captures captures of the match
      */
-    explicit MatchResult(const int offset, const QStringList &captures)
+    explicit MatchResult(const int offset, QStringList &&captures)
         : m_offset(offset)
-        , m_captures(captures)
+        , m_captures(std::move(captures))
     {
     }
 
@@ -69,7 +69,7 @@ public:
      * Captures of the match.
      * @return captured text of this match
      */
-    const QStringList &captures() const
+    QStringList &captures()
     {
         return m_captures;
     }
diff --git a/src/libs/3rdparty/syntax-highlighting/src/lib/repository.cpp b/src/libs/3rdparty/syntax-highlighting/src/lib/repository.cpp
index a12d4ba1a3a..07c28454c5b 100644
--- a/src/libs/3rdparty/syntax-highlighting/src/lib/repository.cpp
+++ b/src/libs/3rdparty/syntax-highlighting/src/lib/repository.cpp
@@ -77,9 +77,9 @@ Definition findHighestPriorityDefinitionIf(const QMap &defs
 }
 
 template
-QVector findDefinitionsIf(const QMap &defs, UnaryPredicate predicate)
+QList findDefinitionsIf(const QMap &defs, UnaryPredicate predicate)
 {
-    QVector matches;
+    QList matches;
     std::copy_if(defs.cbegin(), defs.cend(), std::back_inserter(matches), predicate);
     std::stable_sort(matches.begin(), matches.end(), [](const Definition &lhs, const Definition &rhs) {
         return lhs.priority() > rhs.priority();
@@ -127,7 +127,7 @@ Definition Repository::definitionForFileName(const QString &fileName) const
     return findHighestPriorityDefinitionIf(d->m_defs, anyWildcardMatches(fileNameFromFilePath(fileName)));
 }
 
-QVector Repository::definitionsForFileName(const QString &fileName) const
+QList Repository::definitionsForFileName(const QString &fileName) const
 {
     return findDefinitionsIf(d->m_defs, anyWildcardMatches(fileNameFromFilePath(fileName)));
 }
@@ -137,22 +137,22 @@ Definition Repository::definitionForMimeType(const QString &mimeType) const
     return findHighestPriorityDefinitionIf(d->m_defs, anyMimeTypeEquals(mimeType));
 }
 
-QVector Repository::definitionsForMimeType(const QString &mimeType) const
+QList Repository::definitionsForMimeType(const QString &mimeType) const
 {
     return findDefinitionsIf(d->m_defs, anyMimeTypeEquals(mimeType));
 }
 
-QVector Repository::definitions() const
+QList Repository::definitions() const
 {
     return d->m_sortedDefs;
 }
 
-QVector Repository::themes() const
+QList Repository::themes() const
 {
     return d->m_themes;
 }
 
-static auto lowerBoundTheme(const QVector &themes, QStringView themeName)
+static auto lowerBoundTheme(const QList &themes, QStringView themeName)
 {
     return std::lower_bound(themes.begin(), themes.end(), themeName, [](const Theme &lhs, QStringView rhs) {
         return lhs.name() < rhs;
@@ -177,42 +177,32 @@ Theme Repository::defaultTheme(Repository::DefaultTheme t) const
     return theme(QStringLiteral("Breeze Light"));
 }
 
-Theme Repository::defaultTheme(Repository::DefaultTheme t)
-{
-    return std::as_const(*this).defaultTheme(t);
-}
-
 Theme Repository::themeForPalette(const QPalette &palette) const
 {
     const auto base = palette.color(QPalette::Base);
+    const auto highlight = palette.color(QPalette::Highlight).rgb();
 
-    // find themes with matching background colors
-    QVector matchingThemes;
+    // find themes with matching background and highlight colors
+    const Theme *firstMatchingTheme = nullptr;
     for (const auto &theme : std::as_const(d->m_themes)) {
-        const auto background = theme.editorColor(KSyntaxHighlighting::Theme::EditorColorRole::BackgroundColor);
+        const auto background = theme.editorColor(Theme::EditorColorRole::BackgroundColor);
         if (background == base.rgb()) {
-            matchingThemes.append(&theme);
-        }
-    }
-    if (!matchingThemes.empty()) {
-        // if there's multiple, search for one with a matching highlight color
-        const auto highlight = palette.color(QPalette::Highlight);
-        for (const auto *theme : std::as_const(matchingThemes)) {
-            auto selection = theme->editorColor(KSyntaxHighlighting::Theme::EditorColorRole::TextSelection);
-            if (selection == highlight.rgb()) {
-                return *theme;
+            // find theme with a matching highlight color
+            auto selection = theme.editorColor(Theme::EditorColorRole::TextSelection);
+            if (selection == highlight) {
+                return theme;
+            }
+            if (!firstMatchingTheme) {
+                firstMatchingTheme = &theme;
             }
         }
-        return *matchingThemes.first();
+    }
+    if (firstMatchingTheme) {
+        return *firstMatchingTheme;
     }
 
     // fallback to just use the default light or dark theme
-    return defaultTheme((base.lightness() < 128) ? KSyntaxHighlighting::Repository::DarkTheme : KSyntaxHighlighting::Repository::LightTheme);
-}
-
-Theme Repository::themeForPalette(const QPalette &palette)
-{
-    return std::as_const(*this).themeForPalette(palette);
+    return defaultTheme((base.lightness() < 128) ? Repository::DarkTheme : Repository::LightTheme);
 }
 
 void RepositoryPrivate::load(Repository *repo)
@@ -238,12 +228,6 @@ void RepositoryPrivate::load(Repository *repo)
                                                      QStandardPaths::LocateDirectory)) {
         loadSyntaxFolder(repo, dir);
     }
-
-    // backward compatibility with Kate
-    for (const auto &dir :
-         QStandardPaths::locateAll(QStandardPaths::GenericDataLocation, QStringLiteral("katepart5/syntax"), QStandardPaths::LocateDirectory)) {
-        loadSyntaxFolder(repo, dir);
-    }
 #endif
 
     // default resources are always used, this is the one location that has a index cbor file
@@ -377,25 +361,27 @@ void RepositoryPrivate::addTheme(const Theme &theme)
     }
 }
 
-quint16 RepositoryPrivate::foldingRegionId(const QString &defName, const QString &foldName)
+int RepositoryPrivate::foldingRegionId(const QString &defName, const QString &foldName)
 {
     const auto it = m_foldingRegionIds.constFind(qMakePair(defName, foldName));
     if (it != m_foldingRegionIds.constEnd()) {
         return it.value();
     }
+    Q_ASSERT(m_foldingRegionId < std::numeric_limits::max());
     m_foldingRegionIds.insert(qMakePair(defName, foldName), ++m_foldingRegionId);
     return m_foldingRegionId;
 }
 
-quint16 RepositoryPrivate::nextFormatId()
+int RepositoryPrivate::nextFormatId()
 {
-    Q_ASSERT(m_formatId < std::numeric_limits::max());
+    Q_ASSERT(m_formatId < std::numeric_limits::max());
     return ++m_formatId;
 }
 
 void Repository::reload()
 {
-    qCDebug(Log) << "Reloading syntax definitions!";
+    Q_EMIT aboutToReload();
+
     for (const auto &def : std::as_const(d->m_sortedDefs)) {
         DefinitionData::get(def)->clear();
     }
@@ -410,6 +396,8 @@ void Repository::reload()
     d->m_formatId = 0;
 
     d->load(this);
+
+    Q_EMIT reloaded();
 }
 
 void Repository::addCustomSearchPath(const QString &path)
@@ -418,7 +406,9 @@ void Repository::addCustomSearchPath(const QString &path)
     reload();
 }
 
-QVector Repository::customSearchPaths() const
+QList Repository::customSearchPaths() const
 {
     return d->m_customSearchPaths;
 }
+
+#include "moc_repository.cpp"
diff --git a/src/libs/3rdparty/syntax-highlighting/src/lib/repository.h b/src/libs/3rdparty/syntax-highlighting/src/lib/repository.h
index 7c74753bfe3..612ba54d6a4 100644
--- a/src/libs/3rdparty/syntax-highlighting/src/lib/repository.h
+++ b/src/libs/3rdparty/syntax-highlighting/src/lib/repository.h
@@ -9,7 +9,8 @@
 
 #include "ksyntaxhighlighting_export.h"
 
-#include 
+#include 
+#include 
 #include 
 
 #include 
@@ -76,13 +77,6 @@ class Theme;
  *    map to $HOME/.local5/share/org.kde.syntax-highlighting/syntax and
  *    /usr/share/org.kde.syntax-highlighting/syntax.
  *
- * -# Next, for backwards compatibility with Kate, all syntax highlighting
- *    files are loaded that are located in
- *    QStandardPaths::locateAll(QStandardPaths::GenericDataLocation, QStringLiteral("katepart5/syntax"), QStandardPaths::LocateDirectory);
- *    Again, under Unix, this uses $XDG_DATA_HOME and $XDG_DATA_DIRS, which
- *    could map to $HOME/.local5/share/katepart5/syntax and
- *    /usr/share/katepart5/syntax.
- *
  * -# Then, all files compiled into the library through resources are loaded.
  *    The internal resource path is ":/org.kde.syntax-highlighting/syntax".
  *    This path should never be touched by other applications.
@@ -124,8 +118,12 @@ class Theme;
  * @see Definition, Theme, AbstractHighlighter
  * @since 5.28
  */
-class KSYNTAXHIGHLIGHTING_EXPORT Repository
+class KSYNTAXHIGHLIGHTING_EXPORT Repository : public QObject
 {
+    Q_OBJECT
+    Q_PROPERTY(QList definitions READ definitions NOTIFY reloaded)
+    Q_PROPERTY(QList themes READ themes NOTIFY reloaded)
+
 public:
     /**
      * Create a new syntax definition repository.
@@ -148,7 +146,7 @@ public:
      *       Therefore, only the string "JavaScript" will return a valid
      *       Definition file.
      */
-    Definition definitionForName(const QString &defName) const;
+    Q_INVOKABLE KSyntaxHighlighting::Definition definitionForName(const QString &defName) const;
 
     /**
      * Returns the best matching Definition for the file named @p fileName.
@@ -159,7 +157,7 @@ public:
      * If no match is found, Definition::isValid() of the returned instance
      * returns false.
      */
-    Definition definitionForFileName(const QString &fileName) const;
+    Q_INVOKABLE KSyntaxHighlighting::Definition definitionForFileName(const QString &fileName) const;
 
     /**
      * Returns all Definition%s for the file named @p fileName sorted by priority.
@@ -168,7 +166,7 @@ public:
      *
      * @since 5.56
      */
-    QVector definitionsForFileName(const QString &fileName) const;
+    Q_INVOKABLE QList definitionsForFileName(const QString &fileName) const;
 
     /**
      * Returns the best matching Definition to the type named @p mimeType
@@ -178,34 +176,34 @@ public:
      *
      * @since 5.50
      */
-    Definition definitionForMimeType(const QString &mimeType) const;
+    Q_INVOKABLE KSyntaxHighlighting::Definition definitionForMimeType(const QString &mimeType) const;
 
     /**
      * Returns all Definition%s to the type named @p mimeType sorted by priority
      *
      * @since 5.56
      */
-    QVector definitionsForMimeType(const QString &mimeType) const;
+    Q_INVOKABLE QList definitionsForMimeType(const QString &mimeType) const;
 
     /**
      * Returns all available Definition%s.
      * Definition%ss are ordered by translated section and translated names,
      * for consistent displaying.
      */
-    QVector definitions() const;
+    Q_INVOKABLE QList definitions() const;
 
     /**
      * Returns all available color themes.
      * The returned list should never be empty.
      */
-    QVector themes() const;
+    Q_INVOKABLE QList themes() const;
 
     /**
      * Returns the theme called @p themeName.
      * If the requested theme cannot be found, the retunred Theme is invalid,
      * see Theme::isValid().
      */
-    Theme theme(const QString &themeName) const;
+    Q_INVOKABLE KSyntaxHighlighting::Theme theme(const QString &themeName) const;
 
     /**
      * Built-in default theme types.
@@ -217,21 +215,14 @@ public:
         //! Theme with a dark background color.
         DarkTheme
     };
+    Q_ENUM(DefaultTheme)
 
     /**
      * Returns a default theme instance of the given type.
      * The returned Theme is guaranteed to be a valid theme.
      * @since 5.79
      */
-    Theme defaultTheme(DefaultTheme t = LightTheme) const;
-
-    /**
-     * Returns a default theme instance of the given type.
-     * The returned Theme is guaranteed to be a valid theme.
-     *
-     * KF6: remove in favor of const variant
-     */
-    Theme defaultTheme(DefaultTheme t = LightTheme);
+    Q_INVOKABLE KSyntaxHighlighting::Theme defaultTheme(DefaultTheme t = LightTheme) const;
 
     /**
      * Returns the best matching theme for the given palette
@@ -239,14 +230,6 @@ public:
      **/
     Theme themeForPalette(const QPalette &palette) const;
 
-    /**
-     * Returns the best matching theme for the given palette
-     * @since 5.77
-     *
-     * KF6: remove in favor of const variant
-     **/
-    Theme themeForPalette(const QPalette &palette);
-
     /**
      * Reloads the repository.
      * This is a moderately expensive operations and should thus only be
@@ -278,7 +261,20 @@ public:
      * @see addCustomSearchPath()
      * @since 5.39
      */
-    QVector customSearchPaths() const;
+    QList customSearchPaths() const;
+
+Q_SIGNALS:
+    /**
+     * This signal is emitted before the reload is started.
+     * @since 6.0
+     */
+    void aboutToReload();
+
+    /**
+     * This signal is emitted when the reload is finished.
+     * @since 6.0
+     */
+    void reloaded();
 
 private:
     Q_DISABLE_COPY(Repository)
diff --git a/src/libs/3rdparty/syntax-highlighting/src/lib/repository_p.h b/src/libs/3rdparty/syntax-highlighting/src/lib/repository_p.h
index 447cfae6990..bb9f8ba0820 100644
--- a/src/libs/3rdparty/syntax-highlighting/src/lib/repository_p.h
+++ b/src/libs/3rdparty/syntax-highlighting/src/lib/repository_p.h
@@ -8,11 +8,11 @@
 #define KSYNTAXHIGHLIGHTING_REPOSITORY_P_H
 
 #include 
-#include 
+#include 
+#include 
+#include 
 
-QT_BEGIN_NAMESPACE
-class QString;
-QT_END_NAMESPACE
+#include "dynamicregexpcache_p.h"
 
 namespace KSyntaxHighlighting
 {
@@ -36,22 +36,24 @@ public:
     void loadThemeFolder(const QString &path);
     void addTheme(const Theme &theme);
 
-    quint16 foldingRegionId(const QString &defName, const QString &foldName);
-    quint16 nextFormatId();
+    int foldingRegionId(const QString &defName, const QString &foldName);
+    int nextFormatId();
 
-    QVector m_customSearchPaths;
+    QList m_customSearchPaths;
 
     // sorted map to have deterministic iteration order for e.g. definitionsForFileName
     QMap m_defs;
 
     // this vector is sorted by translated sections/names
-    QVector m_sortedDefs;
+    QList m_sortedDefs;
 
-    QVector m_themes;
+    QList m_themes;
 
-    QHash, quint16> m_foldingRegionIds;
-    quint16 m_foldingRegionId = 0;
-    quint16 m_formatId = 0;
+    QHash, int> m_foldingRegionIds;
+    int m_foldingRegionId = 0;
+    int m_formatId = 0;
+
+    DynamicRegexpCache m_dynamicRegexpCache;
 };
 }
 
diff --git a/src/libs/3rdparty/syntax-highlighting/src/lib/rule.cpp b/src/libs/3rdparty/syntax-highlighting/src/lib/rule.cpp
index 1d02bd6ac34..186ed16120d 100644
--- a/src/libs/3rdparty/syntax-highlighting/src/lib/rule.cpp
+++ b/src/libs/3rdparty/syntax-highlighting/src/lib/rule.cpp
@@ -1,20 +1,19 @@
 /*
     SPDX-FileCopyrightText: 2016 Volker Krause 
     SPDX-FileCopyrightText: 2018 Christoph Cullmann 
-    SPDX-FileCopyrightText: 2020 Jonathan Poelen 
+    SPDX-FileCopyrightText: 2020 Jonathan Poelen 
 
     SPDX-License-Identifier: MIT
 */
 
 #include "context_p.h"
 #include "definition_p.h"
+#include "dynamicregexpcache_p.h"
 #include "ksyntaxhighlighting_logging.h"
 #include "rule_p.h"
 #include "worddelimiters_p.h"
 #include "xml_p.h"
 
-#include 
-
 using namespace KSyntaxHighlighting;
 
 // QChar::isDigit() match any digit in unicode (romain numeral, etc)
@@ -90,8 +89,8 @@ static int matchEscapedChar(QStringView text, int offset)
 static QString replaceCaptures(const QString &pattern, const QStringList &captures, bool quote)
 {
     auto result = pattern;
-    for (int i = captures.size() - 1; i >= 1; --i) {
-        result.replace(QLatin1Char('%') + QString::number(i), quote ? QRegularExpression::escape(captures.at(i)) : captures.at(i));
+    for (int i = captures.size(); i >= 1; --i) {
+        result.replace(QLatin1Char('%') + QString::number(i), quote ? QRegularExpression::escape(captures.at(i - 1)) : captures.at(i - 1));
     }
     return result;
 }
@@ -233,7 +232,7 @@ AnyChar::AnyChar(const HighlightingContextData::Rule::AnyChar &data)
 {
 }
 
-MatchResult AnyChar::doMatch(QStringView text, int offset, const QStringList &) const
+MatchResult AnyChar::doMatch(QStringView text, int offset, const QStringList &, DynamicRegexpCache &) const
 {
     if (m_chars.contains(text.at(offset))) {
         return offset + 1;
@@ -243,15 +242,15 @@ MatchResult AnyChar::doMatch(QStringView text, int offset, const QStringList &)
 
 DetectChar::DetectChar(const HighlightingContextData::Rule::DetectChar &data)
     : m_char(data.char1)
-    , m_captureIndex(data.dynamic ? data.char1.digitValue() : 0)
+    , m_captureIndex((data.dynamic ? data.char1.digitValue() : 0) - 1)
 {
     m_dynamic = data.dynamic;
 }
 
-MatchResult DetectChar::doMatch(QStringView text, int offset, const QStringList &captures) const
+MatchResult DetectChar::doMatch(QStringView text, int offset, const QStringList &captures, DynamicRegexpCache &) const
 {
     if (m_dynamic) {
-        if (m_captureIndex == 0 || captures.size() <= m_captureIndex || captures.at(m_captureIndex).isEmpty()) {
+        if (m_captureIndex == -1 || captures.size() <= m_captureIndex || captures.at(m_captureIndex).isEmpty()) {
             return offset;
         }
         if (text.at(offset) == captures.at(m_captureIndex).at(0)) {
@@ -272,7 +271,7 @@ Detect2Chars::Detect2Chars(const HighlightingContextData::Rule::Detect2Chars &da
 {
 }
 
-MatchResult Detect2Chars::doMatch(QStringView text, int offset, const QStringList &) const
+MatchResult Detect2Chars::doMatch(QStringView text, int offset, const QStringList &, DynamicRegexpCache &) const
 {
     if (text.size() - offset < 2) {
         return offset;
@@ -283,7 +282,7 @@ MatchResult Detect2Chars::doMatch(QStringView text, int offset, const QStringLis
     return offset;
 }
 
-MatchResult DetectIdentifier::doMatch(QStringView text, int offset, const QStringList &) const
+MatchResult DetectIdentifier::doMatch(QStringView text, int offset, const QStringList &, DynamicRegexpCache &) const
 {
     if (!text.at(offset).isLetter() && text.at(offset) != QLatin1Char('_')) {
         return offset;
@@ -299,7 +298,7 @@ MatchResult DetectIdentifier::doMatch(QStringView text, int offset, const QStrin
     return text.size();
 }
 
-MatchResult DetectSpaces::doMatch(QStringView text, int offset, const QStringList &) const
+MatchResult DetectSpaces::doMatch(QStringView text, int offset, const QStringList &, DynamicRegexpCache &) const
 {
     while (offset < text.size() && text.at(offset).isSpace()) {
         ++offset;
@@ -313,7 +312,7 @@ Float::Float(DefinitionData &def, const HighlightingContextData::Rule::Float &da
     resolveAdditionalWordDelimiters(m_wordDelimiters, data.wordDelimiters);
 }
 
-MatchResult Float::doMatch(QStringView text, int offset, const QStringList &) const
+MatchResult Float::doMatch(QStringView text, int offset, const QStringList &, DynamicRegexpCache &) const
 {
     if (offset > 0 && !m_wordDelimiters.contains(text.at(offset - 1))) {
         return offset;
@@ -358,7 +357,7 @@ MatchResult Float::doMatch(QStringView text, int offset, const QStringList &) co
     return expOffset;
 }
 
-MatchResult HlCChar::doMatch(QStringView text, int offset, const QStringList &) const
+MatchResult HlCChar::doMatch(QStringView text, int offset, const QStringList &, DynamicRegexpCache &) const
 {
     if (text.size() < offset + 3) {
         return offset;
@@ -393,7 +392,7 @@ HlCHex::HlCHex(DefinitionData &def, const HighlightingContextData::Rule::HlCHex
     resolveAdditionalWordDelimiters(m_wordDelimiters, data.wordDelimiters);
 }
 
-MatchResult HlCHex::doMatch(QStringView text, int offset, const QStringList &) const
+MatchResult HlCHex::doMatch(QStringView text, int offset, const QStringList &, DynamicRegexpCache &) const
 {
     if (offset > 0 && !m_wordDelimiters.contains(text.at(offset - 1))) {
         return offset;
@@ -427,7 +426,7 @@ HlCOct::HlCOct(DefinitionData &def, const HighlightingContextData::Rule::HlCOct
     resolveAdditionalWordDelimiters(m_wordDelimiters, data.wordDelimiters);
 }
 
-MatchResult HlCOct::doMatch(QStringView text, int offset, const QStringList &) const
+MatchResult HlCOct::doMatch(QStringView text, int offset, const QStringList &, DynamicRegexpCache &) const
 {
     if (offset > 0 && !m_wordDelimiters.contains(text.at(offset - 1))) {
         return offset;
@@ -453,7 +452,7 @@ MatchResult HlCOct::doMatch(QStringView text, int offset, const QStringList &) c
     return offset;
 }
 
-MatchResult HlCStringChar::doMatch(QStringView text, int offset, const QStringList &) const
+MatchResult HlCStringChar::doMatch(QStringView text, int offset, const QStringList &, DynamicRegexpCache &) const
 {
     return matchEscapedChar(text, offset);
 }
@@ -464,7 +463,7 @@ IncludeRules::IncludeRules(const HighlightingContextData::Rule::IncludeRules &da
 {
 }
 
-MatchResult IncludeRules::doMatch(QStringView text, int offset, const QStringList &) const
+MatchResult IncludeRules::doMatch(QStringView text, int offset, const QStringList &, DynamicRegexpCache &) const
 {
     Q_UNUSED(text);
     qCWarning(Log) << "Unresolved include rule";
@@ -477,7 +476,7 @@ Int::Int(DefinitionData &def, const HighlightingContextData::Rule::Int &data)
     resolveAdditionalWordDelimiters(m_wordDelimiters, data.wordDelimiters);
 }
 
-MatchResult Int::doMatch(QStringView text, int offset, const QStringList &) const
+MatchResult Int::doMatch(QStringView text, int offset, const QStringList &, DynamicRegexpCache &) const
 {
     if (offset > 0 && !m_wordDelimiters.contains(text.at(offset - 1))) {
         return offset;
@@ -521,9 +520,10 @@ KeywordListRule::KeywordListRule(const KeywordList &keywordList, DefinitionData
     , m_caseSensitivity(data.hasCaseSensitivityOverride ? data.caseSensitivityOverride : keywordList.caseSensitivity())
 {
     resolveAdditionalWordDelimiters(m_wordDelimiters, data.wordDelimiters);
+    m_hasSkipOffset = true;
 }
 
-MatchResult KeywordListRule::doMatch(QStringView text, int offset, const QStringList &) const
+MatchResult KeywordListRule::doMatch(QStringView text, int offset, const QStringList &, DynamicRegexpCache &) const
 {
     auto newOffset = offset;
     while (text.size() > newOffset && !m_wordDelimiters.contains(text.at(newOffset))) {
@@ -546,7 +546,7 @@ LineContinue::LineContinue(const HighlightingContextData::Rule::LineContinue &da
 {
 }
 
-MatchResult LineContinue::doMatch(QStringView text, int offset, const QStringList &) const
+MatchResult LineContinue::doMatch(QStringView text, int offset, const QStringList &, DynamicRegexpCache &) const
 {
     if (offset == text.size() - 1 && text.at(offset) == m_char) {
         return offset + 1;
@@ -560,7 +560,7 @@ RangeDetect::RangeDetect(const HighlightingContextData::Rule::RangeDetect &data)
 {
 }
 
-MatchResult RangeDetect::doMatch(QStringView text, int offset, const QStringList &) const
+MatchResult RangeDetect::doMatch(QStringView text, int offset, const QStringList &, DynamicRegexpCache &) const
 {
     if (text.size() - offset < 2) {
         return offset;
@@ -591,25 +591,16 @@ static QRegularExpression::PatternOptions makePattenOptions(const HighlightingCo
 
 static void resolveRegex(QRegularExpression ®exp, Context *context)
 {
-    if (!regexp.isValid()) {
-        // DontCaptureOption with back reference capture is an error, remove this option then try again
-        regexp.setPatternOptions(regexp.patternOptions() & ~QRegularExpression::DontCaptureOption);
+    bool enableCapture = context && context->hasDynamicRule();
 
-        if (!regexp.isValid()) {
-            qCDebug(Log) << "Invalid regexp:" << regexp.pattern();
-        }
-
-        return;
+    // disable DontCaptureOption when reference a context with dynamic rule or
+    // with invalid regex because DontCaptureOption with back reference capture is an error
+    if (enableCapture || !regexp.isValid()) {
+        regexp.setPatternOptions(regexp.patternOptions() & ~QRegularExpression::DontCaptureOption);
     }
 
-    // disable DontCaptureOption when reference a context with dynamic rule
-    if (context) {
-        for (const Rule::Ptr &rule : context->rules()) {
-            if (rule->isDynamic()) {
-                regexp.setPatternOptions(regexp.patternOptions() & ~QRegularExpression::DontCaptureOption);
-                break;
-            }
-        }
+    if (!regexp.isValid()) {
+        qCDebug(Log) << "Invalid regexp:" << regexp.pattern();
     }
 }
 
@@ -618,15 +609,25 @@ static MatchResult regexMatch(const QRegularExpression ®exp, QStringView text
     /**
      * match the pattern
      */
+#if QT_VERSION >= QT_VERSION_CHECK(6, 5, 0)
+    const auto result = regexp.matchView(text, offset, QRegularExpression::NormalMatch, QRegularExpression::DontCheckSubjectStringMatchOption);
+#else
     const auto result = regexp.match(text, offset, QRegularExpression::NormalMatch, QRegularExpression::DontCheckSubjectStringMatchOption);
+#endif
     if (result.capturedStart() == offset) {
         /**
          * we only need to compute the captured texts if we have real capture groups
          * highlightings should only address %1..%.., see e.g. replaceCaptures
          * DetectChar ignores %0, too
          */
-        if (result.lastCapturedIndex() > 0) {
-            return MatchResult(offset + result.capturedLength(), result.capturedTexts());
+        int lastCapturedIndex = result.lastCapturedIndex();
+        if (lastCapturedIndex > 0) {
+            QStringList captures;
+            captures.reserve(lastCapturedIndex);
+            // ignore the capturing group number 0
+            for (int i = 1; i <= lastCapturedIndex; ++i)
+                captures.push_back(result.captured(i));
+            return MatchResult(offset + result.capturedLength(), std::move(captures));
         }
 
         /**
@@ -645,20 +646,17 @@ static MatchResult regexMatch(const QRegularExpression ®exp, QStringView text
 RegExpr::RegExpr(const HighlightingContextData::Rule::RegExpr &data)
     : m_regexp(data.pattern, makePattenOptions(data))
 {
+    m_hasSkipOffset = true;
 }
 
 void RegExpr::resolve()
 {
-    if (m_isResolved) {
-        return;
-    }
-
     m_isResolved = true;
 
     resolveRegex(m_regexp, context().context());
 }
 
-MatchResult RegExpr::doMatch(QStringView text, int offset, const QStringList &) const
+MatchResult RegExpr::doMatch(QStringView text, int offset, const QStringList &, DynamicRegexpCache &) const
 {
     if (Q_UNLIKELY(!m_isResolved)) {
         const_cast(this)->resolve();
@@ -672,14 +670,11 @@ DynamicRegExpr::DynamicRegExpr(const HighlightingContextData::Rule::RegExpr &dat
     , m_patternOptions(makePattenOptions(data))
 {
     m_dynamic = true;
+    m_hasSkipOffset = true;
 }
 
 void DynamicRegExpr::resolve()
 {
-    if (m_isResolved) {
-        return;
-    }
-
     m_isResolved = true;
 
     QRegularExpression regexp(m_pattern, m_patternOptions);
@@ -687,7 +682,7 @@ void DynamicRegExpr::resolve()
     m_patternOptions = regexp.patternOptions();
 }
 
-MatchResult DynamicRegExpr::doMatch(QStringView text, int offset, const QStringList &captures) const
+MatchResult DynamicRegExpr::doMatch(QStringView text, int offset, const QStringList &captures, DynamicRegexpCache &dynamicRegexpCache) const
 {
     if (Q_UNLIKELY(!m_isResolved)) {
         const_cast(this)->resolve();
@@ -696,8 +691,8 @@ MatchResult DynamicRegExpr::doMatch(QStringView text, int offset, const QStringL
     /**
      * create new pattern with right instantiation
      */
-    const QRegularExpression regexp(replaceCaptures(m_pattern, captures, true), m_patternOptions);
-
+    auto pattern = replaceCaptures(m_pattern, captures, true);
+    auto ®exp = dynamicRegexpCache.compileRegexp(std::move(pattern), m_patternOptions);
     return regexMatch(regexp, text, offset);
 }
 
@@ -707,7 +702,7 @@ StringDetect::StringDetect(const HighlightingContextData::Rule::StringDetect &da
 {
 }
 
-MatchResult StringDetect::doMatch(QStringView text, int offset, const QStringList &) const
+MatchResult StringDetect::doMatch(QStringView text, int offset, const QStringList &, DynamicRegexpCache &) const
 {
     return matchString(m_string, text, offset, m_caseSensitivity);
 }
@@ -719,7 +714,7 @@ DynamicStringDetect::DynamicStringDetect(const HighlightingContextData::Rule::St
     m_dynamic = true;
 }
 
-MatchResult DynamicStringDetect::doMatch(QStringView text, int offset, const QStringList &captures) const
+MatchResult DynamicStringDetect::doMatch(QStringView text, int offset, const QStringList &captures, DynamicRegexpCache &) const
 {
     /**
      * for dynamic case: create new pattern with right instantiation
@@ -736,7 +731,7 @@ WordDetect::WordDetect(DefinitionData &def, const HighlightingContextData::Rule:
     resolveAdditionalWordDelimiters(m_wordDelimiters, data.wordDelimiters);
 }
 
-MatchResult WordDetect::doMatch(QStringView text, int offset, const QStringList &) const
+MatchResult WordDetect::doMatch(QStringView text, int offset, const QStringList &, DynamicRegexpCache &) const
 {
     if (text.size() - offset < m_word.size()) {
         return offset;
diff --git a/src/libs/3rdparty/syntax-highlighting/src/lib/rule_p.h b/src/libs/3rdparty/syntax-highlighting/src/lib/rule_p.h
index 7536d92e803..bc5f367ad67 100644
--- a/src/libs/3rdparty/syntax-highlighting/src/lib/rule_p.h
+++ b/src/libs/3rdparty/syntax-highlighting/src/lib/rule_p.h
@@ -27,6 +27,7 @@ namespace KSyntaxHighlighting
 class WordDelimiters;
 class DefinitionData;
 class IncludeRules;
+class DynamicRegexpCache;
 
 class Rule
 {
@@ -83,7 +84,15 @@ public:
         return m_type == Type::LineContinue;
     }
 
-    virtual MatchResult doMatch(QStringView text, int offset, const QStringList &captures) const = 0;
+    // If true, then the rule uses the skipOffset parameter of MatchResult.
+    // This is used by AbstractHighlighter::highlightLine() to look for a rule
+    // in the skipOffsets cache only if it can be found there.
+    bool hasSkipOffset() const
+    {
+        return m_hasSkipOffset;
+    }
+
+    virtual MatchResult doMatch(QStringView text, int offset, const QStringList &captures, DynamicRegexpCache &dynamicRegexpCache) const = 0;
 
     static Rule::Ptr create(DefinitionData &def, const HighlightingContextData::Rule &ruleData, QStringView lookupContextName);
 
@@ -98,6 +107,7 @@ private:
         IncludeRules,
     };
 
+private:
     Format m_attributeFormat;
     ContextSwitch m_context;
     int m_column = -1;
@@ -108,6 +118,7 @@ private:
     bool m_lookAhead = false;
 
 protected:
+    bool m_hasSkipOffset = false;
     bool m_dynamic = false;
 };
 
@@ -117,10 +128,10 @@ public:
     AnyChar(const HighlightingContextData::Rule::AnyChar &data);
 
 protected:
-    MatchResult doMatch(QStringView text, int offset, const QStringList &) const override;
+    MatchResult doMatch(QStringView text, int offset, const QStringList &, DynamicRegexpCache &) const override;
 
 private:
-    QString m_chars;
+    WordDelimiters m_chars;
 };
 
 class DetectChar final : public Rule
@@ -129,7 +140,7 @@ public:
     DetectChar(const HighlightingContextData::Rule::DetectChar &data);
 
 protected:
-    MatchResult doMatch(QStringView text, int offset, const QStringList &) const override;
+    MatchResult doMatch(QStringView text, int offset, const QStringList &, DynamicRegexpCache &) const override;
 
 private:
     QChar m_char;
@@ -142,7 +153,7 @@ public:
     Detect2Chars(const HighlightingContextData::Rule::Detect2Chars &data);
 
 protected:
-    MatchResult doMatch(QStringView text, int offset, const QStringList &) const override;
+    MatchResult doMatch(QStringView text, int offset, const QStringList &, DynamicRegexpCache &) const override;
 
 private:
     QChar m_char1;
@@ -152,13 +163,13 @@ private:
 class DetectIdentifier final : public Rule
 {
 protected:
-    MatchResult doMatch(QStringView text, int offset, const QStringList &) const override;
+    MatchResult doMatch(QStringView text, int offset, const QStringList &, DynamicRegexpCache &) const override;
 };
 
 class DetectSpaces final : public Rule
 {
 protected:
-    MatchResult doMatch(QStringView text, int offset, const QStringList &) const override;
+    MatchResult doMatch(QStringView text, int offset, const QStringList &, DynamicRegexpCache &) const override;
 };
 
 class Float final : public Rule
@@ -167,7 +178,7 @@ public:
     Float(DefinitionData &def, const HighlightingContextData::Rule::Float &data);
 
 protected:
-    MatchResult doMatch(QStringView text, int offset, const QStringList &) const override;
+    MatchResult doMatch(QStringView text, int offset, const QStringList &, DynamicRegexpCache &) const override;
 
 private:
     WordDelimiters m_wordDelimiters;
@@ -189,7 +200,7 @@ public:
     }
 
 protected:
-    MatchResult doMatch(QStringView text, int offset, const QStringList &) const override;
+    MatchResult doMatch(QStringView text, int offset, const QStringList &, DynamicRegexpCache &) const override;
 
 private:
     QString m_contextName;
@@ -202,7 +213,7 @@ public:
     Int(DefinitionData &def, const HighlightingContextData::Rule::Int &data);
 
 protected:
-    MatchResult doMatch(QStringView text, int offset, const QStringList &) const override;
+    MatchResult doMatch(QStringView text, int offset, const QStringList &, DynamicRegexpCache &) const override;
 
 private:
     WordDelimiters m_wordDelimiters;
@@ -211,7 +222,7 @@ private:
 class HlCChar final : public Rule
 {
 protected:
-    MatchResult doMatch(QStringView text, int offset, const QStringList &) const override;
+    MatchResult doMatch(QStringView text, int offset, const QStringList &, DynamicRegexpCache &) const override;
 };
 
 class HlCHex final : public Rule
@@ -220,7 +231,7 @@ public:
     HlCHex(DefinitionData &def, const HighlightingContextData::Rule::HlCHex &data);
 
 protected:
-    MatchResult doMatch(QStringView text, int offset, const QStringList &) const override;
+    MatchResult doMatch(QStringView text, int offset, const QStringList &, DynamicRegexpCache &) const override;
 
 private:
     WordDelimiters m_wordDelimiters;
@@ -232,7 +243,7 @@ public:
     HlCOct(DefinitionData &def, const HighlightingContextData::Rule::HlCOct &data);
 
 protected:
-    MatchResult doMatch(QStringView text, int offset, const QStringList &) const override;
+    MatchResult doMatch(QStringView text, int offset, const QStringList &, DynamicRegexpCache &) const override;
 
 private:
     WordDelimiters m_wordDelimiters;
@@ -241,7 +252,7 @@ private:
 class HlCStringChar final : public Rule
 {
 protected:
-    MatchResult doMatch(QStringView text, int offset, const QStringList &) const override;
+    MatchResult doMatch(QStringView text, int offset, const QStringList &, DynamicRegexpCache &) const override;
 };
 
 class KeywordListRule final : public Rule
@@ -252,7 +263,7 @@ public:
     static Rule::Ptr create(DefinitionData &def, const HighlightingContextData::Rule::Keyword &data, QStringView lookupContextName);
 
 protected:
-    MatchResult doMatch(QStringView text, int offset, const QStringList &) const override;
+    MatchResult doMatch(QStringView text, int offset, const QStringList &, DynamicRegexpCache &) const override;
 
 private:
     WordDelimiters m_wordDelimiters;
@@ -266,7 +277,7 @@ public:
     LineContinue(const HighlightingContextData::Rule::LineContinue &data);
 
 protected:
-    MatchResult doMatch(QStringView text, int offset, const QStringList &) const override;
+    MatchResult doMatch(QStringView text, int offset, const QStringList &, DynamicRegexpCache &) const override;
 
 private:
     QChar m_char;
@@ -278,7 +289,7 @@ public:
     RangeDetect(const HighlightingContextData::Rule::RangeDetect &data);
 
 protected:
-    MatchResult doMatch(QStringView text, int offset, const QStringList &) const override;
+    MatchResult doMatch(QStringView text, int offset, const QStringList &, DynamicRegexpCache &) const override;
 
 private:
     QChar m_begin;
@@ -291,7 +302,7 @@ public:
     RegExpr(const HighlightingContextData::Rule::RegExpr &data);
 
 protected:
-    MatchResult doMatch(QStringView text, int offset, const QStringList &) const override;
+    MatchResult doMatch(QStringView text, int offset, const QStringList &, DynamicRegexpCache &) const override;
 
 private:
     void resolve();
@@ -305,7 +316,7 @@ public:
     DynamicRegExpr(const HighlightingContextData::Rule::RegExpr &data);
 
 protected:
-    MatchResult doMatch(QStringView text, int offset, const QStringList &) const override;
+    MatchResult doMatch(QStringView text, int offset, const QStringList &, DynamicRegexpCache &) const override;
 
 private:
     void resolve();
@@ -320,7 +331,7 @@ public:
     StringDetect(const HighlightingContextData::Rule::StringDetect &data);
 
 protected:
-    MatchResult doMatch(QStringView text, int offset, const QStringList &) const override;
+    MatchResult doMatch(QStringView text, int offset, const QStringList &, DynamicRegexpCache &) const override;
 
 private:
     QString m_string;
@@ -333,7 +344,7 @@ public:
     DynamicStringDetect(const HighlightingContextData::Rule::StringDetect &data);
 
 protected:
-    MatchResult doMatch(QStringView text, int offset, const QStringList &) const override;
+    MatchResult doMatch(QStringView text, int offset, const QStringList &, DynamicRegexpCache &) const override;
 
 private:
     QString m_string;
@@ -346,7 +357,7 @@ public:
     WordDetect(DefinitionData &def, const HighlightingContextData::Rule::WordDetect &data);
 
 protected:
-    MatchResult doMatch(QStringView text, int offset, const QStringList &) const override;
+    MatchResult doMatch(QStringView text, int offset, const QStringList &, DynamicRegexpCache &) const override;
 
 private:
     WordDelimiters m_wordDelimiters;
diff --git a/src/libs/3rdparty/syntax-highlighting/src/lib/state.cpp b/src/libs/3rdparty/syntax-highlighting/src/lib/state.cpp
index fc44a6dbd4c..dca58b35b7c 100644
--- a/src/libs/3rdparty/syntax-highlighting/src/lib/state.cpp
+++ b/src/libs/3rdparty/syntax-highlighting/src/lib/state.cpp
@@ -1,4 +1,4 @@
-/*
+/*
     SPDX-FileCopyrightText: 2016 Volker Krause 
     SPDX-FileCopyrightText: 2018 Christoph Cullmann 
 
@@ -14,36 +14,23 @@
 
 using namespace KSyntaxHighlighting;
 
-StateData *StateData::get(State &state)
+StateData *StateData::reset(State &state)
 {
-    // create state data on demand, to make default state construction cheap
-    if (!state.d) {
-        state.d = new StateData();
-    } else {
-        state.d.detach();
-    }
-    return state.d.data();
-}
-
-bool StateData::isEmpty() const
-{
-    return m_contextStack.isEmpty();
-}
-
-void StateData::clear()
-{
-    m_contextStack.clear();
+    auto *p = new StateData();
+    state.d.reset(p);
+    return p;
 }
 
-int StateData::size() const
+StateData *StateData::detach(State &state)
 {
-    return m_contextStack.size();
+    state.d.detach();
+    return state.d.data();
 }
 
-void StateData::push(Context *context, const QStringList &captures)
+void StateData::push(Context *context, QStringList &&captures)
 {
     Q_ASSERT(context);
-    m_contextStack.push_back(qMakePair(context, captures));
+    m_contextStack.push_back(StackValue{context, std::move(captures)});
 }
 
 bool StateData::pop(int popCount)
@@ -54,42 +41,23 @@ bool StateData::pop(int popCount)
     }
 
     // keep the initial context alive in any case
-    Q_ASSERT(!isEmpty());
-    const bool initialContextSurvived = m_contextStack.size() > popCount;
+    Q_ASSERT(!m_contextStack.empty());
+    const bool initialContextSurvived = int(m_contextStack.size()) > popCount;
     m_contextStack.resize(std::max(1, int(m_contextStack.size()) - popCount));
     return initialContextSurvived;
 }
 
-Context *StateData::topContext() const
-{
-    Q_ASSERT(!isEmpty());
-    return m_contextStack.last().first;
-}
+State::State() = default;
 
-const QStringList &StateData::topCaptures() const
-{
-    Q_ASSERT(!isEmpty());
-    return m_contextStack.last().second;
-}
+State::State(State &&other) noexcept = default;
 
-State::State()
-{
-}
+State::State(const State &other) noexcept = default;
 
-State::State(const State &other)
-    : d(other.d)
-{
-}
+State::~State() = default;
 
-State::~State()
-{
-}
+State &State::operator=(State &&other) noexcept = default;
 
-State &State::operator=(const State &other)
-{
-    d = other.d;
-    return *this;
-}
+State &State::operator=(const State &other) noexcept = default;
 
 bool State::operator==(const State &other) const
 {
@@ -104,8 +72,13 @@ bool State::operator!=(const State &other) const
 
 bool State::indentationBasedFoldingEnabled() const
 {
-    if (!d || d->m_contextStack.isEmpty()) {
+    if (!d || d->m_contextStack.empty()) {
         return false;
     }
-    return d->m_contextStack.last().first->indentationBasedFoldingEnabled();
+    return d->m_contextStack.back().context->indentationBasedFoldingEnabled();
+}
+
+std::size_t KSyntaxHighlighting::qHash(const State &state, std::size_t seed)
+{
+    return state.d ? qHashMulti(seed, *state.d) : 0;
 }
diff --git a/src/libs/3rdparty/syntax-highlighting/src/lib/state.h b/src/libs/3rdparty/syntax-highlighting/src/lib/state.h
index 726ff32a884..3003a9b7cbf 100644
--- a/src/libs/3rdparty/syntax-highlighting/src/lib/state.h
+++ b/src/libs/3rdparty/syntax-highlighting/src/lib/state.h
@@ -10,11 +10,15 @@
 #include "ksyntaxhighlighting_export.h"
 
 #include 
+#include 
 
 namespace KSyntaxHighlighting
 {
+class State;
 class StateData;
 
+KSYNTAXHIGHLIGHTING_EXPORT std::size_t qHash(const State &state, std::size_t seed = 0);
+
 /** Opaque handle to the state of the highlighting engine.
  *  This needs to be fed into AbstractHighlighter for every line of text
  *  and allows concrete highlighter implementations to store state per
@@ -29,9 +33,11 @@ public:
      *  in a document.
      */
     State();
-    State(const State &other);
+    State(State &&other) noexcept;
+    State(const State &other) noexcept;
     ~State();
-    State &operator=(const State &rhs);
+    State &operator=(State &&rhs) noexcept;
+    State &operator=(const State &rhs) noexcept;
 
     /** Compares two states for equality.
      *  For two equal states and identical text input, AbstractHighlighter
@@ -56,13 +62,13 @@ public:
 
 private:
     friend class StateData;
+    KSYNTAXHIGHLIGHTING_EXPORT friend std::size_t qHash(const State &, std::size_t);
     QExplicitlySharedDataPointer d;
 };
-
 }
 
 QT_BEGIN_NAMESPACE
-Q_DECLARE_TYPEINFO(KSyntaxHighlighting::State, Q_MOVABLE_TYPE);
+Q_DECLARE_TYPEINFO(KSyntaxHighlighting::State, Q_RELOCATABLE_TYPE);
 QT_END_NAMESPACE
 
 #endif // KSYNTAXHIGHLIGHTING_STATE_H
diff --git a/src/libs/3rdparty/syntax-highlighting/src/lib/state_p.h b/src/libs/3rdparty/syntax-highlighting/src/lib/state_p.h
index 0248330304f..4aee1416818 100644
--- a/src/libs/3rdparty/syntax-highlighting/src/lib/state_p.h
+++ b/src/libs/3rdparty/syntax-highlighting/src/lib/state_p.h
@@ -8,8 +8,10 @@
 #ifndef KSYNTAXHIGHLIGHTING_STATE_P_H
 #define KSYNTAXHIGHLIGHTING_STATE_P_H
 
+#include 
+
 #include 
-#include 
+#include 
 
 #include "definitionref_p.h"
 
@@ -21,15 +23,25 @@ class StateData : public QSharedData
 {
     friend class State;
     friend class AbstractHighlighter;
+    friend std::size_t qHash(const StateData &, std::size_t);
 
 public:
     StateData() = default;
-    static StateData *get(State &state);
 
-    bool isEmpty() const;
-    void clear();
-    int size() const;
-    void push(Context *context, const QStringList &captures);
+    static StateData *reset(State &state);
+    static StateData *detach(State &state);
+
+    static StateData *get(const State &state)
+    {
+        return state.d.data();
+    }
+
+    int size() const
+    {
+        return m_contextStack.size();
+    }
+
+    void push(Context *context, QStringList &&captures);
 
     /**
      * Pop the number of elements given from the top of the current stack.
@@ -39,8 +51,25 @@ public:
      */
     bool pop(int popCount);
 
-    Context *topContext() const;
-    const QStringList &topCaptures() const;
+    Context *topContext() const
+    {
+        return m_contextStack.back().context;
+    }
+
+    const QStringList &topCaptures() const
+    {
+        return m_contextStack.back().captures;
+    }
+
+    struct StackValue {
+        Context *context;
+        QStringList captures;
+
+        bool operator==(const StackValue &other) const
+        {
+            return context == other.context && captures == other.captures;
+        }
+    };
 
 private:
     /**
@@ -51,9 +80,18 @@ private:
     /**
      * the context stack combines the active context + valid captures
      */
-    QVector> m_contextStack;
+    std::vector m_contextStack;
 };
 
+inline std::size_t qHash(const StateData::StackValue &stackValue, std::size_t seed = 0)
+{
+    return qHashMulti(seed, stackValue.context, stackValue.captures);
+}
+
+inline std::size_t qHash(const StateData &k, std::size_t seed = 0)
+{
+    return qHashMulti(seed, k.m_defId, qHashRange(k.m_contextStack.begin(), k.m_contextStack.end(), seed));
+}
 }
 
 #endif
diff --git a/src/libs/3rdparty/syntax-highlighting/src/lib/syntaxhighlighter.cpp b/src/libs/3rdparty/syntax-highlighting/src/lib/syntaxhighlighter.cpp
index 4754da22c61..70b26a79bf8 100644
--- a/src/libs/3rdparty/syntax-highlighting/src/lib/syntaxhighlighter.cpp
+++ b/src/libs/3rdparty/syntax-highlighting/src/lib/syntaxhighlighter.cpp
@@ -7,10 +7,13 @@
 #include "syntaxhighlighter.h"
 #include "abstracthighlighter_p.h"
 #include "definition.h"
+#include "definition_p.h"
 #include "foldingregion.h"
 #include "format.h"
+#include "format_p.h"
 #include "state.h"
 #include "theme.h"
+#include "themedata_p.h"
 
 Q_DECLARE_METATYPE(QTextBlock)
 
@@ -22,14 +25,26 @@ class TextBlockUserData : public QTextBlockUserData
 {
 public:
     State state;
-    QVector foldingRegions;
+    QList foldingRegions;
 };
 
 class SyntaxHighlighterPrivate : public AbstractHighlighterPrivate
 {
 public:
     static FoldingRegion foldingRegion(const QTextBlock &startBlock);
-    QVector foldingRegions;
+    void initTextFormat(QTextCharFormat &tf, const Format &format);
+    void computeTextFormats();
+
+    struct TextFormat {
+        QTextCharFormat tf;
+        /**
+         * id to check that the format belongs to the definition
+         */
+        std::intptr_t ptrId;
+    };
+
+    QList foldingRegions;
+    std::vector tfs;
 };
 
 }
@@ -48,6 +63,52 @@ FoldingRegion SyntaxHighlighterPrivate::foldingRegion(const QTextBlock &startBlo
     return FoldingRegion();
 }
 
+void SyntaxHighlighterPrivate::initTextFormat(QTextCharFormat &tf, const Format &format)
+{
+    // always set the foreground color to avoid palette issues
+    tf.setForeground(format.textColor(m_theme));
+
+    if (format.hasBackgroundColor(m_theme)) {
+        tf.setBackground(format.backgroundColor(m_theme));
+    }
+    if (format.isBold(m_theme)) {
+        tf.setFontWeight(QFont::Bold);
+    }
+    if (format.isItalic(m_theme)) {
+        tf.setFontItalic(true);
+    }
+    if (format.isUnderline(m_theme)) {
+        tf.setFontUnderline(true);
+    }
+    if (format.isStrikeThrough(m_theme)) {
+        tf.setFontStrikeOut(true);
+    }
+}
+
+void SyntaxHighlighterPrivate::computeTextFormats()
+{
+    auto definitions = m_definition.includedDefinitions();
+    definitions.append(m_definition);
+
+    int maxId = 0;
+    for (const auto &definition : std::as_const(definitions)) {
+        for (const auto &format : std::as_const(DefinitionData::get(definition)->formats)) {
+            maxId = qMax(maxId, format.id());
+        }
+    }
+    tfs.clear();
+    tfs.resize(maxId + 1);
+
+    // initialize tfs
+    for (const auto &definition : std::as_const(definitions)) {
+        for (const auto &format : std::as_const(DefinitionData::get(definition)->formats)) {
+            auto &tf = tfs[format.id()];
+            tf.ptrId = FormatPrivate::ptrId(format);
+            initTextFormat(tf.tf, format);
+        }
+    }
+}
+
 SyntaxHighlighter::SyntaxHighlighter(QObject *parent)
     : QSyntaxHighlighter(parent)
     , AbstractHighlighter(new SyntaxHighlighterPrivate)
@@ -68,13 +129,27 @@ SyntaxHighlighter::~SyntaxHighlighter()
 
 void SyntaxHighlighter::setDefinition(const Definition &def)
 {
-    const auto needsRehighlight = definition() != def;
-    AbstractHighlighter::setDefinition(def);
+    Q_D(SyntaxHighlighter);
+
+    const auto needsRehighlight = d->m_definition != def;
+    if (DefinitionData::get(d->m_definition) != DefinitionData::get(def)) {
+        d->m_definition = def;
+        d->tfs.clear();
+    }
     if (needsRehighlight) {
         rehighlight();
     }
 }
 
+void SyntaxHighlighter::setTheme(const Theme &theme)
+{
+    Q_D(SyntaxHighlighter);
+    if (ThemeData::get(d->m_theme) != ThemeData::get(theme)) {
+        d->m_theme = theme;
+        d->tfs.clear();
+    }
+}
+
 bool SyntaxHighlighter::startsFoldingRegion(const QTextBlock &startBlock) const
 {
     return SyntaxHighlighterPrivate::foldingRegion(startBlock).type() == FoldingRegion::Begin;
@@ -92,13 +167,13 @@ QTextBlock SyntaxHighlighter::findFoldingRegionEnd(const QTextBlock &startBlock)
         if (!data) {
             continue;
         }
-        for (auto it = data->foldingRegions.constBegin(); it != data->foldingRegions.constEnd(); ++it) {
-            if ((*it).id() != region.id()) {
+        for (const auto &foldingRegion : std::as_const(data->foldingRegions)) {
+            if (foldingRegion.id() != region.id()) {
                 continue;
             }
-            if ((*it).type() == FoldingRegion::End) {
+            if (foldingRegion.type() == FoldingRegion::End) {
                 --depth;
-            } else if ((*it).type() == FoldingRegion::Begin) {
+            } else if (foldingRegion.type() == FoldingRegion::Begin) {
                 ++depth;
             }
             if (depth == 0) {
@@ -114,30 +189,31 @@ void SyntaxHighlighter::highlightBlock(const QString &text)
 {
     Q_D(SyntaxHighlighter);
 
-    State state;
+    static const State emptyState;
+    const State *previousState = &emptyState;
     if (currentBlock().position() > 0) {
         const auto prevBlock = currentBlock().previous();
         const auto prevData = dynamic_cast(prevBlock.userData());
         if (prevData) {
-            state = prevData->state;
+            previousState = &prevData->state;
         }
     }
     d->foldingRegions.clear();
-    state = highlightLine(text, state);
+    auto newState = highlightLine(text, *previousState);
 
     auto data = dynamic_cast(currentBlockUserData());
     if (!data) { // first time we highlight this
         data = new TextBlockUserData;
-        data->state = state;
+        data->state = std::move(newState);
         data->foldingRegions = d->foldingRegions;
         setCurrentBlockUserData(data);
         return;
     }
 
-    if (data->state == state && data->foldingRegions == d->foldingRegions) { // we ended up in the same state, so we are done here
+    if (data->state == newState && data->foldingRegions == d->foldingRegions) { // we ended up in the same state, so we are done here
         return;
     }
-    data->state = state;
+    data->state = std::move(newState);
     data->foldingRegions = d->foldingRegions;
 
     const auto nextBlock = currentBlock().next();
@@ -146,40 +222,35 @@ void SyntaxHighlighter::highlightBlock(const QString &text)
     }
 }
 
-void SyntaxHighlighter::applyFormat(int offset, int length, const KSyntaxHighlighting::Format &format)
+void SyntaxHighlighter::applyFormat(int offset, int length, const Format &format)
 {
     if (length == 0) {
         return;
     }
 
-    QTextCharFormat tf;
-    // always set the foreground color to avoid palette issues
-    tf.setForeground(format.textColor(theme()));
+    Q_D(SyntaxHighlighter);
 
-    if (format.hasBackgroundColor(theme())) {
-        tf.setBackground(format.backgroundColor(theme()));
-    }
-    if (format.isBold(theme())) {
-        tf.setFontWeight(QFont::Bold);
-    }
-    if (format.isItalic(theme())) {
-        tf.setFontItalic(true);
-    }
-    if (format.isUnderline(theme())) {
-        tf.setFontUnderline(true);
-    }
-    if (format.isStrikeThrough(theme())) {
-        tf.setFontStrikeOut(true);
+    if (Q_UNLIKELY(d->tfs.empty())) {
+        d->computeTextFormats();
     }
 
-    QSyntaxHighlighter::setFormat(offset, length, tf);
+    const auto id = static_cast(format.id());
+    // This doesn't happen when format comes from the definition.
+    // But as the user can override the function to pass any format, this is a possible scenario.
+    if (id < d->tfs.size() && d->tfs[id].ptrId == FormatPrivate::ptrId(format)) {
+        QSyntaxHighlighter::setFormat(offset, length, d->tfs[id].tf);
+    } else {
+        QTextCharFormat tf;
+        d->initTextFormat(tf, format);
+        QSyntaxHighlighter::setFormat(offset, length, tf);
+    }
 }
 
 void SyntaxHighlighter::applyFolding(int offset, int length, FoldingRegion region)
 {
     Q_UNUSED(offset);
     Q_UNUSED(length);
-    [[maybe_unused]] Q_D(SyntaxHighlighter);
+    Q_D(SyntaxHighlighter);
 
     if (region.type() == FoldingRegion::Begin) {
         d->foldingRegions.push_back(region);
@@ -196,3 +267,5 @@ void SyntaxHighlighter::applyFolding(int offset, int length, FoldingRegion regio
         d->foldingRegions.push_back(region);
     }
 }
+
+#include "moc_syntaxhighlighter.cpp"
diff --git a/src/libs/3rdparty/syntax-highlighting/src/lib/syntaxhighlighter.h b/src/libs/3rdparty/syntax-highlighting/src/lib/syntaxhighlighter.h
index a57455d9baa..c19cb798dd1 100644
--- a/src/libs/3rdparty/syntax-highlighting/src/lib/syntaxhighlighter.h
+++ b/src/libs/3rdparty/syntax-highlighting/src/lib/syntaxhighlighter.h
@@ -32,6 +32,7 @@ public:
     ~SyntaxHighlighter() override;
 
     void setDefinition(const Definition &def) override;
+    void setTheme(const Theme &theme) override;
 
     /** Returns whether there is a folding region beginning at @p startBlock.
      *  This only considers syntax-based folding regions,
diff --git a/src/libs/3rdparty/syntax-highlighting/src/lib/theme.cpp b/src/libs/3rdparty/syntax-highlighting/src/lib/theme.cpp
index b23852f337a..c54bb38b180 100644
--- a/src/libs/3rdparty/syntax-highlighting/src/lib/theme.cpp
+++ b/src/libs/3rdparty/syntax-highlighting/src/lib/theme.cpp
@@ -103,3 +103,5 @@ QRgb Theme::editorColor(EditorColorRole role) const
 {
     return m_data->editorColor(role);
 }
+
+#include "moc_theme.cpp"
diff --git a/src/libs/3rdparty/syntax-highlighting/src/lib/theme.h b/src/libs/3rdparty/syntax-highlighting/src/lib/theme.h
index 37f9de1694b..c3fb0e6b6e6 100644
--- a/src/libs/3rdparty/syntax-highlighting/src/lib/theme.h
+++ b/src/libs/3rdparty/syntax-highlighting/src/lib/theme.h
@@ -67,11 +67,6 @@ class KSYNTAXHIGHLIGHTING_EXPORT Theme
     Q_PROPERTY(QString name READ name)
     Q_PROPERTY(QString translatedName READ translatedName)
 public:
-    // TODO KF6:
-    // - make TextStyle an enum class
-    // - move out of Theme into KSyntaxHighlighting
-    // - do the same for EditorColorRole
-
     /**
      * Default styles that can be referenced from syntax definition XML files.
      * Make sure to choose readable colors with good contrast especially in
@@ -342,7 +337,7 @@ private:
     /**
      * Constructor taking a shared ThemeData instance.
      */
-    explicit Theme(ThemeData *data);
+    KSYNTAXHIGHLIGHTING_NO_EXPORT explicit Theme(ThemeData *data);
     friend class RepositoryPrivate;
     friend class ThemeData;
 
@@ -356,7 +351,7 @@ private:
 }
 
 QT_BEGIN_NAMESPACE
-Q_DECLARE_TYPEINFO(KSyntaxHighlighting::Theme, Q_MOVABLE_TYPE);
+Q_DECLARE_TYPEINFO(KSyntaxHighlighting::Theme, Q_RELOCATABLE_TYPE);
 QT_END_NAMESPACE
 
 #endif // KSYNTAXHIGHLIGHTING_THEME_H
diff --git a/src/libs/3rdparty/syntax-highlighting/src/lib/themedata.cpp b/src/libs/3rdparty/syntax-highlighting/src/lib/themedata.cpp
index 4f77dcc494f..9d42d03db03 100644
--- a/src/libs/3rdparty/syntax-highlighting/src/lib/themedata.cpp
+++ b/src/libs/3rdparty/syntax-highlighting/src/lib/themedata.cpp
@@ -18,11 +18,6 @@
 
 using namespace KSyntaxHighlighting;
 
-ThemeData *ThemeData::get(const Theme &theme)
-{
-    return theme.m_data.data();
-}
-
 ThemeData::ThemeData()
 {
     memset(m_editorColors, 0, sizeof(m_editorColors));
@@ -87,9 +82,18 @@ bool ThemeData::load(const QString &filePath)
         return false;
     }
     const QByteArray jsonData = loadFile.readAll();
+    // look for metadata object
+    int metaDataStart = jsonData.indexOf("\"metadata\"");
+    int start = jsonData.indexOf('{', metaDataStart);
+    int end = jsonData.indexOf("}", metaDataStart);
+    if (start < 0 || end < 0) {
+        qCWarning(Log) << "Failed to parse theme file" << filePath << ":"
+                       << "no metadata object found";
+        return false;
+    }
 
     QJsonParseError parseError;
-    QJsonDocument jsonDoc = QJsonDocument::fromJson(jsonData, &parseError);
+    QJsonDocument jsonDoc = QJsonDocument::fromJson(jsonData.mid(start, (end + 1) - start), &parseError);
     if (parseError.error != QJsonParseError::NoError) {
         qCWarning(Log) << "Failed to parse theme file" << filePath << ":" << parseError.errorString();
         return false;
@@ -97,13 +101,34 @@ bool ThemeData::load(const QString &filePath)
 
     m_filePath = filePath;
 
-    QJsonObject obj = jsonDoc.object();
-
     // read metadata
-    const QJsonObject metadata = obj.value(QLatin1String("metadata")).toObject();
+    QJsonObject metadata = jsonDoc.object();
     m_name = metadata.value(QLatin1String("name")).toString();
     m_revision = metadata.value(QLatin1String("revision")).toInt();
+    return true;
+}
 
+void ThemeData::loadComplete()
+{
+    if (m_completelyLoaded) {
+        return;
+    }
+    m_completelyLoaded = true;
+
+    QFile loadFile(m_filePath);
+    if (!loadFile.open(QIODevice::ReadOnly)) {
+        return;
+    }
+    const QByteArray jsonData = loadFile.readAll();
+
+    QJsonParseError parseError;
+    QJsonDocument jsonDoc = QJsonDocument::fromJson(jsonData, &parseError);
+    if (parseError.error != QJsonParseError::NoError) {
+        qCWarning(Log) << "Failed to parse theme file" << m_filePath << ":" << parseError.errorString();
+        return;
+    }
+
+    QJsonObject obj = jsonDoc.object();
     // read text styles
     const auto metaEnumStyle = QMetaEnum::fromType();
     const QJsonObject textStyles = obj.value(QLatin1String("text-styles")).toObject();
@@ -162,7 +187,7 @@ bool ThemeData::load(const QString &filePath)
         }
     }
 
-    return true;
+    return;
 }
 
 QString ThemeData::name() const
@@ -187,6 +212,9 @@ QString ThemeData::filePath() const
 
 TextStyleData ThemeData::textStyle(Theme::TextStyle style) const
 {
+    if (!m_completelyLoaded) {
+        const_cast(this)->loadComplete();
+    }
     return m_textStyles[style];
 }
 
@@ -232,12 +260,18 @@ bool ThemeData::isStrikeThrough(Theme::TextStyle style) const
 
 QRgb ThemeData::editorColor(Theme::EditorColorRole role) const
 {
+    if (!m_completelyLoaded) {
+        const_cast(this)->loadComplete();
+    }
     Q_ASSERT(static_cast(role) >= 0 && static_cast(role) <= static_cast(Theme::TemplateReadOnlyPlaceholder));
     return m_editorColors[role];
 }
 
 TextStyleData ThemeData::textStyleOverride(const QString &definitionName, const QString &attributeName) const
 {
+    if (!m_completelyLoaded) {
+        const_cast(this)->loadComplete();
+    }
     auto it = m_textStyleOverrides.find(definitionName);
     if (it != m_textStyleOverrides.end()) {
         return it->value(attributeName);
diff --git a/src/libs/3rdparty/syntax-highlighting/src/lib/themedata_p.h b/src/libs/3rdparty/syntax-highlighting/src/lib/themedata_p.h
index 4ce87f0aaf9..6ee772f172c 100644
--- a/src/libs/3rdparty/syntax-highlighting/src/lib/themedata_p.h
+++ b/src/libs/3rdparty/syntax-highlighting/src/lib/themedata_p.h
@@ -24,7 +24,10 @@ namespace KSyntaxHighlighting
 class ThemeData : public QSharedData
 {
 public:
-    static ThemeData *get(const Theme &theme);
+    static ThemeData *get(const Theme &theme)
+    {
+        return theme.m_data.data();
+    }
 
     /**
      * Default constructor, creating an uninitialized ThemeData instance.
@@ -37,6 +40,8 @@ public:
      */
     bool load(const QString &filePath);
 
+    void loadComplete();
+
     /**
      * Returns the unique name of this Theme.
      */
@@ -140,6 +145,8 @@ private:
     //! on disk (in a read-only or a writeable location).
     QString m_filePath;
 
+    bool m_completelyLoaded = false;
+
     //! TextStyles
     std::vector m_textStyles;
 
@@ -154,7 +161,7 @@ private:
 }
 
 QT_BEGIN_NAMESPACE
-Q_DECLARE_TYPEINFO(KSyntaxHighlighting::TextStyleData, Q_MOVABLE_TYPE);
+Q_DECLARE_TYPEINFO(KSyntaxHighlighting::TextStyleData, Q_RELOCATABLE_TYPE);
 QT_END_NAMESPACE
 
 #endif // KSYNTAXHIGHLIGHTING_THEMEDATA_P_H
diff --git a/src/libs/3rdparty/syntax-highlighting/src/lib/worddelimiters.cpp b/src/libs/3rdparty/syntax-highlighting/src/lib/worddelimiters.cpp
index c5401a57cc9..ce55cd4b293 100644
--- a/src/libs/3rdparty/syntax-highlighting/src/lib/worddelimiters.cpp
+++ b/src/libs/3rdparty/syntax-highlighting/src/lib/worddelimiters.cpp
@@ -16,6 +16,12 @@ WordDelimiters::WordDelimiters()
     }
 }
 
+WordDelimiters::WordDelimiters(QStringView str)
+    : asciiDelimiters{}
+{
+    append(str);
+}
+
 bool WordDelimiters::contains(QChar c) const
 {
     if (c.unicode() < 128) {
diff --git a/src/libs/3rdparty/syntax-highlighting/src/lib/worddelimiters_p.h b/src/libs/3rdparty/syntax-highlighting/src/lib/worddelimiters_p.h
index ccad679a4ef..c23670d6344 100644
--- a/src/libs/3rdparty/syntax-highlighting/src/lib/worddelimiters_p.h
+++ b/src/libs/3rdparty/syntax-highlighting/src/lib/worddelimiters_p.h
@@ -26,6 +26,11 @@ class WordDelimiters
 public:
     WordDelimiters();
 
+    /**
+     * Initialize with a default delimiters.
+     */
+    explicit WordDelimiters(QStringView str);
+
     /**
      * Returns @c true if @p c is a word delimiter; otherwise returns @c false.
      */
diff --git a/src/libs/3rdparty/syntax-highlighting/src/quick/CMakeLists.txt b/src/libs/3rdparty/syntax-highlighting/src/quick/CMakeLists.txt
index 9277c2aee7d..1fb92ad2201 100644
--- a/src/libs/3rdparty/syntax-highlighting/src/quick/CMakeLists.txt
+++ b/src/libs/3rdparty/syntax-highlighting/src/quick/CMakeLists.txt
@@ -7,11 +7,10 @@ ecm_add_qml_module(kquicksyntaxhighlightingplugin URI "org.kde.syntaxhighlightin
 target_sources(kquicksyntaxhighlightingplugin PRIVATE
     kquicksyntaxhighlightingplugin.cpp
     kquicksyntaxhighlighter.cpp
-    repositorywrapper.cpp
 )
 target_link_libraries(kquicksyntaxhighlightingplugin PRIVATE
-    KF5SyntaxHighlighting
-    Qt${QT_MAJOR_VERSION}::Quick
+    KF6SyntaxHighlighting
+    Qt6::Quick
 )
 
 ecm_finalize_qml_module(kquicksyntaxhighlightingplugin DESTINATION ${KDE_INSTALL_QMLDIR})
diff --git a/src/libs/3rdparty/syntax-highlighting/src/quick/kquicksyntaxhighlighter.cpp b/src/libs/3rdparty/syntax-highlighting/src/quick/kquicksyntaxhighlighter.cpp
index eb795b1468e..19cfbacf58c 100644
--- a/src/libs/3rdparty/syntax-highlighting/src/quick/kquicksyntaxhighlighter.cpp
+++ b/src/libs/3rdparty/syntax-highlighting/src/quick/kquicksyntaxhighlighter.cpp
@@ -49,7 +49,7 @@ QVariant KQuickSyntaxHighlighter::definition() const
 void KQuickSyntaxHighlighter::setDefinition(const QVariant &definition)
 {
     Definition def;
-    if (definition.type() == QVariant::String) {
+    if (definition.userType() == QMetaType::QString) {
         def = unwrappedRepository()->definitionForName(definition.toString());
     } else {
         def = definition.value();
@@ -73,9 +73,9 @@ QVariant KQuickSyntaxHighlighter::theme() const
 void KQuickSyntaxHighlighter::setTheme(const QVariant &theme)
 {
     Theme t;
-    if (theme.type() == QVariant::String) {
+    if (theme.userType() == QMetaType::QString) {
         t = unwrappedRepository()->theme(theme.toString());
-    } else if (theme.type() == QVariant::Int) {
+    } else if (theme.userType() == QMetaType::Int) {
         t = unwrappedRepository()->defaultTheme(static_cast(theme.toInt()));
     } else {
         t = theme.value();
@@ -89,12 +89,12 @@ void KQuickSyntaxHighlighter::setTheme(const QVariant &theme)
     }
 }
 
-RepositoryWrapper *KQuickSyntaxHighlighter::repository() const
+Repository *KQuickSyntaxHighlighter::repository() const
 {
     return m_repository;
 }
 
-void KQuickSyntaxHighlighter::setRepository(RepositoryWrapper *repository)
+void KQuickSyntaxHighlighter::setRepository(Repository *repository)
 {
     if (m_repository == repository) {
         return;
@@ -106,7 +106,9 @@ void KQuickSyntaxHighlighter::setRepository(RepositoryWrapper *repository)
 Repository *KQuickSyntaxHighlighter::unwrappedRepository() const
 {
     if (m_repository) {
-        return m_repository->m_repository;
+        return m_repository;
     }
     return defaultRepository();
 }
+
+#include "moc_kquicksyntaxhighlighter.cpp"
diff --git a/src/libs/3rdparty/syntax-highlighting/src/quick/kquicksyntaxhighlighter.h b/src/libs/3rdparty/syntax-highlighting/src/quick/kquicksyntaxhighlighter.h
index 211f80d37f5..b45c26339f2 100644
--- a/src/libs/3rdparty/syntax-highlighting/src/quick/kquicksyntaxhighlighter.h
+++ b/src/libs/3rdparty/syntax-highlighting/src/quick/kquicksyntaxhighlighter.h
@@ -8,8 +8,6 @@
 #ifndef KQUICKSYNTAXHIGHLIGHTER_H
 #define KQUICKSYNTAXHIGHLIGHTER_H
 
-#include "repositorywrapper.h"
-
 #include 
 #include 
 
@@ -29,7 +27,7 @@ class KQuickSyntaxHighlighter : public QObject
     Q_PROPERTY(QObject *textEdit READ textEdit WRITE setTextEdit NOTIFY textEditChanged)
     Q_PROPERTY(QVariant definition READ definition WRITE setDefinition NOTIFY definitionChanged)
     Q_PROPERTY(QVariant theme READ theme WRITE setTheme NOTIFY themeChanged)
-    Q_PROPERTY(RepositoryWrapper *repository READ repository WRITE setRepository NOTIFY repositoryChanged)
+    Q_PROPERTY(KSyntaxHighlighting::Repository *repository READ repository WRITE setRepository NOTIFY repositoryChanged)
 
 public:
     explicit KQuickSyntaxHighlighter(QObject *parent = nullptr);
@@ -44,8 +42,8 @@ public:
     QVariant theme() const;
     void setTheme(const QVariant &theme);
 
-    RepositoryWrapper *repository() const;
-    void setRepository(RepositoryWrapper *repository);
+    KSyntaxHighlighting::Repository *repository() const;
+    void setRepository(KSyntaxHighlighting::Repository *repository);
 
 Q_SIGNALS:
     void textEditChanged() const;
@@ -59,7 +57,7 @@ private:
     QObject *m_textEdit;
     KSyntaxHighlighting::Definition m_definition;
     KSyntaxHighlighting::Theme m_theme;
-    RepositoryWrapper *m_repository = nullptr;
+    KSyntaxHighlighting::Repository *m_repository = nullptr;
     KSyntaxHighlighting::SyntaxHighlighter *m_highlighter = nullptr;
 };
 
diff --git a/src/libs/3rdparty/syntax-highlighting/src/quick/kquicksyntaxhighlightingplugin.cpp b/src/libs/3rdparty/syntax-highlighting/src/quick/kquicksyntaxhighlightingplugin.cpp
index 9aeb503ec5d..5eb06862df8 100644
--- a/src/libs/3rdparty/syntax-highlighting/src/quick/kquicksyntaxhighlightingplugin.cpp
+++ b/src/libs/3rdparty/syntax-highlighting/src/quick/kquicksyntaxhighlightingplugin.cpp
@@ -7,7 +7,6 @@
 
 #include "kquicksyntaxhighlightingplugin.h"
 #include "kquicksyntaxhighlighter.h"
-#include "repositorywrapper.h"
 
 #include 
 #include 
@@ -30,17 +29,18 @@ void KQuickSyntaxHighlightingPlugin::registerTypes(const char *uri)
 {
     Q_ASSERT(QLatin1String(uri) == QLatin1String("org.kde.syntaxhighlighting"));
     qRegisterMetaType();
-    qRegisterMetaType>();
+    qRegisterMetaType>();
     qRegisterMetaType();
-    qRegisterMetaType>();
+    qRegisterMetaType>();
     qmlRegisterType(uri, 1, 0, "SyntaxHighlighter");
-    qmlRegisterUncreatableType(uri, 1, 0, "Definition", {});
-    qmlRegisterUncreatableType(uri, 1, 0, "Theme", {});
-    qmlRegisterSingletonType(uri, 1, 0, "Repository", [](auto engine, auto scriptEngine) {
+    qmlRegisterUncreatableMetaObject(Definition::staticMetaObject, uri, 1, 0, "Definition", {});
+    qmlRegisterUncreatableMetaObject(Theme::staticMetaObject, uri, 1, 0, "Theme", {});
+    qmlRegisterSingletonType(uri, 1, 0, "Repository", [](auto engine, auto scriptEngine) {
         (void)engine;
-        (void)scriptEngine;
-        auto repo = new RepositoryWrapper;
-        repo->m_repository = defaultRepository();
-        return repo;
+        auto repo = defaultRepository();
+        scriptEngine->setObjectOwnership(repo, QJSEngine::CppOwnership);
+        return defaultRepository();
     });
 }
+
+#include "moc_kquicksyntaxhighlightingplugin.cpp"
diff --git a/src/libs/3rdparty/syntax-highlighting/src/quick/repositorywrapper.cpp b/src/libs/3rdparty/syntax-highlighting/src/quick/repositorywrapper.cpp
deleted file mode 100644
index 733c799ed13..00000000000
--- a/src/libs/3rdparty/syntax-highlighting/src/quick/repositorywrapper.cpp
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
-    SPDX-FileCopyrightText: 2021 Volker Krause 
-
-    SPDX-License-Identifier: MIT
-*/
-
-#include "repositorywrapper.h"
-
-#include 
-#include 
-#include 
-
-using namespace KSyntaxHighlighting;
-
-RepositoryWrapper::RepositoryWrapper(QObject *parent)
-    : QObject(parent)
-{
-}
-
-Definition RepositoryWrapper::definitionForName(const QString &defName) const
-{
-    return m_repository->definitionForName(defName);
-}
-
-Definition RepositoryWrapper::definitionForFileName(const QString &fileName) const
-{
-    return m_repository->definitionForFileName(fileName);
-}
-
-QVector RepositoryWrapper::definitionsForFileName(const QString &fileName) const
-{
-    return m_repository->definitionsForFileName(fileName);
-}
-
-Definition RepositoryWrapper::definitionForMimeType(const QString &mimeType) const
-{
-    return m_repository->definitionForMimeType(mimeType);
-}
-
-QVector RepositoryWrapper::definitionsForMimeType(const QString &mimeType) const
-{
-    return m_repository->definitionsForMimeType(mimeType);
-}
-
-QVector RepositoryWrapper::definitions() const
-{
-    return m_repository->definitions();
-}
-
-QVector RepositoryWrapper::themes() const
-{
-    return m_repository->themes();
-}
-
-Theme RepositoryWrapper::theme(const QString &themeName) const
-{
-    return m_repository->theme(themeName);
-}
-
-Theme RepositoryWrapper::defaultTheme(DefaultTheme t) const
-{
-    return m_repository->defaultTheme(static_cast(t));
-}
-
-#include "moc_repositorywrapper.cpp"
diff --git a/src/libs/3rdparty/syntax-highlighting/src/quick/repositorywrapper.h b/src/libs/3rdparty/syntax-highlighting/src/quick/repositorywrapper.h
deleted file mode 100644
index d4fb8d251cc..00000000000
--- a/src/libs/3rdparty/syntax-highlighting/src/quick/repositorywrapper.h
+++ /dev/null
@@ -1,45 +0,0 @@
-/*
-    SPDX-FileCopyrightText: 2021 Volker Krause 
-
-    SPDX-License-Identifier: MIT
-*/
-
-#ifndef REPOSITORYWRAPPER_H
-#define REPOSITORYWRAPPER_H
-
-#include 
-
-namespace KSyntaxHighlighting
-{
-class Definition;
-class Repository;
-class Theme;
-}
-
-// TODO KF6: merge this into KSyntaxHighlighting::Repository
-class RepositoryWrapper : public QObject
-{
-    Q_OBJECT
-    // TODO KF6: NOTIFY on reload
-    Q_PROPERTY(QVector definitions READ definitions CONSTANT)
-    Q_PROPERTY(QVector themes READ themes CONSTANT)
-public:
-    explicit RepositoryWrapper(QObject *parent = nullptr);
-
-    Q_INVOKABLE KSyntaxHighlighting::Definition definitionForName(const QString &defName) const;
-    Q_INVOKABLE KSyntaxHighlighting::Definition definitionForFileName(const QString &fileName) const;
-    Q_INVOKABLE QVector definitionsForFileName(const QString &fileName) const;
-    Q_INVOKABLE KSyntaxHighlighting::Definition definitionForMimeType(const QString &mimeType) const;
-    Q_INVOKABLE QVector definitionsForMimeType(const QString &mimeType) const;
-    QVector definitions() const;
-
-    QVector themes() const;
-    Q_INVOKABLE KSyntaxHighlighting::Theme theme(const QString &themeName) const;
-    enum DefaultTheme { LightTheme, DarkTheme };
-    Q_ENUM(DefaultTheme)
-    Q_INVOKABLE KSyntaxHighlighting::Theme defaultTheme(DefaultTheme t = LightTheme) const;
-
-    KSyntaxHighlighting::Repository *m_repository = nullptr;
-};
-
-#endif // REPOSITORYWRAPPER_H
-- 
cgit v1.2.3