aboutsummaryrefslogtreecommitdiffstats
path: root/src/libs/3rdparty/syntax-highlighting/src/lib
diff options
context:
space:
mode:
authorDavid Schulz <david.schulz@qt.io>2018-11-08 11:39:48 +0100
committerDavid Schulz <david.schulz@qt.io>2019-01-28 11:37:08 +0000
commit14834e6b0a4e7c1272ec3a1838b0634dd66e72ea (patch)
tree23caed8a748c0d38c59e1f92b448551122d11df2 /src/libs/3rdparty/syntax-highlighting/src/lib
parent1c77d7e1a79f59485eb90c066d17ec7436f46a93 (diff)
TextEditor: replace generic highlighter with ksyntaxhighlighting
Fixes: QTCREATORBUG-21029 Change-Id: I9894c4384e0e47da6bf030b7b8e07c3ad4737ff3 Reviewed-by: Orgad Shaneh <orgads@gmail.com>
Diffstat (limited to 'src/libs/3rdparty/syntax-highlighting/src/lib')
-rw-r--r--src/libs/3rdparty/syntax-highlighting/src/lib/CMakeLists.txt86
-rw-r--r--src/libs/3rdparty/syntax-highlighting/src/lib/abstracthighlighter.cpp328
-rw-r--r--src/libs/3rdparty/syntax-highlighting/src/lib/abstracthighlighter.h195
-rw-r--r--src/libs/3rdparty/syntax-highlighting/src/lib/abstracthighlighter_p.h54
-rw-r--r--src/libs/3rdparty/syntax-highlighting/src/lib/context.cpp206
-rw-r--r--src/libs/3rdparty/syntax-highlighting/src/lib/context_p.h139
-rw-r--r--src/libs/3rdparty/syntax-highlighting/src/lib/contextswitch.cpp90
-rw-r--r--src/libs/3rdparty/syntax-highlighting/src/lib/contextswitch_p.h56
-rw-r--r--src/libs/3rdparty/syntax-highlighting/src/lib/definition.cpp798
-rw-r--r--src/libs/3rdparty/syntax-highlighting/src/lib/definition.h400
-rw-r--r--src/libs/3rdparty/syntax-highlighting/src/lib/definition_p.h111
-rw-r--r--src/libs/3rdparty/syntax-highlighting/src/lib/definitiondownloader.cpp193
-rw-r--r--src/libs/3rdparty/syntax-highlighting/src/lib/definitiondownloader.h113
-rw-r--r--src/libs/3rdparty/syntax-highlighting/src/lib/definitionref_p.h74
-rw-r--r--src/libs/3rdparty/syntax-highlighting/src/lib/foldingregion.cpp60
-rw-r--r--src/libs/3rdparty/syntax-highlighting/src/lib/foldingregion.h108
-rw-r--r--src/libs/3rdparty/syntax-highlighting/src/lib/format.cpp264
-rw-r--r--src/libs/3rdparty/syntax-highlighting/src/lib/format.h152
-rw-r--r--src/libs/3rdparty/syntax-highlighting/src/lib/format_p.h55
-rw-r--r--src/libs/3rdparty/syntax-highlighting/src/lib/htmlhighlighter.cpp161
-rw-r--r--src/libs/3rdparty/syntax-highlighting/src/lib/htmlhighlighter.h64
-rw-r--r--src/libs/3rdparty/syntax-highlighting/src/lib/keywordlist.cpp104
-rw-r--r--src/libs/3rdparty/syntax-highlighting/src/lib/keywordlist_p.h101
-rw-r--r--src/libs/3rdparty/syntax-highlighting/src/lib/ksyntaxhighlighting_export.h34
-rw-r--r--src/libs/3rdparty/syntax-highlighting/src/lib/matchresult_p.h113
-rw-r--r--src/libs/3rdparty/syntax-highlighting/src/lib/repository.cpp325
-rw-r--r--src/libs/3rdparty/syntax-highlighting/src/lib/repository.h257
-rw-r--r--src/libs/3rdparty/syntax-highlighting/src/lib/repository_p.h72
-rw-r--r--src/libs/3rdparty/syntax-highlighting/src/lib/rule.cpp663
-rw-r--r--src/libs/3rdparty/syntax-highlighting/src/lib/rule_p.h291
-rw-r--r--src/libs/3rdparty/syntax-highlighting/src/lib/state.cpp123
-rw-r--r--src/libs/3rdparty/syntax-highlighting/src/lib/state.h86
-rw-r--r--src/libs/3rdparty/syntax-highlighting/src/lib/state_p.h81
-rw-r--r--src/libs/3rdparty/syntax-highlighting/src/lib/syntaxhighlighter.cpp198
-rw-r--r--src/libs/3rdparty/syntax-highlighting/src/lib/syntaxhighlighter.h85
-rw-r--r--src/libs/3rdparty/syntax-highlighting/src/lib/textstyledata_p.h63
-rw-r--r--src/libs/3rdparty/syntax-highlighting/src/lib/theme.cpp124
-rw-r--r--src/libs/3rdparty/syntax-highlighting/src/lib/theme.h378
-rw-r--r--src/libs/3rdparty/syntax-highlighting/src/lib/themedata.cpp255
-rw-r--r--src/libs/3rdparty/syntax-highlighting/src/lib/themedata_p.h170
-rw-r--r--src/libs/3rdparty/syntax-highlighting/src/lib/wildcardmatcher.cpp83
-rw-r--r--src/libs/3rdparty/syntax-highlighting/src/lib/wildcardmatcher_p.h51
-rw-r--r--src/libs/3rdparty/syntax-highlighting/src/lib/xml_p.h42
43 files changed, 7406 insertions, 0 deletions
diff --git a/src/libs/3rdparty/syntax-highlighting/src/lib/CMakeLists.txt b/src/libs/3rdparty/syntax-highlighting/src/lib/CMakeLists.txt
new file mode 100644
index 0000000000..bf729fca71
--- /dev/null
+++ b/src/libs/3rdparty/syntax-highlighting/src/lib/CMakeLists.txt
@@ -0,0 +1,86 @@
+ecm_create_qm_loader(syntax_highlighting_QM_LOADER syntaxhighlighting5_qt)
+
+set(syntax_highlighting_srcs
+ abstracthighlighter.cpp
+ context.cpp
+ contextswitch.cpp
+ definitiondownloader.cpp
+ foldingregion.cpp
+ format.cpp
+ htmlhighlighter.cpp
+ keywordlist.cpp
+ rule.cpp
+ definition.cpp
+ repository.cpp
+ state.cpp
+ syntaxhighlighter.cpp
+ theme.cpp
+ wildcardmatcher.cpp
+ themedata.cpp
+ ${syntax_highlighting_QM_LOADER}
+)
+ecm_qt_declare_logging_category(syntax_highlighting_srcs
+ HEADER ksyntaxhighlighting_logging.h
+ IDENTIFIER KSyntaxHighlighting::Log
+ CATEGORY_NAME org.kde.ksyntaxhighlighting
+)
+
+add_library(KF5SyntaxHighlighting ${syntax_highlighting_srcs} $<TARGET_OBJECTS:SyntaxHighlightingData>)
+generate_export_header(KF5SyntaxHighlighting BASE_NAME KSyntaxHighlighting)
+set_target_properties(KF5SyntaxHighlighting PROPERTIES
+ VERSION ${SyntaxHighlighting_VERSION_STRING}
+ SOVERSION ${SyntaxHighlighting_SOVERSION}
+ EXPORT_NAME SyntaxHighlighting
+)
+target_include_directories(KF5SyntaxHighlighting INTERFACE "$<INSTALL_INTERFACE:${KDE_INSTALL_INCLUDEDIR_KF5}/KSyntaxHighlighting;${KDE_INSTALL_INCLUDEDIR_KF5}>")
+target_include_directories(KF5SyntaxHighlighting PUBLIC "$<BUILD_INTERFACE:${CMAKE_CURRENT_SOURCE_DIR};${CMAKE_CURRENT_BINARY_DIR};>")
+target_link_libraries(KF5SyntaxHighlighting LINK_PUBLIC Qt5::Gui LINK_PRIVATE Qt5::Network)
+
+ecm_generate_headers(SyntaxHighlighting_HEADERS
+ HEADER_NAMES
+ AbstractHighlighter
+ Definition
+ FoldingRegion
+ Format
+ Repository
+ State
+ SyntaxHighlighter
+ Theme
+ REQUIRED_HEADERS SyntaxHighlighting_HEADERS
+)
+
+install(TARGETS KF5SyntaxHighlighting EXPORT KF5SyntaxHighlightingTargets ${INSTALL_TARGETS_DEFAULT_ARGS})
+install(FILES
+ ${SyntaxHighlighting_HEADERS}
+ ${CMAKE_CURRENT_BINARY_DIR}/ksyntaxhighlighting_export.h
+ DESTINATION ${KDE_INSTALL_INCLUDEDIR_KF5}/KSyntaxHighlighting)
+
+if(BUILD_QCH)
+ ecm_add_qch(
+ KF5SyntaxHighlighting_QCH
+ NAME KSyntaxHighlighting
+ BASE_NAME KF5SyntaxHighlighting
+ VERSION ${KF5_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
+ BLANK_MACROS
+ KSYNTAXHIGHLIGHTING_EXPORT
+ KSYNTAXHIGHLIGHTING_DEPRECATED
+ TAGFILE_INSTALL_DESTINATION ${KDE_INSTALL_QTQCHDIR}
+ QCH_INSTALL_DESTINATION ${KDE_INSTALL_QTQCHDIR}
+ 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_KF5}/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
new file mode 100644
index 0000000000..f69944debd
--- /dev/null
+++ b/src/libs/3rdparty/syntax-highlighting/src/lib/abstracthighlighter.cpp
@@ -0,0 +1,328 @@
+/*
+ Copyright (C) 2016 Volker Krause <vkrause@kde.org>
+
+ Permission is hereby granted, free of charge, to any person obtaining
+ a copy of this software and associated documentation files (the
+ "Software"), to deal in the Software without restriction, including
+ without limitation the rights to use, copy, modify, merge, publish,
+ distribute, sublicense, and/or sell copies of the Software, and to
+ permit persons to whom the Software is furnished to do so, subject to
+ the following conditions:
+
+ The above copyright notice and this permission notice shall be included
+ in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+#include "abstracthighlighter.h"
+#include "abstracthighlighter_p.h"
+#include "context_p.h"
+#include "definition_p.h"
+#include "foldingregion.h"
+#include "format.h"
+#include "repository.h"
+#include "rule_p.h"
+#include "state.h"
+#include "state_p.h"
+#include "ksyntaxhighlighting_logging.h"
+#include "theme.h"
+
+using namespace KSyntaxHighlighting;
+
+AbstractHighlighterPrivate::AbstractHighlighterPrivate()
+{
+}
+
+AbstractHighlighterPrivate::~AbstractHighlighterPrivate()
+{
+}
+
+void AbstractHighlighterPrivate::ensureDefinitionLoaded()
+{
+ auto defData = DefinitionData::get(m_definition);
+ if (Q_UNLIKELY(!m_definition.isValid() && defData->repo && !m_definition.name().isEmpty())) {
+ qCDebug(Log) << "Definition became invalid, trying re-lookup.";
+ m_definition = defData->repo->definitionForName(m_definition.name());
+ defData = DefinitionData::get(m_definition);
+ }
+
+ if (Q_UNLIKELY(!defData->repo && !defData->name.isEmpty()))
+ qCCritical(Log) << "Repository got deleted while a highlighter is still active!";
+
+ if (m_definition.isValid())
+ defData->load();
+}
+
+AbstractHighlighter::AbstractHighlighter() :
+ d_ptr(new AbstractHighlighterPrivate)
+{
+}
+
+AbstractHighlighter::AbstractHighlighter(AbstractHighlighterPrivate *dd) :
+ d_ptr(dd)
+{
+}
+
+AbstractHighlighter::~AbstractHighlighter()
+{
+ delete d_ptr;
+}
+
+Definition AbstractHighlighter::definition() const
+{
+ return d_ptr->m_definition;
+}
+
+void AbstractHighlighter::setDefinition(const Definition &def)
+{
+ Q_D(AbstractHighlighter);
+ d->m_definition = def;
+}
+
+Theme AbstractHighlighter::theme() const
+{
+ Q_D(const AbstractHighlighter);
+ return d->m_theme;
+}
+
+void AbstractHighlighter::setTheme(const Theme &theme)
+{
+ Q_D(AbstractHighlighter);
+ d->m_theme = theme;
+}
+
+/**
+ * Returns the index of the first non-space character. If the line is empty,
+ * or only contains white spaces, text.size() is returned.
+ */
+static inline int firstNonSpaceChar(const QString & text)
+{
+ for (int i = 0; i < text.length(); ++i) {
+ if (!text[i].isSpace()) {
+ return i;
+ }
+ }
+ return text.size();
+}
+
+State AbstractHighlighter::highlightLine(const QString& text, const State &state)
+{
+ Q_D(AbstractHighlighter);
+
+ // verify definition, deal with no highlighting being enabled
+ d->ensureDefinitionLoaded();
+ if (!d->m_definition.isValid()) {
+ applyFormat(0, text.size(), Format());
+ return State();
+ }
+
+ // verify/initialize state
+ auto defData = DefinitionData::get(d->m_definition);
+ auto newState = state;
+ auto stateData = StateData::get(newState);
+ const DefinitionRef currentDefRef(d->m_definition);
+ if (!stateData->isEmpty() && (stateData->m_defRef != currentDefRef)) {
+ qCDebug(Log) << "Got invalid state, resetting.";
+ stateData->clear();
+ }
+ if (stateData->isEmpty()) {
+ stateData->push(defData->initialContext(), QStringList());
+ stateData->m_defRef = currentDefRef;
+ }
+
+ // process empty lines
+ if (text.isEmpty()) {
+ while (!stateData->topContext()->lineEmptyContext().isStay()) {
+ if (!d->switchContext(stateData, stateData->topContext()->lineEmptyContext(), QStringList()))
+ break;
+ }
+ auto context = stateData->topContext();
+ applyFormat(0, 0, context->attributeFormat());
+ return newState;
+ }
+
+ int offset = 0, beginOffset = 0;
+ bool lineContinuation = false;
+ QHash<Rule*, int> skipOffsets;
+
+ /**
+ * current active format
+ * stored as pointer to avoid deconstruction/constructions inside the internal loop
+ * the pointers are stable, the formats are either in the contexts or rules
+ */
+ auto currentFormat = &stateData->topContext()->attributeFormat();
+
+ /**
+ * cached first non-space character, needs to be computed if < 0
+ */
+ int firstNonSpace = -1;
+ int lastOffset = offset;
+ int endlessLoopingCounter = 0;
+ do {
+ /**
+ * avoid that we loop endless for some broken hl definitions
+ */
+ if (lastOffset == offset) {
+ ++endlessLoopingCounter;
+ if (endlessLoopingCounter > 1024) {
+ qCDebug(Log) << "Endless state transitions, aborting highlighting of line.";
+ break;
+ }
+ } else {
+ // ensure we made progress, clear the endlessLoopingCounter
+ Q_ASSERT(offset > lastOffset);
+ lastOffset = offset;
+ endlessLoopingCounter = 0;
+ }
+
+ /**
+ * try to match all rules in the context in order of declaration in XML
+ */
+ bool isLookAhead = false;
+ int newOffset = 0;
+ const Format *newFormat = nullptr;
+ for (const auto &rule : stateData->topContext()->rules()) {
+ /**
+ * filter out rules that require a specific column
+ */
+ if ((rule->requiredColumn() >= 0) && (rule->requiredColumn() != offset)) {
+ continue;
+ }
+
+ /**
+ * filter out rules that only match for leading whitespace
+ */
+ if (rule->firstNonSpace()) {
+ /**
+ * compute the first non-space lazy
+ * avoids computing it for contexts without any such rules
+ */
+ if (firstNonSpace < 0) {
+ firstNonSpace = firstNonSpaceChar(text);
+ }
+
+ /**
+ * can we skip?
+ */
+ if (offset > firstNonSpace) {
+ continue;
+ }
+ }
+
+ /**
+ * 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
+ */
+ const auto currentSkipOffset = skipOffsets.value(rule.get());
+ if (currentSkipOffset < 0 || currentSkipOffset > offset)
+ continue;
+
+
+ const auto newResult = rule->doMatch(text, offset, stateData->topCaptures());
+ 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)
+ skipOffsets.insert(rule.get(), newResult.skipOffset());
+
+ if (newOffset <= offset)
+ continue;
+
+ // apply folding
+ if (rule->endRegion().isValid())
+ applyFolding(offset, newOffset - offset, rule->endRegion());
+ if (rule->beginRegion().isValid())
+ applyFolding(offset, newOffset - offset, rule->beginRegion());
+
+ if (rule->isLookAhead()) {
+ Q_ASSERT(!rule->context().isStay());
+ d->switchContext(stateData, rule->context(), newResult.captures());
+ isLookAhead = true;
+ break;
+ }
+
+ d->switchContext(stateData, rule->context(), newResult.captures());
+ newFormat = rule->attributeFormat().isValid() ? &rule->attributeFormat() : &stateData->topContext()->attributeFormat();
+ if (newOffset == text.size() && std::dynamic_pointer_cast<LineContinue>(rule))
+ lineContinuation = true;
+ break;
+ }
+ if (isLookAhead)
+ continue;
+
+ if (newOffset <= offset) { // no matching rule
+ if (stateData->topContext()->fallthrough()) {
+ d->switchContext(stateData, stateData->topContext()->fallthroughContext(), QStringList());
+ continue;
+ }
+
+ newOffset = offset + 1;
+ newFormat = &stateData->topContext()->attributeFormat();
+ }
+
+ /**
+ * if we arrive here, some new format has to be set!
+ */
+ Q_ASSERT(newFormat);
+
+ /**
+ * on format change, apply the last one and switch to new one
+ */
+ if (newFormat != currentFormat && newFormat->id() != currentFormat->id()) {
+ if (offset > 0)
+ applyFormat(beginOffset, offset - beginOffset, *currentFormat);
+ beginOffset = offset;
+ currentFormat = newFormat;
+ }
+
+ /**
+ * we must have made progress if we arrive here!
+ */
+ Q_ASSERT(newOffset > offset);
+ offset = newOffset;
+
+ } while (offset < text.size());
+
+ if (beginOffset < offset)
+ applyFormat(beginOffset, text.size() - beginOffset, *currentFormat);
+
+ while (!stateData->topContext()->lineEndContext().isStay() && !lineContinuation) {
+ if (!d->switchContext(stateData, stateData->topContext()->lineEndContext(), QStringList()))
+ break;
+ }
+
+ return newState;
+}
+
+bool AbstractHighlighterPrivate::switchContext(StateData *data, const ContextSwitch &contextSwitch, const QStringList &captures)
+{
+ // kill as many items as requested from the stack, will always keep the initial context alive!
+ const bool initialContextSurvived = data->pop(contextSwitch.popCount());
+
+ // if we have a new context to add, push it
+ // then we always "succeed"
+ if (contextSwitch.context()) {
+ data->push(contextSwitch.context(), captures);
+ return true;
+ }
+
+ // else we abort, if we did try to pop the initial context
+ return initialContextSurvived;
+}
+
+void AbstractHighlighter::applyFolding(int offset, int length, FoldingRegion region)
+{
+ Q_UNUSED(offset);
+ Q_UNUSED(length);
+ Q_UNUSED(region);
+}
diff --git a/src/libs/3rdparty/syntax-highlighting/src/lib/abstracthighlighter.h b/src/libs/3rdparty/syntax-highlighting/src/lib/abstracthighlighter.h
new file mode 100644
index 0000000000..2b88729697
--- /dev/null
+++ b/src/libs/3rdparty/syntax-highlighting/src/lib/abstracthighlighter.h
@@ -0,0 +1,195 @@
+/*
+ Copyright (C) 2016 Volker Krause <vkrause@kde.org>
+
+ Permission is hereby granted, free of charge, to any person obtaining
+ a copy of this software and associated documentation files (the
+ "Software"), to deal in the Software without restriction, including
+ without limitation the rights to use, copy, modify, merge, publish,
+ distribute, sublicense, and/or sell copies of the Software, and to
+ permit persons to whom the Software is furnished to do so, subject to
+ the following conditions:
+
+ The above copyright notice and this permission notice shall be included
+ in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+#ifndef KSYNTAXHIGHLIGHTING_ABSTRACTHIGHLIGHTERM_H
+#define KSYNTAXHIGHLIGHTING_ABSTRACTHIGHLIGHTERM_H
+
+#include "ksyntaxhighlighting_export.h"
+
+#include <QObject>
+
+#include <memory>
+
+QT_BEGIN_NAMESPACE
+class QString;
+QT_END_NAMESPACE
+
+namespace KSyntaxHighlighting {
+
+class AbstractHighlighterPrivate;
+class Definition;
+class FoldingRegion;
+class Format;
+class State;
+class Theme;
+
+/**
+ * Abstract base class for highlighters.
+ *
+ * @section abshl_intro Introduction
+ *
+ * The AbstractHighlighter provides an interface to highlight text.
+ *
+ * The SyntaxHighlighting framework already ships with one implementation,
+ * namely the SyntaxHighlighter, which also derives from QSyntaxHighlighter,
+ * meaning that it can be used to highlight a QTextDocument or a QML TextEdit.
+ * In order to use the SyntaxHighlighter, just call setDefinition() and
+ * setTheme(), and the associated documents will automatically be highlighted.
+ *
+ * However, if you want to use the SyntaxHighlighting framework to implement
+ * your own syntax highlighter, you need to sublcass from AbstractHighlighter.
+ *
+ * @section abshl_impl Implementing your own Syntax Highlighter
+ *
+ * In order to implement your own syntax highlighter, you need to inherit from
+ * AbstractHighlighter. Then, pass each text line that needs to be highlighted
+ * in order to highlightLine(). Internally, highlightLine() uses the Definition
+ * initially set through setDefinition() and the State of the previous text line
+ * to parse and highlight the given text line. For each visual highlighting
+ * change, highlightLine() will call applyFormat(). Therefore, reimplement
+ * applyFormat() to get notified of the Format that is valid in the range
+ * starting at the given offset with the specified length. Similarly, for each
+ * text part that starts or ends a code folding region, highlightLine() will
+ * call applyFolding(). Therefore, if you are interested in code folding,
+ * reimplement applyFolding() to get notified of the starting and ending code
+ * folding regions, again specified in the range starting at the given offset
+ * with the given length.
+ *
+ * The Format class itself depends on the current Theme. A theme must be
+ * initially set once such that the Format%s instances can be queried for
+ * concrete colors.
+ *
+ * Optionally, you can also reimplement setTheme() and setDefinition() to get
+ * notified whenever the Definition or the Theme changes.
+ *
+ * @see SyntaxHighlighter
+ * @since 5.28
+ */
+class KSYNTAXHIGHLIGHTING_EXPORT AbstractHighlighter
+{
+public:
+ virtual ~AbstractHighlighter();
+
+ /**
+ * Returns the syntax definition used for highlighting.
+ *
+ * @see setDefinition()
+ */
+ Definition definition() const;
+
+ /**
+ * Sets the syntax definition used for highlighting.
+ *
+ * Subclasses can re-implement this method to e.g. trigger
+ * re-highlighting or clear internal data structures if needed.
+ */
+ virtual void setDefinition(const Definition &def);
+
+ /**
+ * Returns the currently selected theme for highlighting.
+ *
+ * @note If no Theme was set through setTheme(), the returned Theme will be
+ * invalid, see Theme::isValid().
+ */
+ Theme theme() const;
+
+ /**
+ * Sets the theme used for highlighting.
+ *
+ * Subclasses can re-implement this method to e.g. trigger
+ * re-highlighing or to do general palette color setup.
+ */
+ virtual void setTheme(const Theme &theme);
+
+protected:
+ AbstractHighlighter();
+ AbstractHighlighter(AbstractHighlighterPrivate *dd);
+
+ // 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()
+ * and applyFolding() calls as a result.
+ * @param text A string containing the text of the line to highlight.
+ * @param state The highlighting state handle returned by the call
+ * to highlightLine() for the previous line. For the very first line,
+ * just pass a default constructed State().
+ * @returns The state of the highlighing engine after processing the
+ * given line. This needs to passed into highlightLine() for the
+ * next line. You can store the state for efficient partial
+ * re-highlighting for example during editing.
+ *
+ * @see applyFormat(), applyFolding()
+ */
+ State highlightLine(const QString &text, const State &state);
+
+ /**
+ * Reimplement this to apply formats to your output. The provided @p format
+ * is valid for the interval [@p offset, @p offset + @p length).
+ *
+ * @param offset The start column of the interval for which @p format matches
+ * @param length The length of the matching text
+ * @param format The Format that applies to the range [offset, offset + length)
+ *
+ * @note Make sure to set a valid Definition, otherwise the parameter
+ * @p format is invalid for the entire line passed to highlightLine()
+ * (cf. Format::isValid()).
+ *
+ * @see applyFolding(), highlightLine()
+ */
+ virtual void applyFormat(int offset, int length, const Format &format) = 0;
+
+ /**
+ * Reimplement this to apply folding to your output. The provided
+ * FoldingRegion @p region either stars or ends a code folding region in the
+ * interval [@p offset, @p offset + @p length).
+ *
+ * @param offset The start column of the FoldingRegion
+ * @param length The length of the matching text that starts / ends a
+ * folding region
+ * @param region The FoldingRegion that applies to the range [offset, offset + length)
+ *
+ * @note The FoldingRegion @p region is @e always either of type
+ * FoldingRegion::Type::Begin or FoldingRegion::Type::End.
+ *
+ * @see applyFormat(), highlightLine(), FoldingRegion
+ */
+ virtual void applyFolding(int offset, int length, FoldingRegion region);
+
+protected:
+ AbstractHighlighterPrivate *d_ptr;
+
+private:
+ Q_DECLARE_PRIVATE(AbstractHighlighter)
+ Q_DISABLE_COPY(AbstractHighlighter)
+};
+}
+
+QT_BEGIN_NAMESPACE
+Q_DECLARE_INTERFACE(KSyntaxHighlighting::AbstractHighlighter, "org.kde.SyntaxHighlighting.AbstractHighlighter")
+QT_END_NAMESPACE
+
+#endif // KSYNTAXHIGHLIGHTING_ABSTRACTHIGHLIGHTERM_H
diff --git a/src/libs/3rdparty/syntax-highlighting/src/lib/abstracthighlighter_p.h b/src/libs/3rdparty/syntax-highlighting/src/lib/abstracthighlighter_p.h
new file mode 100644
index 0000000000..bdfdf23bc1
--- /dev/null
+++ b/src/libs/3rdparty/syntax-highlighting/src/lib/abstracthighlighter_p.h
@@ -0,0 +1,54 @@
+/*
+ Copyright (C) 2016 Volker Krause <vkrause@kde.org>
+
+ Permission is hereby granted, free of charge, to any person obtaining
+ a copy of this software and associated documentation files (the
+ "Software"), to deal in the Software without restriction, including
+ without limitation the rights to use, copy, modify, merge, publish,
+ distribute, sublicense, and/or sell copies of the Software, and to
+ permit persons to whom the Software is furnished to do so, subject to
+ the following conditions:
+
+ The above copyright notice and this permission notice shall be included
+ in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+#ifndef KSYNTAXHIGHLIGHTING_ABSTRACTHIGHLIGHTER_P_H
+#define KSYNTAXHIGHLIGHTING_ABSTRACTHIGHLIGHTER_P_H
+
+#include "definition.h"
+#include "theme.h"
+
+QT_BEGIN_NAMESPACE
+class QStringList;
+QT_END_NAMESPACE
+
+namespace KSyntaxHighlighting {
+
+class ContextSwitch;
+class StateData;
+
+class AbstractHighlighterPrivate
+{
+public:
+ AbstractHighlighterPrivate();
+ virtual ~AbstractHighlighterPrivate();
+
+ void ensureDefinitionLoaded();
+ bool switchContext(StateData* data, const ContextSwitch &contextSwitch, const QStringList &captures);
+
+ Definition m_definition;
+ Theme m_theme;
+};
+
+}
+
+#endif
diff --git a/src/libs/3rdparty/syntax-highlighting/src/lib/context.cpp b/src/libs/3rdparty/syntax-highlighting/src/lib/context.cpp
new file mode 100644
index 0000000000..9887b959d0
--- /dev/null
+++ b/src/libs/3rdparty/syntax-highlighting/src/lib/context.cpp
@@ -0,0 +1,206 @@
+/*
+ Copyright (C) 2016 Volker Krause <vkrause@kde.org>
+
+ Permission is hereby granted, free of charge, to any person obtaining
+ a copy of this software and associated documentation files (the
+ "Software"), to deal in the Software without restriction, including
+ without limitation the rights to use, copy, modify, merge, publish,
+ distribute, sublicense, and/or sell copies of the Software, and to
+ permit persons to whom the Software is furnished to do so, subject to
+ the following conditions:
+
+ The above copyright notice and this permission notice shall be included
+ in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+#include "context_p.h"
+#include "definition_p.h"
+#include "format.h"
+#include "repository.h"
+#include "rule_p.h"
+#include "ksyntaxhighlighting_logging.h"
+#include "xml_p.h"
+
+#include <QString>
+#include <QXmlStreamReader>
+
+using namespace KSyntaxHighlighting;
+
+Definition Context::definition() const
+{
+ return m_def.definition();
+}
+
+void Context::setDefinition(const DefinitionRef &def)
+{
+ m_def = def;
+}
+
+bool Context::indentationBasedFoldingEnabled() const
+{
+ if (m_noIndentationBasedFolding)
+ return false;
+
+ return m_def.definition().indentationBasedFoldingEnabled();
+}
+
+void Context::load(QXmlStreamReader& reader)
+{
+ Q_ASSERT(reader.name() == QLatin1String("context"));
+ Q_ASSERT(reader.tokenType() == QXmlStreamReader::StartElement);
+
+ m_name = reader.attributes().value(QStringLiteral("name")).toString();
+ m_attribute = reader.attributes().value(QStringLiteral("attribute")).toString();
+ m_lineEndContext.parse(reader.attributes().value(QStringLiteral("lineEndContext")));
+ m_lineEmptyContext.parse(reader.attributes().value(QStringLiteral("lineEmptyContext")));
+ m_fallthrough = Xml::attrToBool(reader.attributes().value(QStringLiteral("fallthrough")));
+ m_fallthroughContext.parse(reader.attributes().value(QStringLiteral("fallthroughContext")));
+ if (m_fallthroughContext.isStay())
+ m_fallthrough = false;
+ m_noIndentationBasedFolding = Xml::attrToBool(reader.attributes().value(QStringLiteral("noIndentationBasedFolding")));
+
+ reader.readNext();
+ while (!reader.atEnd()) {
+ switch (reader.tokenType()) {
+ case QXmlStreamReader::StartElement:
+ {
+ auto rule = Rule::create(reader.name());
+ if (rule) {
+ rule->setDefinition(m_def.definition());
+ if (rule->load(reader))
+ m_rules.push_back(rule);
+ } else {
+ reader.skipCurrentElement();
+ }
+ reader.readNext();
+ break;
+ }
+ case QXmlStreamReader::EndElement:
+ return;
+ default:
+ reader.readNext();
+ break;
+ }
+ }
+}
+
+void Context::resolveContexts()
+{
+ const auto def = m_def.definition();
+ m_lineEndContext.resolve(def);
+ m_lineEmptyContext.resolve(def);
+ m_fallthroughContext.resolve(def);
+ for (const auto &rule : m_rules)
+ rule->resolveContext();
+}
+
+Context::ResolveState Context::resolveState()
+{
+ if (m_resolveState == Unknown) {
+ for (const auto &rule : m_rules) {
+ auto inc = std::dynamic_pointer_cast<IncludeRules>(rule);
+ if (inc) {
+ m_resolveState = Unresolved;
+ return m_resolveState;
+ }
+ }
+ m_resolveState = Resolved;
+ }
+ return m_resolveState;
+}
+
+void Context::resolveIncludes()
+{
+ if (resolveState() == Resolved)
+ return;
+ if (resolveState() == Resolving) {
+ qCWarning(Log) << "Cyclic dependency!";
+ return;
+ }
+
+ Q_ASSERT(resolveState() == Unresolved);
+ m_resolveState = Resolving; // cycle guard
+
+ for (auto it = m_rules.begin(); it != m_rules.end();) {
+ auto inc = std::dynamic_pointer_cast<IncludeRules>(*it);
+ if (!inc) {
+ ++it;
+ continue;
+ }
+ Context* context = nullptr;
+ auto myDefData = DefinitionData::get(m_def.definition());
+ if (inc->definitionName().isEmpty()) { // local include
+ context = myDefData->contextByName(inc->contextName());
+ } else {
+ auto def = myDefData->repo->definitionForName(inc->definitionName());
+ if (!def.isValid()) {
+ qCWarning(Log) << "Unable to resolve external include rule for definition" << inc->definitionName() << "in" << m_def.definition().name();
+ ++it;
+ continue;
+ }
+ auto defData = DefinitionData::get(def);
+ defData->load();
+ if (inc->contextName().isEmpty())
+ context = defData->initialContext();
+ else
+ context = defData->contextByName(inc->contextName());
+ }
+ if (!context) {
+ qCWarning(Log) << "Unable to resolve include rule for definition" << inc->contextName() << "##" << inc->definitionName() << "in" << m_def.definition().name();
+ ++it;
+ continue;
+ }
+ context->resolveIncludes();
+
+ /**
+ * handle included attribute
+ * transitive closure: we might include attributes included from somewhere else
+ */
+ if (inc->includeAttribute()) {
+ m_attribute = context->m_attribute;
+ m_attributeContext = context->m_attributeContext ? context->m_attributeContext : context;
+ }
+
+ it = m_rules.erase(it);
+ for (const auto &rule : context->rules()) {
+ it = m_rules.insert(it, rule);
+ ++it;
+ }
+ }
+
+ m_resolveState = Resolved;
+}
+
+void Context::resolveAttributeFormat()
+{
+ /**
+ * try to get our format from the definition we stem from
+ * we need to handle included attributes via m_attributeContext
+ */
+ if (!m_attribute.isEmpty()) {
+ const auto def = m_attributeContext ? m_attributeContext->m_def.definition() : m_def.definition();
+ m_attributeFormat = DefinitionData::get(def)->formatByName(m_attribute);
+ if (!m_attributeFormat.isValid()) {
+ if (m_attributeContext) {
+ qCWarning(Log) << "Context: Unknown format" << m_attribute << "in context" << m_name << "of definition" << m_def.definition().name() << "from included context" << m_attributeContext->m_name << "of definition" << def.name();
+ } else {
+ qCWarning(Log) << "Context: Unknown format" << m_attribute << "in context" << m_name << "of definition" << m_def.definition().name();
+ }
+ }
+ }
+
+ /**
+ * lookup formats for our rules
+ */
+ for (const auto &rule : m_rules) {
+ rule->resolveAttributeFormat(this);
+ }
+}
diff --git a/src/libs/3rdparty/syntax-highlighting/src/lib/context_p.h b/src/libs/3rdparty/syntax-highlighting/src/lib/context_p.h
new file mode 100644
index 0000000000..a034d0e27d
--- /dev/null
+++ b/src/libs/3rdparty/syntax-highlighting/src/lib/context_p.h
@@ -0,0 +1,139 @@
+/*
+ Copyright (C) 2016 Volker Krause <vkrause@kde.org>
+
+ Permission is hereby granted, free of charge, to any person obtaining
+ a copy of this software and associated documentation files (the
+ "Software"), to deal in the Software without restriction, including
+ without limitation the rights to use, copy, modify, merge, publish,
+ distribute, sublicense, and/or sell copies of the Software, and to
+ permit persons to whom the Software is furnished to do so, subject to
+ the following conditions:
+
+ The above copyright notice and this permission notice shall be included
+ in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+#ifndef KSYNTAXHIGHLIGHTING_CONTEXT_P_H
+#define KSYNTAXHIGHLIGHTING_CONTEXT_P_H
+
+#include "rule_p.h"
+#include "contextswitch_p.h"
+#include "definition.h"
+#include "definitionref_p.h"
+#include "format.h"
+
+#include <QString>
+
+#include <vector>
+
+QT_BEGIN_NAMESPACE
+class QXmlStreamReader;
+QT_END_NAMESPACE
+
+namespace KSyntaxHighlighting {
+
+class Context
+{
+public:
+ Context() = default;
+ ~Context() = default;
+
+ Definition definition() const;
+ void setDefinition(const DefinitionRef &def);
+
+ const QString &name() const
+ {
+ return m_name;
+ }
+
+ const ContextSwitch &lineEndContext() const
+ {
+ return m_lineEndContext;
+ }
+
+ const ContextSwitch &lineEmptyContext() const
+ {
+ return m_lineEmptyContext;
+ }
+
+ bool fallthrough() const
+ {
+ return m_fallthrough;
+ }
+
+ const ContextSwitch &fallthroughContext() const
+ {
+ return m_fallthroughContext;
+ }
+
+ const Format &attributeFormat() const
+ {
+ return m_attributeFormat;
+ }
+
+ const std::vector<Rule::Ptr> &rules() const
+ {
+ return m_rules;
+ }
+
+ /**
+ * Returns @c true, when indentationBasedFolding is enabled for the
+ * associated Definition and when "noIndentationBasedFolding" is NOT set.
+ */
+ bool indentationBasedFoldingEnabled() const;
+
+ void load(QXmlStreamReader &reader);
+ void resolveContexts();
+ void resolveIncludes();
+ void resolveAttributeFormat();
+
+private:
+ Q_DISABLE_COPY(Context)
+
+ enum ResolveState {
+ Unknown,
+ Unresolved,
+ Resolving,
+ Resolved
+ };
+ ResolveState resolveState();
+
+ DefinitionRef m_def;
+ QString m_name;
+
+ /**
+ * attribute name, to lookup our format
+ */
+ QString m_attribute;
+
+ /**
+ * context to use for lookup, if != this context
+ */
+ const Context *m_attributeContext = nullptr;
+
+ /**
+ * resolved format for our attribute, done in resolveAttributeFormat
+ */
+ Format m_attributeFormat;
+
+ ContextSwitch m_lineEndContext;
+ ContextSwitch m_lineEmptyContext;
+ ContextSwitch m_fallthroughContext;
+
+ std::vector<Rule::Ptr> m_rules;
+
+ ResolveState m_resolveState = Unknown;
+ bool m_fallthrough = false;
+ bool m_noIndentationBasedFolding = false;
+};
+}
+
+#endif // KSYNTAXHIGHLIGHTING_CONTEXT_P_H
diff --git a/src/libs/3rdparty/syntax-highlighting/src/lib/contextswitch.cpp b/src/libs/3rdparty/syntax-highlighting/src/lib/contextswitch.cpp
new file mode 100644
index 0000000000..a4d1dbbd85
--- /dev/null
+++ b/src/libs/3rdparty/syntax-highlighting/src/lib/contextswitch.cpp
@@ -0,0 +1,90 @@
+/*
+ Copyright (C) 2016 Volker Krause <vkrause@kde.org>
+
+ Permission is hereby granted, free of charge, to any person obtaining
+ a copy of this software and associated documentation files (the
+ "Software"), to deal in the Software without restriction, including
+ without limitation the rights to use, copy, modify, merge, publish,
+ distribute, sublicense, and/or sell copies of the Software, and to
+ permit persons to whom the Software is furnished to do so, subject to
+ the following conditions:
+
+ The above copyright notice and this permission notice shall be included
+ in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+#include "contextswitch_p.h"
+#include "definition.h"
+#include "definition_p.h"
+#include "repository.h"
+#include "ksyntaxhighlighting_logging.h"
+
+
+using namespace KSyntaxHighlighting;
+
+bool ContextSwitch::isStay() const
+{
+ return m_popCount == 0 && !m_context && m_contextName.isEmpty() && m_defName.isEmpty();
+}
+
+int ContextSwitch::popCount() const
+{
+ return m_popCount;
+}
+
+Context* ContextSwitch::context() const
+{
+ return m_context;
+}
+
+void ContextSwitch::parse(const QStringRef& contextInstr)
+{
+ if (contextInstr.isEmpty() || contextInstr == QLatin1String("#stay"))
+ return;
+
+ if (contextInstr.startsWith(QLatin1String("#pop!"))) {
+ ++m_popCount;
+ m_contextName = contextInstr.mid(5).toString();
+ return;
+ }
+
+ if (contextInstr.startsWith(QLatin1String("#pop"))) {
+ ++m_popCount;
+ parse(contextInstr.mid(4));
+ return;
+ }
+
+ const auto idx = contextInstr.indexOf(QLatin1String("##"));
+ if (idx >= 0) {
+ m_contextName = contextInstr.left(idx).toString();
+ m_defName = contextInstr.mid(idx + 2).toString();
+ } else {
+ m_contextName = contextInstr.toString();
+ }
+}
+
+void ContextSwitch::resolve(const Definition &def)
+{
+ auto d = def;
+ if (!m_defName.isEmpty()) {
+ d = DefinitionData::get(def)->repo->definitionForName(m_defName);
+ auto data = DefinitionData::get(d);
+ data->load();
+ if (m_contextName.isEmpty())
+ m_context = data->initialContext();
+ }
+
+ if (!m_contextName.isEmpty()) {
+ m_context = DefinitionData::get(d)->contextByName(m_contextName);
+ if (!m_context)
+ qCWarning(Log) << "cannot find context" << m_contextName << "in" << def.name();
+ }
+}
diff --git a/src/libs/3rdparty/syntax-highlighting/src/lib/contextswitch_p.h b/src/libs/3rdparty/syntax-highlighting/src/lib/contextswitch_p.h
new file mode 100644
index 0000000000..669855af7a
--- /dev/null
+++ b/src/libs/3rdparty/syntax-highlighting/src/lib/contextswitch_p.h
@@ -0,0 +1,56 @@
+/*
+ Copyright (C) 2016 Volker Krause <vkrause@kde.org>
+
+ Permission is hereby granted, free of charge, to any person obtaining
+ a copy of this software and associated documentation files (the
+ "Software"), to deal in the Software without restriction, including
+ without limitation the rights to use, copy, modify, merge, publish,
+ distribute, sublicense, and/or sell copies of the Software, and to
+ permit persons to whom the Software is furnished to do so, subject to
+ the following conditions:
+
+ The above copyright notice and this permission notice shall be included
+ in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+#ifndef KSYNTAXHIGHLIGHTING_CONTEXTSWITCH_P_H
+#define KSYNTAXHIGHLIGHTING_CONTEXTSWITCH_P_H
+
+#include <QString>
+
+namespace KSyntaxHighlighting {
+
+class Context;
+class Definition;
+
+class ContextSwitch
+{
+public:
+ ContextSwitch() = default;
+ ~ContextSwitch() = default;
+
+ bool isStay() const;
+
+ int popCount() const;
+ Context* context() const;
+
+ void parse(const QStringRef &contextInstr);
+ void resolve(const Definition &def);
+
+private:
+ QString m_defName;
+ QString m_contextName;
+ Context *m_context = nullptr;
+ int m_popCount = 0;
+};
+}
+
+#endif // KSYNTAXHIGHLIGHTING_CONTEXTSWITCH_P_H
diff --git a/src/libs/3rdparty/syntax-highlighting/src/lib/definition.cpp b/src/libs/3rdparty/syntax-highlighting/src/lib/definition.cpp
new file mode 100644
index 0000000000..c03d23dc48
--- /dev/null
+++ b/src/libs/3rdparty/syntax-highlighting/src/lib/definition.cpp
@@ -0,0 +1,798 @@
+/*
+ Copyright (C) 2016 Volker Krause <vkrause@kde.org>
+ Copyright (C) 2018 Dominik Haumann <dhaumann@kde.org>
+ Copyright (C) 2018 Christoph Cullmann <cullmann@kde.org>
+
+ Permission is hereby granted, free of charge, to any person obtaining
+ a copy of this software and associated documentation files (the
+ "Software"), to deal in the Software without restriction, including
+ without limitation the rights to use, copy, modify, merge, publish,
+ distribute, sublicense, and/or sell copies of the Software, and to
+ permit persons to whom the Software is furnished to do so, subject to
+ the following conditions:
+
+ The above copyright notice and this permission notice shall be included
+ in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+
+#include "definition.h"
+#include "definition_p.h"
+#include "definitionref_p.h"
+
+#include "context_p.h"
+#include "format.h"
+#include "format_p.h"
+#include "repository_p.h"
+#include "rule_p.h"
+#include "ksyntaxhighlighting_logging.h"
+#include "ksyntaxhighlighting_version.h"
+#include "xml_p.h"
+
+#include <QCoreApplication>
+#include <QDebug>
+#include <QFile>
+#include <QHash>
+#include <QJsonObject>
+#include <QStringList>
+#include <QVector>
+#include <QXmlStreamReader>
+
+#include <algorithm>
+
+using namespace KSyntaxHighlighting;
+
+DefinitionData::DefinitionData()
+ : wordDelimiters(QStringLiteral("\t !%&()*+,-./:;<=>?[\\]^{|}~")) // must be sorted!
+ , wordWrapDelimiters(wordDelimiters)
+{
+}
+
+DefinitionData::~DefinitionData()
+{
+ qDeleteAll(contexts);
+}
+
+DefinitionData* DefinitionData::get(const Definition &def)
+{
+ return def.d.get();
+}
+
+Definition::Definition() :
+ d(new DefinitionData)
+{
+}
+
+Definition::Definition(const Definition &other) :
+ d(other.d)
+{
+ d->q = *this;
+}
+
+Definition::Definition(const std::shared_ptr<DefinitionData> &dd) :
+ d(dd)
+{
+}
+
+Definition::~Definition()
+{
+}
+
+Definition& Definition::operator=(const Definition &rhs)
+{
+ d = rhs.d;
+ return *this;
+}
+
+bool Definition::operator==(const Definition &other) const
+{
+ return d->fileName == other.d->fileName;
+}
+
+bool Definition::operator!=(const Definition& other) const
+{
+ return d->fileName != other.d->fileName;
+}
+
+bool Definition::isValid() const
+{
+ return d->repo && !d->fileName.isEmpty() && !d->name.isEmpty();
+}
+
+QString Definition::filePath() const
+{
+ return d->fileName;
+}
+
+QString Definition::name() const
+{
+ return d->name;
+}
+
+QString Definition::translatedName() const
+{
+ return QCoreApplication::instance()->translate("Language", d->name.toUtf8().constData());
+}
+
+QString Definition::section() const
+{
+ return d->section;
+}
+
+QString Definition::translatedSection() const
+{
+ return QCoreApplication::instance()->translate("Language Section", d->section.toUtf8().constData());
+}
+
+QVector<QString> Definition::mimeTypes() const
+{
+ return d->mimetypes;
+}
+
+QVector<QString> Definition::extensions() const
+{
+ return d->extensions;
+}
+
+int Definition::version() const
+{
+ return d->version;
+}
+
+int Definition::priority() const
+{
+ return d->priority;
+}
+
+bool Definition::isHidden() const
+{
+ return d->hidden;
+}
+
+QString Definition::style() const
+{
+ return d->style;
+}
+
+QString Definition::indenter() const
+{
+ return d->indenter;
+}
+
+QString Definition::author() const
+{
+ return d->author;
+}
+
+QString Definition::license() const
+{
+ return d->license;
+}
+
+bool Definition::isWordDelimiter(QChar c) const
+{
+ d->load();
+ return d->isWordDelimiter(c);
+}
+
+bool Definition::isWordWrapDelimiter(QChar c) const
+{
+ d->load();
+ return std::binary_search(d->wordWrapDelimiters.constBegin(), d->wordWrapDelimiters.constEnd(), c);
+}
+
+bool Definition::foldingEnabled() const
+{
+ d->load();
+ if (d->hasFoldingRegions || indentationBasedFoldingEnabled()) {
+ return true;
+ }
+
+ // check included definitions
+ const auto defs = includedDefinitions();
+ for (const auto &def : defs) {
+ if (def.foldingEnabled()) {
+ d->hasFoldingRegions = true;
+ break;
+ }
+ }
+
+ return d->hasFoldingRegions;
+}
+
+bool Definition::indentationBasedFoldingEnabled() const
+{
+ d->load();
+ return d->indentationBasedFolding;
+}
+
+QStringList Definition::foldingIgnoreList() const
+{
+ d->load();
+ return d->foldingIgnoreList;
+}
+
+QStringList Definition::keywordLists() const
+{
+ d->load();
+ return d->keywordLists.keys();
+}
+
+QStringList Definition::keywordList(const QString& name) const
+{
+ d->load();
+ const auto list = d->keywordList(name);
+ return list ? list->keywords() : QStringList();
+}
+
+QVector<Format> Definition::formats() const
+{
+ d->load();
+
+ // sort formats so that the order matches the order of the itemDatas in the xml files.
+ auto formatList = QVector<Format>::fromList(d->formats.values());
+ std::sort(formatList.begin(), formatList.end(), [](const KSyntaxHighlighting::Format & lhs, const KSyntaxHighlighting::Format & rhs){
+ return lhs.id() < rhs.id();
+ });
+
+ return formatList;
+}
+
+QVector<Definition> Definition::includedDefinitions() const
+{
+ d->load();
+
+ // init worklist and result used as guard with this definition
+ QVector<Definition> queue{*this};
+ QVector<Definition> definitions{*this};
+ while (!queue.isEmpty()) {
+ // Iterate all context rules to find associated Definitions. This will
+ // automatically catch other Definitions referenced with IncludeRuldes or ContextSwitch.
+ const auto definition = queue.takeLast();
+ for (const auto & context : qAsConst(definition.d->contexts)) {
+ // handle context switch attributes of this context itself
+ for (const auto switchContext : {context->lineEndContext().context(), context->lineEmptyContext().context(), context->fallthroughContext().context()}) {
+ if (switchContext) {
+ if (!definitions.contains(switchContext->definition())) {
+ queue.push_back(switchContext->definition());
+ definitions.push_back(switchContext->definition());
+ }
+ }
+ }
+
+ // handle the embedded rules
+ for (const auto &rule : context->rules()) {
+ // handle include rules like inclusion
+ if (!definitions.contains(rule->definition())) {
+ queue.push_back(rule->definition());
+ definitions.push_back(rule->definition());
+ }
+
+ // handle context switch context inclusion
+ if (auto switchContext = rule->context().context()) {
+ if (!definitions.contains(switchContext->definition())) {
+ queue.push_back(switchContext->definition());
+ definitions.push_back(switchContext->definition());
+ }
+ }
+ }
+ }
+ }
+
+ // remove the 1st entry, since it is this Definition
+ definitions.pop_front();
+
+ return definitions;
+}
+
+QString Definition::singleLineCommentMarker() const
+{
+ d->load();
+ return d->singleLineCommentMarker;
+}
+
+CommentPosition Definition::singleLineCommentPosition() const
+{
+ d->load();
+ return d->singleLineCommentPosition;
+}
+
+QPair<QString, QString> Definition::multiLineCommentMarker() const
+{
+ d->load();
+ return { d->multiLineCommentStartMarker, d->multiLineCommentEndMarker };
+}
+
+QVector<QPair<QChar, QString>> Definition::characterEncodings() const
+{
+ d->load();
+ return d->characterEncodings;
+}
+
+Context* DefinitionData::initialContext() const
+{
+ Q_ASSERT(!contexts.isEmpty());
+ return contexts.first();
+}
+
+Context* DefinitionData::contextByName(const QString& name) const
+{
+ foreach (auto context, contexts) {
+ if (context->name() == name)
+ return context;
+ }
+ return nullptr;
+}
+
+KeywordList *DefinitionData::keywordList(const QString& name)
+{
+ auto it = keywordLists.find(name);
+ return (it == keywordLists.end()) ? nullptr : &it.value();
+}
+
+bool DefinitionData::isWordDelimiter(QChar c) const
+{
+ return std::binary_search(wordDelimiters.constBegin(), wordDelimiters.constEnd(), c);
+}
+
+Format DefinitionData::formatByName(const QString& name) const
+{
+ const auto it = formats.constFind(name);
+ if (it != formats.constEnd())
+ return it.value();
+
+ return Format();
+}
+
+bool DefinitionData::isLoaded() const
+{
+ return !contexts.isEmpty();
+}
+
+bool DefinitionData::load()
+{
+ if (fileName.isEmpty())
+ return false;
+
+ if (isLoaded())
+ return true;
+
+ QFile file(fileName);
+ if (!file.open(QFile::ReadOnly))
+ return false;
+
+ QXmlStreamReader reader(&file);
+ while (!reader.atEnd()) {
+ const auto token = reader.readNext();
+ if (token != QXmlStreamReader::StartElement)
+ continue;
+
+ if (reader.name() == QLatin1String("highlighting"))
+ loadHighlighting(reader);
+
+ else if (reader.name() == QLatin1String("general"))
+ loadGeneral(reader);
+ }
+
+ for (auto it = keywordLists.begin(); it != keywordLists.end(); ++it)
+ (*it).setCaseSensitivity(caseSensitive);
+
+ foreach (auto context, contexts) {
+ context->resolveContexts();
+ context->resolveIncludes();
+ context->resolveAttributeFormat();
+ }
+
+ Q_ASSERT(std::is_sorted(wordDelimiters.constBegin(), wordDelimiters.constEnd()));
+ return true;
+}
+
+void DefinitionData::clear()
+{
+ // keep only name and repo, so we can re-lookup to make references persist over repo reloads
+ keywordLists.clear();
+ qDeleteAll(contexts);
+ contexts.clear();
+ formats.clear();
+
+ fileName.clear();
+ section.clear();
+ style.clear();
+ indenter.clear();
+ author.clear();
+ license.clear();
+ mimetypes.clear();
+ extensions.clear();
+ wordDelimiters = QStringLiteral("\t !%&()*+,-./:;<=>?[\\]^{|}~"); // must be sorted!
+ wordWrapDelimiters = wordDelimiters;
+ caseSensitive = Qt::CaseSensitive;
+ version = 0.0f;
+ priority = 0;
+ hidden = false;
+}
+
+bool DefinitionData::loadMetaData(const QString& definitionFileName)
+{
+ fileName = definitionFileName;
+
+ QFile file(definitionFileName);
+ if (!file.open(QFile::ReadOnly))
+ return false;
+
+ QXmlStreamReader reader(&file);
+ while (!reader.atEnd()) {
+ const auto token = reader.readNext();
+ if (token != QXmlStreamReader::StartElement)
+ continue;
+ if (reader.name() == QLatin1String("language")) {
+ return loadLanguage(reader);
+ }
+ }
+
+ return false;
+}
+
+bool DefinitionData::loadMetaData(const QString &file, const QJsonObject &obj)
+{
+ name = obj.value(QLatin1String("name")).toString();
+ section = obj.value(QLatin1String("section")).toString();
+ version = obj.value(QLatin1String("version")).toInt();
+ priority = obj.value(QLatin1String("priority")).toInt();
+ style = obj.value(QLatin1String("style")).toString();
+ author = obj.value(QLatin1String("author")).toString();
+ license = obj.value(QLatin1String("license")).toString();
+ indenter = obj.value(QLatin1String("indenter")).toString();
+ hidden = obj.value(QLatin1String("hidden")).toBool();
+ fileName = file;
+
+ const auto exts = obj.value(QLatin1String("extensions")).toString();
+ foreach (const auto &ext, exts.split(QLatin1Char(';'), QString::SkipEmptyParts))
+ extensions.push_back(ext);
+ const auto mts = obj.value(QLatin1String("mimetype")).toString();
+ foreach (const auto &mt, mts.split(QLatin1Char(';'), QString::SkipEmptyParts))
+ mimetypes.push_back(mt);
+
+ return true;
+}
+
+bool DefinitionData::loadLanguage(QXmlStreamReader &reader)
+{
+ Q_ASSERT(reader.name() == QLatin1String("language"));
+ Q_ASSERT(reader.tokenType() == QXmlStreamReader::StartElement);
+
+ if (!checkKateVersion(reader.attributes().value(QStringLiteral("kateversion"))))
+ return false;
+
+ name = reader.attributes().value(QStringLiteral("name")).toString();
+ section = reader.attributes().value(QStringLiteral("section")).toString();
+ // toFloat instead of toInt for backward compatibility with old Kate files
+ version = reader.attributes().value(QStringLiteral("version")).toFloat();
+ priority = reader.attributes().value(QStringLiteral("priority")).toInt();
+ hidden = Xml::attrToBool(reader.attributes().value(QStringLiteral("hidden")));
+ style = reader.attributes().value(QStringLiteral("style")).toString();
+ indenter = reader.attributes().value(QStringLiteral("indenter")).toString();
+ author = reader.attributes().value(QStringLiteral("author")).toString();
+ license = reader.attributes().value(QStringLiteral("license")).toString();
+ const auto exts = reader.attributes().value(QStringLiteral("extensions")).toString();
+ foreach (const auto &ext, exts.split(QLatin1Char(';'), QString::SkipEmptyParts))
+ extensions.push_back(ext);
+ const auto mts = reader.attributes().value(QStringLiteral("mimetype")).toString();
+ foreach (const auto &mt, mts.split(QLatin1Char(';'), QString::SkipEmptyParts))
+ mimetypes.push_back(mt);
+ if (reader.attributes().hasAttribute(QStringLiteral("casesensitive")))
+ caseSensitive = Xml::attrToBool(reader.attributes().value(QStringLiteral("casesensitive"))) ? Qt::CaseSensitive : Qt::CaseInsensitive;
+ return true;
+}
+
+void DefinitionData::loadHighlighting(QXmlStreamReader& reader)
+{
+ Q_ASSERT(reader.name() == QLatin1String("highlighting"));
+ Q_ASSERT(reader.tokenType() == QXmlStreamReader::StartElement);
+
+ while (!reader.atEnd()) {
+ switch (reader.tokenType()) {
+ case QXmlStreamReader::StartElement:
+ if (reader.name() == QLatin1String("list")) {
+ KeywordList keywords;
+ keywords.load(reader);
+ keywordLists.insert(keywords.name(), keywords);
+ } else if (reader.name() == QLatin1String("contexts")) {
+ loadContexts(reader);
+ reader.readNext();
+ } else if (reader.name() == QLatin1String("itemDatas")) {
+ loadItemData(reader);
+ } else {
+ reader.readNext();
+ }
+ break;
+ case QXmlStreamReader::EndElement:
+ return;
+ default:
+ reader.readNext();
+ break;
+ }
+ }
+}
+
+void DefinitionData::loadContexts(QXmlStreamReader& reader)
+{
+ Q_ASSERT(reader.name() == QLatin1String("contexts"));
+ Q_ASSERT(reader.tokenType() == QXmlStreamReader::StartElement);
+
+ while (!reader.atEnd()) {
+ switch (reader.tokenType()) {
+ case QXmlStreamReader::StartElement:
+ if (reader.name() == QLatin1String("context")) {
+ auto context = new Context;
+ context->setDefinition(q);
+ context->load(reader);
+ contexts.push_back(context);
+ }
+ reader.readNext();
+ break;
+ case QXmlStreamReader::EndElement:
+ return;
+ default:
+ reader.readNext();
+ break;
+ }
+ }
+}
+
+void DefinitionData::loadItemData(QXmlStreamReader& reader)
+{
+ Q_ASSERT(reader.name() == QLatin1String("itemDatas"));
+ Q_ASSERT(reader.tokenType() == QXmlStreamReader::StartElement);
+
+ while (!reader.atEnd()) {
+ switch (reader.tokenType()) {
+ case QXmlStreamReader::StartElement:
+ if (reader.name() == QLatin1String("itemData")) {
+ Format f;
+ auto formatData = FormatPrivate::detachAndGet(f);
+ formatData->definition = q;
+ formatData->load(reader);
+ formatData->id = RepositoryPrivate::get(repo)->nextFormatId();
+ formats.insert(f.name(), f);
+ reader.readNext();
+ }
+ reader.readNext();
+ break;
+ case QXmlStreamReader::EndElement:
+ return;
+ default:
+ reader.readNext();
+ break;
+ }
+ }
+}
+
+void DefinitionData::loadGeneral(QXmlStreamReader& reader)
+{
+ Q_ASSERT(reader.name() == QLatin1String("general"));
+ Q_ASSERT(reader.tokenType() == QXmlStreamReader::StartElement);
+ reader.readNext();
+
+ // reference counter to count XML child elements, to not return too early
+ int elementRefCounter = 1;
+
+ while (!reader.atEnd()) {
+ switch (reader.tokenType()) {
+ case QXmlStreamReader::StartElement:
+ ++elementRefCounter;
+
+ if (reader.name() == QLatin1String("keywords")) {
+ if (reader.attributes().hasAttribute(QStringLiteral("casesensitive")))
+ caseSensitive = Xml::attrToBool(reader.attributes().value(QStringLiteral("casesensitive"))) ? Qt::CaseSensitive : Qt::CaseInsensitive;
+
+ // adapt sorted wordDelimiters
+ wordDelimiters += reader.attributes().value(QStringLiteral("additionalDeliminator"));
+ std::sort(wordDelimiters.begin(), wordDelimiters.end());
+ auto it = std::unique(wordDelimiters.begin(), wordDelimiters.end());
+ wordDelimiters.truncate(std::distance(wordDelimiters.begin(), it));
+ foreach (const auto c, reader.attributes().value(QLatin1String("weakDeliminator")))
+ wordDelimiters.remove(c);
+
+ // adaptWordWrapDelimiters, and sort
+ wordWrapDelimiters = reader.attributes().value(QStringLiteral("wordWrapDeliminator")).toString();
+ std::sort(wordWrapDelimiters.begin(), wordWrapDelimiters.end());
+ if (wordWrapDelimiters.isEmpty())
+ wordWrapDelimiters = wordDelimiters;
+ } else if (reader.name() == QLatin1String("folding")) {
+ if (reader.attributes().hasAttribute(QStringLiteral("indentationsensitive")))
+ indentationBasedFolding = Xml::attrToBool(reader.attributes().value(QStringLiteral("indentationsensitive")));
+ } else if (reader.name() == QLatin1String("emptyLines")) {
+ loadFoldingIgnoreList(reader);
+ } else if (reader.name() == QLatin1String("comments")) {
+ loadComments(reader);
+ } else if (reader.name() == QLatin1String("spellchecking")) {
+ loadSpellchecking(reader);
+ } else {
+ reader.skipCurrentElement();
+ }
+ reader.readNext();
+ break;
+ case QXmlStreamReader::EndElement:
+ --elementRefCounter;
+ if (elementRefCounter == 0)
+ return;
+ reader.readNext();
+ break;
+ default:
+ reader.readNext();
+ break;
+ }
+ }
+}
+
+void DefinitionData::loadComments(QXmlStreamReader &reader)
+{
+ Q_ASSERT(reader.name() == QLatin1String("comments"));
+ Q_ASSERT(reader.tokenType() == QXmlStreamReader::StartElement);
+ reader.readNext();
+
+ // reference counter to count XML child elements, to not return too early
+ int elementRefCounter = 1;
+
+ while (!reader.atEnd()) {
+ switch (reader.tokenType()) {
+ case QXmlStreamReader::StartElement:
+ ++elementRefCounter;
+ if (reader.name() == QLatin1String("comment")) {
+ const bool isSingleLine = reader.attributes().value(QStringLiteral("name")) == QStringLiteral("singleLine");
+ if (isSingleLine) {
+ singleLineCommentMarker = reader.attributes().value(QStringLiteral("start")).toString();
+ const bool afterWhiteSpace = reader.attributes().value(QStringLiteral("position")).toString() == QStringLiteral("afterwhitespace");
+ singleLineCommentPosition = afterWhiteSpace ? CommentPosition::AfterWhitespace : CommentPosition::StartOfLine;
+ } else {
+ multiLineCommentStartMarker = reader.attributes().value(QStringLiteral("start")).toString();
+ multiLineCommentEndMarker = reader.attributes().value(QStringLiteral("end")).toString();
+ }
+ }
+ reader.readNext();
+ break;
+ case QXmlStreamReader::EndElement:
+ --elementRefCounter;
+ if (elementRefCounter == 0)
+ return;
+ reader.readNext();
+ break;
+ default:
+ reader.readNext();
+ break;
+ }
+ }
+}
+
+void DefinitionData::loadFoldingIgnoreList(QXmlStreamReader& reader)
+{
+ Q_ASSERT(reader.name() == QLatin1String("emptyLines"));
+ Q_ASSERT(reader.tokenType() == QXmlStreamReader::StartElement);
+ reader.readNext();
+
+ // reference counter to count XML child elements, to not return too early
+ int elementRefCounter = 1;
+
+ while (!reader.atEnd()) {
+ switch (reader.tokenType()) {
+ case QXmlStreamReader::StartElement:
+ ++elementRefCounter;
+ if (reader.name() == QLatin1String("emptyLine")) {
+ foldingIgnoreList << reader.attributes().value(QStringLiteral("regexpr")).toString();
+ }
+ reader.readNext();
+ break;
+ case QXmlStreamReader::EndElement:
+ --elementRefCounter;
+ if (elementRefCounter == 0)
+ return;
+ reader.readNext();
+ break;
+ default:
+ reader.readNext();
+ break;
+ }
+ }
+}
+
+void DefinitionData::loadSpellchecking(QXmlStreamReader &reader)
+{
+ Q_ASSERT(reader.name() == QLatin1String("spellchecking"));
+ Q_ASSERT(reader.tokenType() == QXmlStreamReader::StartElement);
+ reader.readNext();
+
+ // reference counter to count XML child elements, to not return too early
+ int elementRefCounter = 1;
+
+ while (!reader.atEnd()) {
+ switch (reader.tokenType()) {
+ case QXmlStreamReader::StartElement:
+ ++elementRefCounter;
+ if (reader.name() == QLatin1String("encoding")) {
+ const auto charRef = reader.attributes().value(QStringLiteral("char"));
+ if (!charRef.isEmpty()) {
+ const auto str = reader.attributes().value(QStringLiteral("string")).toString();
+ characterEncodings.push_back({ charRef[0], str });
+ }
+ }
+ reader.readNext();
+ break;
+ case QXmlStreamReader::EndElement:
+ --elementRefCounter;
+ if (elementRefCounter == 0)
+ return;
+ reader.readNext();
+ break;
+ default:
+ reader.readNext();
+ break;
+ }
+ }
+}
+
+bool DefinitionData::checkKateVersion(const QStringRef& verStr)
+{
+ const auto idx = verStr.indexOf(QLatin1Char('.'));
+ if (idx <= 0) {
+ qCWarning(Log) << "Skipping" << fileName << "due to having no valid kateversion attribute:" << verStr;
+ return false;
+ }
+ 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)) {
+ qCWarning(Log) << "Skipping" << fileName << "due to being too new, version:" << verStr;
+ return false;
+ }
+
+ return true;
+}
+
+quint16 DefinitionData::foldingRegionId(const QString &foldName)
+{
+ hasFoldingRegions = true;
+ return RepositoryPrivate::get(repo)->foldingRegionId(name, foldName);
+}
+
+DefinitionRef::DefinitionRef()
+{
+}
+
+DefinitionRef::DefinitionRef(const Definition &def) :
+ d(def.d)
+{
+}
+
+DefinitionRef::~DefinitionRef()
+{
+}
+
+DefinitionRef& DefinitionRef::operator=(const Definition &def)
+{
+ d = def.d;
+ return *this;
+}
+
+Definition DefinitionRef::definition() const
+{
+ if (!d.expired())
+ return Definition(d.lock());
+ return Definition();
+}
+
+bool DefinitionRef::operator==(const DefinitionRef &other) const
+{
+ if (d.expired() != other.d.expired()) {
+ return false;
+ }
+
+ return d.expired() || d.lock().get() == other.d.lock().get();
+}
diff --git a/src/libs/3rdparty/syntax-highlighting/src/lib/definition.h b/src/libs/3rdparty/syntax-highlighting/src/lib/definition.h
new file mode 100644
index 0000000000..6f0dba9a45
--- /dev/null
+++ b/src/libs/3rdparty/syntax-highlighting/src/lib/definition.h
@@ -0,0 +1,400 @@
+/*
+ Copyright (C) 2016 Volker Krause <vkrause@kde.org>
+
+ Permission is hereby granted, free of charge, to any person obtaining
+ a copy of this software and associated documentation files (the
+ "Software"), to deal in the Software without restriction, including
+ without limitation the rights to use, copy, modify, merge, publish,
+ distribute, sublicense, and/or sell copies of the Software, and to
+ permit persons to whom the Software is furnished to do so, subject to
+ the following conditions:
+
+ The above copyright notice and this permission notice shall be included
+ in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+#ifndef KSYNTAXHIGHLIGHTING_DEFINITION_H
+#define KSYNTAXHIGHLIGHTING_DEFINITION_H
+
+#include "ksyntaxhighlighting_export.h"
+
+#include <QTypeInfo>
+#include <QPair>
+
+#include <memory>
+
+QT_BEGIN_NAMESPACE
+class QChar;
+class QString;
+class QStringList;
+template <typename T> class QVector;
+QT_END_NAMESPACE
+
+namespace KSyntaxHighlighting {
+
+class Context;
+class Format;
+class KeywordList;
+
+class DefinitionData;
+
+/**
+ * Defines the insert position when commenting code.
+ * @since 5.50
+ * @see Definition::singleLineCommentPosition()
+ */
+enum class CommentPosition
+{
+ //! The comment marker is inserted at the beginning of a line at column 0
+ StartOfLine = 0,
+ //! The comment marker is inserted after leading whitespaces right befire
+ //! the first non-whitespace character.
+ AfterWhitespace
+};
+
+/**
+ * Represents a syntax definition.
+ *
+ * @section def_intro Introduction to Definitions
+ *
+ * A Definition is the short term for a syntax highlighting definition. It
+ * typically is defined in terms of an XML syntax highlighting file, containing
+ * all information about a particular syntax highlighting. This includes the
+ * highlighting of keywords, information about code folding regions, and
+ * indentation preferences.
+ *
+ * @section def_info General Header Data
+ *
+ * Each Definition contains a non-translated unique name() and a section().
+ * In addition, for putting this information e.g. into menus, the functions
+ * translatedName() and translatedSection() are provided. However, if isHidden()
+ * returns @e true, the Definition should not be visible in the UI. The location
+ * of the Definition can be obtained through filePath(), which either is the
+ * location on disk or a path to a compiled-in Qt resource.
+ *
+ * The supported files of a Definition are defined by the list of extensions(),
+ * and additionally by the list of mimeTypes(). Note, that extensions() returns
+ * wildcards that need to be matched against the filename of the file that
+ * requires highlighting. If multiple Definition%s match the file, then the one
+ * with higher priority() wins.
+ *
+ * @section def_metadata Advanced Definition Data
+ *
+ * Advanced text editors such as Kate require additional information from a
+ * Definition. For instance, foldingEnabled() defines whether a Definition has
+ * code folding regions that can be shown in a code folding pane. Or
+ * singleLineCommentMarker() and multiLineCommentMarker() provide comment
+ * markers that can be used for commenting/uncommenting code. Similarly,
+ * formats() returns a list of Format items defined by this Definition (which
+ * equal the itemDatas of a highlighing definition file). includedDefinitions()
+ * returns a list of all included Definition%s referenced by this Definition via
+ * the rule IncludeRules, which is useful for displaying all Format items for
+ * color configuration in the user interface.
+ *
+ * @see Repository
+ * @since 5.28
+ */
+class KSYNTAXHIGHLIGHTING_EXPORT Definition
+{
+public:
+ /**
+ * Default constructor, creating an empty (invalid) Definition instance.
+ * isValid() for this instance returns @e false.
+ *
+ * Use the Repository instead to obtain valid instances.
+ */
+ Definition();
+
+ /**
+ * Copy constructor.
+ * Both this definition as well as @p other share the Definition data.
+ */
+ Definition(const Definition &other);
+
+ /**
+ * Destructor.
+ */
+ ~Definition();
+
+ /**
+ * Assignment operator.
+ * Both this definition as well as @p rhs share the Definition data.
+ */
+ Definition& operator=(const Definition &rhs);
+
+ /**
+ * Checks two definitions for equality.
+ */
+ bool operator==(const Definition &other) const;
+
+ /**
+ * Checks two definitions for inequality.
+ */
+ bool operator!=(const Definition &other) const;
+
+ /**
+ * @name General Header Data
+ *
+ * @{
+ */
+
+ /**
+ * Checks whether this object refers to a valid syntax definition.
+ */
+ bool isValid() const;
+
+ /**
+ * Returns the full path to the definition XML file containing
+ * the syntax definition. Note that this can be a path to QRC content.
+ */
+ QString filePath() const;
+
+ /** Name of the syntax.
+ * Used for internal references, prefer translatedName() for display.
+ */
+ QString name() const;
+
+ /**
+ * Translated name for display.
+ */
+ QString translatedName() const;
+
+ /**
+ * The group this syntax definition belongs to.
+ * For display, consider translatedSection().
+ */
+ QString section() const;
+
+ /**
+ * Translated group name for display.
+ */
+ QString translatedSection() const;
+
+ /**
+ * Mime types associated with this syntax definition.
+ */
+ QVector<QString> mimeTypes() const;
+
+ /**
+ * File extensions associated with this syntax definition.
+ * The returned list contains wildcards.
+ */
+ QVector<QString> extensions() const;
+
+ /**
+ * Returns the definition version.
+ */
+ int version() const;
+
+ /**
+ * Returns the definition priority.
+ * A Definition with higher priority wins over Definitions with lower priorities.
+ */
+ int priority() const;
+
+ /**
+ * Returns @c true if this is an internal definition that should not be
+ * displayed to the user.
+ */
+ bool isHidden() const;
+
+ /**
+ * Generalized language style, used for indentation.
+ */
+ QString style() const;
+
+ /**
+ * Indentation style to be used for this syntax.
+ */
+ QString indenter() const;
+
+ /**
+ * Name and email of the author of this syntax definition.
+ */
+ QString author() const;
+
+ /**
+ * License of this syntax definition.
+ */
+ QString license() const;
+
+ /**
+ * @}
+ *
+ * @name Advanced Definition Data
+ */
+
+ /**
+ * Returns whether the character @p c is a word delimiter.
+ * A delimiter defines whether a characters is a word boundary. Internally,
+ * delimiters are used for matching keyword lists. As example, typically the
+ * dot '.' is a word delimiter. However, if you have a keyword in a keyword
+ * list that contains a dot, you have to add the dot to the
+ * @e weakDeliminator attribute of the @e general section in your
+ * highlighting definition. Similarly, sometimes additional delimiters are
+ * required, which can be specified in @e additionalDeliminator.
+ *
+ * Checking whether a character is a delimiter is useful for instance if
+ * text is selected with double click. Typically, the whole word should be
+ * selected in this case. Similarly to the example above, the dot '.'
+ * usually acts as word delimiter. However, using this function you can
+ * implement text selection in such a way that keyword lists are correctly
+ * selected.
+ *
+ * @note By default, the list of delimiters contains the following
+ * characters: \\t !%&()*+,-./:;<=>?[\\]^{|}~
+ *
+ * @since 5.50
+ * @see isWordWrapDelimiter()
+ */
+ bool isWordDelimiter(QChar c) const;
+
+ /**
+ * Returns whether it is safe to break a line at before the character @c.
+ * This is useful when wrapping a line e.g. by applying static word wrap.
+ *
+ * As example, consider the LaTeX code
+ * @code
+ * \command1\command2
+ * @endcode
+ * Applying static word wrap could lead to the following code:
+ * @code
+ * \command1\
+ * command2
+ * @endcode
+ * command2 without a leading backslash is invalid in LaTeX. If '\\' is set
+ * as word wrap delimiter, isWordWrapDelimiter('\\') then returns true,
+ * meaning that it is safe to break the line before @c. The resulting code
+ * then would be
+ * @code
+ * \command1
+ * \command2
+ * @endcode
+ *
+ * @note By default, the word wrap delimiters are equal to the word
+ * delimiters in isWordDelimiter().
+ *
+ * @since 5.50
+ * @see isWordDelimiter()
+ */
+ bool isWordWrapDelimiter(QChar c) const;
+
+ /**
+ * Returns whether the highlighting supports code folding.
+ * Code folding is supported either if the highlighting defines code folding
+ * regions or if indentationBasedFoldingEnabled() returns @e true.
+ * @since 5.50
+ * @see indentationBasedFoldingEnabled()
+ */
+ bool foldingEnabled() const;
+
+ /**
+ * Returns whether indentation-based folding is enabled.
+ * An example for indentation-based folding is Python.
+ * When indentation-based folding is enabled, make sure to also check
+ * foldingIgnoreList() for lines that should be treated as empty.
+ *
+ * @see foldingIgnoreList(), State::indentationBasedFoldingEnabled()
+ */
+ bool indentationBasedFoldingEnabled() const;
+
+ /**
+ * If indentationBasedFoldingEnabled() returns @c true, this function returns
+ * a list of regular expressions that represent empty lines. That is, all
+ * lines matching entirely one of the regular expressions should be treated
+ * as empty lines when calculating the indentation-based folding ranges.
+ *
+ * @note This list is only of relevance, if indentationBasedFoldingEnabled()
+ * returns @c true.
+ *
+ * @see indentationBasedFoldingEnabled()
+ */
+ QStringList foldingIgnoreList() const;
+
+ /**
+ * Returns the section names of keywords.
+ * @since 5.49
+ * @see keywordList()
+ */
+ QStringList keywordLists() const;
+
+ /**
+ * Returns the list of keywords for the keyword list @p name.
+ * @since 5.49
+ * @see keywordLists()
+ */
+ QStringList keywordList(const QString& name) const;
+
+ /**
+ * Returns a list of all Format items used by this definition.
+ * The order of the Format items equals the order of the itemDatas in the xml file.
+ * @since 5.49
+ */
+ QVector<Format> formats() const;
+
+ /**
+ * Returns a list of Definitions that are referenced with the IncludeRules rule.
+ * The returned list does not include this Definition. In case no other
+ * Definitions are referenced via IncludeRules, the returned list is empty.
+ *
+ * @since 5.49
+ */
+ QVector<Definition> includedDefinitions() const;
+
+ /**
+ * Returns the marker that starts a single line comment.
+ * For instance, in C++ the single line comment marker is "//".
+ * @since 5.50
+ * @see singleLineCommentPosition();
+ */
+ QString singleLineCommentMarker() const;
+
+ /**
+ * Returns the insert position of the comment marker for sinle line
+ * comments.
+ * @since 5.50
+ * @see singleLineCommentMarker();
+ */
+ CommentPosition singleLineCommentPosition() const;
+
+ /**
+ * Returns the markers that start and end multiline comments.
+ * For instance, in XML this is defined as "<!--" and "-->".
+ * @since 5.50
+ */
+ QPair<QString, QString> multiLineCommentMarker() const;
+
+ /**
+ * Returns a list of character/string mapping that can be used for spell
+ * checking. This is useful for instance when spell checking LaTeX, where
+ * the string \"{A} represents the character Ä.
+ * @since 5.50
+ */
+ QVector<QPair<QChar, QString>> characterEncodings() const;
+
+ /**
+ * @}
+ */
+
+private:
+ friend class DefinitionData;
+ friend class DefinitionRef;
+ explicit Definition(const std::shared_ptr<DefinitionData> &dd);
+ std::shared_ptr<DefinitionData> d;
+};
+
+}
+
+QT_BEGIN_NAMESPACE
+Q_DECLARE_TYPEINFO(KSyntaxHighlighting::Definition, Q_MOVABLE_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
new file mode 100644
index 0000000000..ab95a9552c
--- /dev/null
+++ b/src/libs/3rdparty/syntax-highlighting/src/lib/definition_p.h
@@ -0,0 +1,111 @@
+/*
+ Copyright (C) 2016 Volker Krause <vkrause@kde.org>
+
+ Permission is hereby granted, free of charge, to any person obtaining
+ a copy of this software and associated documentation files (the
+ "Software"), to deal in the Software without restriction, including
+ without limitation the rights to use, copy, modify, merge, publish,
+ distribute, sublicense, and/or sell copies of the Software, and to
+ permit persons to whom the Software is furnished to do so, subject to
+ the following conditions:
+
+ The above copyright notice and this permission notice shall be included
+ in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+#ifndef KSYNTAXHIGHLIGHTING_DEFINITION_P_H
+#define KSYNTAXHIGHLIGHTING_DEFINITION_P_H
+
+#include "definitionref_p.h"
+#include "definition.h"
+
+#include <QHash>
+#include <QString>
+#include <QVector>
+
+QT_BEGIN_NAMESPACE
+class QXmlStreamReader;
+class QJsonObject;
+QT_END_NAMESPACE
+
+namespace KSyntaxHighlighting {
+
+class Repository;
+
+class DefinitionData
+{
+public:
+ DefinitionData();
+ ~DefinitionData();
+
+ static DefinitionData* get(const Definition &def);
+
+ bool isLoaded() const;
+ bool loadMetaData(const QString &definitionFileName);
+ bool loadMetaData(const QString &fileName, const QJsonObject &obj);
+
+ void clear();
+
+ bool load();
+ bool loadLanguage(QXmlStreamReader &reader);
+ void loadHighlighting(QXmlStreamReader &reader);
+ void loadContexts(QXmlStreamReader &reader);
+ void loadItemData(QXmlStreamReader &reader);
+ void loadGeneral(QXmlStreamReader &reader);
+ void loadComments(QXmlStreamReader &reader);
+ void loadFoldingIgnoreList(QXmlStreamReader &reader);
+ void loadSpellchecking(QXmlStreamReader &reader);
+ bool checkKateVersion(const QStringRef &verStr);
+
+ KeywordList *keywordList(const QString &name);
+ bool isWordDelimiter(QChar c) const;
+
+ Context* initialContext() const;
+ Context* contextByName(const QString &name) const;
+
+ Format formatByName(const QString &name) const;
+
+ quint16 foldingRegionId(const QString &foldName);
+
+ DefinitionRef q;
+
+ Repository *repo = nullptr;
+ QHash<QString, KeywordList> keywordLists;
+ QVector<Context*> contexts;
+ QHash<QString, Format> formats;
+ QString wordDelimiters;
+ QString wordWrapDelimiters;
+ bool hasFoldingRegions = false;
+ bool indentationBasedFolding = false;
+ QStringList foldingIgnoreList;
+ QString singleLineCommentMarker;
+ CommentPosition singleLineCommentPosition = CommentPosition::StartOfLine;
+ QString multiLineCommentStartMarker;
+ QString multiLineCommentEndMarker;
+ QVector<QPair<QChar, QString>> characterEncodings;
+
+ QString fileName;
+ QString name = QStringLiteral(QT_TRANSLATE_NOOP("Syntax highlighting", "None"));
+ QString section;
+ QString style;
+ QString indenter;
+ QString author;
+ QString license;
+ QVector<QString> mimetypes;
+ QVector<QString> extensions;
+ Qt::CaseSensitivity caseSensitive = Qt::CaseSensitive;
+ int version = 0;
+ int priority = 0;
+ bool hidden = false;
+};
+}
+
+#endif
diff --git a/src/libs/3rdparty/syntax-highlighting/src/lib/definitiondownloader.cpp b/src/libs/3rdparty/syntax-highlighting/src/lib/definitiondownloader.cpp
new file mode 100644
index 0000000000..4c3e5f5f1e
--- /dev/null
+++ b/src/libs/3rdparty/syntax-highlighting/src/lib/definitiondownloader.cpp
@@ -0,0 +1,193 @@
+/*
+ Copyright (C) 2016 Volker Krause <vkrause@kde.org>
+
+ Permission is hereby granted, free of charge, to any person obtaining
+ a copy of this software and associated documentation files (the
+ "Software"), to deal in the Software without restriction, including
+ without limitation the rights to use, copy, modify, merge, publish,
+ distribute, sublicense, and/or sell copies of the Software, and to
+ permit persons to whom the Software is furnished to do so, subject to
+ the following conditions:
+
+ The above copyright notice and this permission notice shall be included
+ in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+#include "definitiondownloader.h"
+#include "definition.h"
+#include "repository.h"
+#include "ksyntaxhighlighting_logging.h"
+#include "ksyntaxhighlighting_version.h"
+
+#include <QDebug>
+#include <QDir>
+#include <QFile>
+#include <QNetworkAccessManager>
+#include <QNetworkReply>
+#include <QNetworkRequest>
+#include <QStandardPaths>
+#include <QTimer>
+#include <QXmlStreamReader>
+
+using namespace KSyntaxHighlighting;
+
+class KSyntaxHighlighting::DefinitionDownloaderPrivate
+{
+public:
+ DefinitionDownloader *q;
+ Repository *repo;
+ QNetworkAccessManager *nam;
+ QString downloadLocation;
+ int pendingDownloads;
+ bool needsReload;
+
+ void definitionListDownloadFinished(QNetworkReply *reply);
+ void updateDefinition(QXmlStreamReader &parser);
+ void downloadDefinition(const QUrl &url);
+ void downloadDefinitionFinished(QNetworkReply *reply);
+ void checkDone();
+};
+
+void DefinitionDownloaderPrivate::definitionListDownloadFinished(QNetworkReply *reply)
+{
+ if (reply->error() != QNetworkReply::NoError) {
+ qCWarning(Log) << reply->error();
+ emit q->done(); // TODO return error
+ return;
+ }
+
+ QXmlStreamReader parser(reply);
+ while (!parser.atEnd()) {
+ switch (parser.readNext()) {
+ case QXmlStreamReader::StartElement:
+ if (parser.name() == QLatin1String("Definition"))
+ updateDefinition(parser);
+ break;
+ default:
+ break;
+ }
+ }
+
+ if (pendingDownloads == 0)
+ emit q->informationMessage(QObject::tr("All syntax definitions are up-to-date."));
+ checkDone();
+}
+
+void DefinitionDownloaderPrivate::updateDefinition(QXmlStreamReader &parser)
+{
+ const auto name = parser.attributes().value(QLatin1String("name"));
+ if (name.isEmpty())
+ return;
+
+ auto localDef = repo->definitionForName(name.toString());
+ if (!localDef.isValid()) {
+ emit q->informationMessage(QObject::tr("Downloading new syntax definition for '%1'...").arg(name.toString()));
+ downloadDefinition(QUrl(parser.attributes().value(QLatin1String("url")).toString()));
+ return;
+ }
+
+ const auto version = parser.attributes().value(QLatin1String("version"));
+ if (localDef.version() < version.toFloat()) {
+ emit q->informationMessage(QObject::tr("Updating syntax definition for '%1' to version %2...").arg(name.toString(), version.toString()));
+ downloadDefinition(QUrl(parser.attributes().value(QLatin1String("url")).toString()));
+ }
+}
+
+void DefinitionDownloaderPrivate::downloadDefinition(const QUrl& downloadUrl)
+{
+ if (!downloadUrl.isValid())
+ return;
+ auto url = downloadUrl;
+ if (url.scheme() == QLatin1String("http"))
+ url.setScheme(QStringLiteral("https"));
+
+ QNetworkRequest req(url);
+ auto reply = nam->get(req);
+ QObject::connect(reply, &QNetworkReply::finished, q, [this, reply]() {
+ downloadDefinitionFinished(reply);
+ });
+ ++pendingDownloads;
+ needsReload = true;
+}
+
+void DefinitionDownloaderPrivate::downloadDefinitionFinished(QNetworkReply *reply)
+{
+ --pendingDownloads;
+ if (reply->error() != QNetworkReply::NoError) {
+ qCWarning(Log) << "Failed to download definition file" << reply->url() << reply->error();
+ checkDone();
+ return;
+ }
+
+ // handle redirects
+ // needs to be done manually, download server redirects to unsafe http links
+ const auto redirectUrl = reply->attribute(QNetworkRequest::RedirectionTargetAttribute).toUrl();
+ if (!redirectUrl.isEmpty()) {
+ downloadDefinition(reply->url().resolved(redirectUrl));
+ checkDone();
+ return;
+ }
+
+ QFile file(downloadLocation + QLatin1Char('/') + reply->url().fileName());
+ if (!file.open(QFile::WriteOnly)) {
+ qCWarning(Log) << "Failed to open" << file.fileName() << file.error();
+ } else {
+ file.write(reply->readAll());
+ }
+ checkDone();
+}
+
+void DefinitionDownloaderPrivate::checkDone()
+{
+ if (pendingDownloads == 0) {
+ if (needsReload)
+ repo->reload();
+
+ emit QTimer::singleShot(0, q, &DefinitionDownloader::done);
+ }
+}
+
+
+DefinitionDownloader::DefinitionDownloader(Repository *repo, QObject *parent)
+ : QObject(parent)
+ , d(new DefinitionDownloaderPrivate())
+{
+ Q_ASSERT(repo);
+
+ d->q = this;
+ d->repo = repo;
+ d->nam = new QNetworkAccessManager(this);
+ d->pendingDownloads = 0;
+ d->needsReload = false;
+
+ d->downloadLocation = QStandardPaths::writableLocation(QStandardPaths::GenericDataLocation) + QStringLiteral("/org.kde.syntax-highlighting/syntax");
+ QDir().mkpath(d->downloadLocation);
+ Q_ASSERT(QFile::exists(d->downloadLocation));
+}
+
+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");
+ auto req = QNetworkRequest(QUrl(url));
+ req.setAttribute(QNetworkRequest::FollowRedirectsAttribute, true);
+ auto reply = d->nam->get(req);
+ QObject::connect(reply, &QNetworkReply::finished, this, [=]() {
+ d->definitionListDownloadFinished(reply);
+ });
+}
diff --git a/src/libs/3rdparty/syntax-highlighting/src/lib/definitiondownloader.h b/src/libs/3rdparty/syntax-highlighting/src/lib/definitiondownloader.h
new file mode 100644
index 0000000000..06e28f6a65
--- /dev/null
+++ b/src/libs/3rdparty/syntax-highlighting/src/lib/definitiondownloader.h
@@ -0,0 +1,113 @@
+/*
+ Copyright (C) 2016 Volker Krause <vkrause@kde.org>
+
+ Permission is hereby granted, free of charge, to any person obtaining
+ a copy of this software and associated documentation files (the
+ "Software"), to deal in the Software without restriction, including
+ without limitation the rights to use, copy, modify, merge, publish,
+ distribute, sublicense, and/or sell copies of the Software, and to
+ permit persons to whom the Software is furnished to do so, subject to
+ the following conditions:
+
+ The above copyright notice and this permission notice shall be included
+ in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+#ifndef KSYNTAXHIGHLIGHTING_DEFINITIONDOWNLOADER_H
+#define KSYNTAXHIGHLIGHTING_DEFINITIONDOWNLOADER_H
+
+#include "ksyntaxhighlighting_export.h"
+
+#include <QObject>
+#include <memory>
+
+namespace KSyntaxHighlighting {
+
+class DefinitionDownloaderPrivate;
+class Repository;
+
+/**
+ * Helper class to download definition file updates.
+ *
+ * With the DefinitionDownloader you can download new and update existing
+ * syntax highlighting definition files (xml files).
+ *
+ * An example that updates the highlighting Definition%s and prints the current
+ * update progress to the console may look as follows:
+ *
+ * @code
+ * auto downloader = new DefinitionDownloader(repo); // repo is a pointer to a Repository
+ *
+ * // print update progress to console
+ * QObject::connect(downloader, &DefinitionDownloader::informationMessage, [](const QString &msg) {
+ * std::cout << qPrintable(msg) << std::endl;
+ * });
+ *
+ * // connect to signal done to delete the downloader later
+ * QObject::connect(downloader, &DefinitionDownloader::done,
+ * downloader, &DefinitionDownloader::deleteLater);
+ * downloader->start();
+ * @endcode
+ *
+ * @see Repository, Definition
+ * @since 5.28
+ */
+class KSYNTAXHIGHLIGHTING_EXPORT DefinitionDownloader : public QObject
+{
+ Q_OBJECT
+public:
+ /**
+ * Constructor.
+ * The Repository @p repo is used as reference to compare the versions of
+ * the existing Definition%s with the ones that are available online.
+ *
+ * Optionally, @p parent is a pointer to the owner of this instance.
+ */
+ explicit DefinitionDownloader(Repository *repo, QObject *parent = nullptr);
+
+ /**
+ * Destructor.
+ */
+ ~DefinitionDownloader();
+
+ /**
+ * Starts the update procedure.
+ * Once no more updates are available (i.e. either the local definition files
+ * are up-to-date, or all updates have been downloaded), the signal done()
+ * is emitted.
+ *
+ * During the update process, the signal informationMessage() can be used
+ * to display the current update progress to the user.
+ *
+ * @see done(), informationMessage()
+ */
+ void start();
+
+Q_SIGNALS:
+ /**
+ * Prints the information about the current state of the definition files.
+ * If all files are up-to-date, this signal is emitted informing you that
+ * all highlighting files are up-to-date. If there are updates, this signal
+ * is emitted for each update being downloaded.
+ */
+ void informationMessage(const QString &msg);
+
+ /**
+ * This signal is emitted when there are no pending downloads anymore.
+ */
+ void done();
+
+private:
+ std::unique_ptr<DefinitionDownloaderPrivate> d;
+};
+}
+
+#endif // KSYNTAXHIGHLIGHTING_DEFINITIONDOWNLOADER_H
diff --git a/src/libs/3rdparty/syntax-highlighting/src/lib/definitionref_p.h b/src/libs/3rdparty/syntax-highlighting/src/lib/definitionref_p.h
new file mode 100644
index 0000000000..08604a4821
--- /dev/null
+++ b/src/libs/3rdparty/syntax-highlighting/src/lib/definitionref_p.h
@@ -0,0 +1,74 @@
+/*
+ Copyright (C) 2016 Volker Krause <vkrause@kde.org>
+
+ Permission is hereby granted, free of charge, to any person obtaining
+ a copy of this software and associated documentation files (the
+ "Software"), to deal in the Software without restriction, including
+ without limitation the rights to use, copy, modify, merge, publish,
+ distribute, sublicense, and/or sell copies of the Software, and to
+ permit persons to whom the Software is furnished to do so, subject to
+ the following conditions:
+
+ The above copyright notice and this permission notice shall be included
+ in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+#ifndef KSYNTAXHIGHLIGHTING_DEFINITIONREF_P_H
+#define KSYNTAXHIGHLIGHTING_DEFINITIONREF_P_H
+
+#include <memory>
+
+namespace KSyntaxHighlighting {
+
+class Definition;
+class DefinitionData;
+class DefinitionPrivate;
+
+/** Weak reference for Definition instances.
+ *
+ * This must be used when holding Definition instances
+ * in objects hold directly or indirectly by Definition
+ * to avoid reference count loops and thus memory leaks.
+ *
+ * @internal
+ */
+class DefinitionRef
+{
+public:
+ DefinitionRef();
+ explicit DefinitionRef(const Definition &def);
+ ~DefinitionRef();
+ DefinitionRef& operator=(const Definition &def);
+
+ Definition definition() const;
+
+ /**
+ * Checks two definition references for equality.
+ */
+ bool operator==(const DefinitionRef &other) const;
+
+ /**
+ * Checks two definition references for inequality.
+ */
+ bool operator!=(const DefinitionRef &other) const
+ {
+ return !(*this == other);
+ }
+
+private:
+ friend class DefinitionData;
+ std::weak_ptr<DefinitionData> d;
+};
+
+}
+
+#endif
+
diff --git a/src/libs/3rdparty/syntax-highlighting/src/lib/foldingregion.cpp b/src/libs/3rdparty/syntax-highlighting/src/lib/foldingregion.cpp
new file mode 100644
index 0000000000..e8f89bd788
--- /dev/null
+++ b/src/libs/3rdparty/syntax-highlighting/src/lib/foldingregion.cpp
@@ -0,0 +1,60 @@
+/*
+ Copyright (C) 2016 Volker Krause <vkrause@kde.org>
+
+ Permission is hereby granted, free of charge, to any person obtaining
+ a copy of this software and associated documentation files (the
+ "Software"), to deal in the Software without restriction, including
+ without limitation the rights to use, copy, modify, merge, publish,
+ distribute, sublicense, and/or sell copies of the Software, and to
+ permit persons to whom the Software is furnished to do so, subject to
+ the following conditions:
+
+ The above copyright notice and this permission notice shall be included
+ in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+#include "foldingregion.h"
+
+using namespace KSyntaxHighlighting;
+
+static_assert(sizeof(FoldingRegion) == 2, "FoldingRegion is size-sensitive to frequent use in KTextEditor!");
+
+FoldingRegion::FoldingRegion() :
+ m_type(None),
+ m_id(0)
+{
+}
+
+FoldingRegion::FoldingRegion(Type type, quint16 id) :
+ m_type(type),
+ m_id(id)
+{
+}
+
+bool FoldingRegion::operator==(const FoldingRegion &other) const
+{
+ return m_id == other.m_id && m_type == other.m_type;
+}
+
+bool FoldingRegion::isValid() const
+{
+ return type() != None;
+}
+
+quint16 FoldingRegion::id() const
+{
+ return m_id;
+}
+
+FoldingRegion::Type FoldingRegion::type() const
+{
+ return static_cast<FoldingRegion::Type>(m_type);
+}
diff --git a/src/libs/3rdparty/syntax-highlighting/src/lib/foldingregion.h b/src/libs/3rdparty/syntax-highlighting/src/lib/foldingregion.h
new file mode 100644
index 0000000000..074b9478be
--- /dev/null
+++ b/src/libs/3rdparty/syntax-highlighting/src/lib/foldingregion.h
@@ -0,0 +1,108 @@
+/*
+ Copyright (C) 2016 Volker Krause <vkrause@kde.org>
+
+ Permission is hereby granted, free of charge, to any person obtaining
+ a copy of this software and associated documentation files (the
+ "Software"), to deal in the Software without restriction, including
+ without limitation the rights to use, copy, modify, merge, publish,
+ distribute, sublicense, and/or sell copies of the Software, and to
+ permit persons to whom the Software is furnished to do so, subject to
+ the following conditions:
+
+ The above copyright notice and this permission notice shall be included
+ in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+#ifndef KSYNTAXHIGHLIGHTING_FOLDINGREGION_H
+#define KSYNTAXHIGHLIGHTING_FOLDINGREGION_H
+
+#include "ksyntaxhighlighting_export.h"
+
+#include <QTypeInfo>
+
+namespace KSyntaxHighlighting {
+
+/** Represents a begin or end of a folding region.
+ * @since 5.28 */
+class KSYNTAXHIGHLIGHTING_EXPORT FoldingRegion
+{
+public:
+ /**
+ * Defines whether a FoldingRegion starts or ends a folding region.
+ */
+ enum Type {
+ //! Used internally as indicator for invalid FoldingRegion%s.
+ None,
+ //! Indicates the start of a FoldingRegion.
+ Begin,
+ //! Indicates the end of a FoldingRegion.
+ End
+ };
+
+ /**
+ * Constructs an invalid folding region, meaning that isValid() returns @e false.
+ * To obtain valid instances, see AbstractHighlighter::applyFolding().
+ */
+ FoldingRegion();
+
+ /** Compares two FoldingRegion instances for equality. */
+ bool operator==(const FoldingRegion &other) const;
+
+ /**
+ * Returns @c true if this is a valid folding region.
+ * A valid FoldingRegion is defined by a type() other than Type::None.
+ *
+ * @note The FoldingRegion%s passed in AbstractHighlighter::applyFolding()
+ * are always valid.
+ */
+ bool isValid() const;
+
+ /**
+ * Returns a unique identifier for this folding region.
+ *
+ * As example, the C/C++ highlighter starts and ends a folding region for
+ * scopes, e.g.:
+ * \code
+ * void foo() { // '{' starts a folding region
+ * if (bar()) { // '{' starts a (nested) folding region
+ * } // '}' ends the (nested) folding region
+ * } // '}' ends the outer folding region
+ * \endcode
+ * In this example, all braces '{' and '}' have the same id(), meaning that
+ * if you want to find the matching closing region for the first opening
+ * brace, you need to do kind of a reference counting to find the correct
+ * closing brace.
+ */
+ quint16 id() const;
+
+ /**
+ * Returns whether this is the begin or end of a region.
+ *
+ * @note The FoldingRegion%s passed in AbstractHighlighter::applyFolding()
+ * are always valid, i.e. either Type::Begin or Type::End.
+ */
+ Type type() const;
+
+private:
+ friend class Rule;
+ FoldingRegion(Type type, quint16 id);
+
+ quint16 m_type : 2;
+ quint16 m_id: 14;
+};
+
+}
+
+QT_BEGIN_NAMESPACE
+Q_DECLARE_TYPEINFO(KSyntaxHighlighting::FoldingRegion, Q_PRIMITIVE_TYPE);
+QT_END_NAMESPACE
+
+#endif
diff --git a/src/libs/3rdparty/syntax-highlighting/src/lib/format.cpp b/src/libs/3rdparty/syntax-highlighting/src/lib/format.cpp
new file mode 100644
index 0000000000..397da6d700
--- /dev/null
+++ b/src/libs/3rdparty/syntax-highlighting/src/lib/format.cpp
@@ -0,0 +1,264 @@
+/*
+ Copyright (C) 2016 Volker Krause <vkrause@kde.org>
+
+ Permission is hereby granted, free of charge, to any person obtaining
+ a copy of this software and associated documentation files (the
+ "Software"), to deal in the Software without restriction, including
+ without limitation the rights to use, copy, modify, merge, publish,
+ distribute, sublicense, and/or sell copies of the Software, and to
+ permit persons to whom the Software is furnished to do so, subject to
+ the following conditions:
+
+ The above copyright notice and this permission notice shall be included
+ in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+#include "format.h"
+#include "format_p.h"
+#include "definition.h"
+#include "definitionref_p.h"
+#include "textstyledata_p.h"
+#include "themedata_p.h"
+#include "xml_p.h"
+
+#include <QColor>
+#include <QDebug>
+#include <QMetaEnum>
+#include <QXmlStreamReader>
+
+using namespace KSyntaxHighlighting;
+
+static Theme::TextStyle stringToDefaultFormat(const QStringRef &str)
+{
+ if (!str.startsWith(QLatin1String("ds")))
+ return Theme::Normal;
+
+ static const auto idx = Theme::staticMetaObject.indexOfEnumerator("TextStyle");
+ Q_ASSERT(idx >= 0);
+ const auto metaEnum = Theme::staticMetaObject.enumerator(idx);
+
+ bool ok = false;
+ const auto value = metaEnum.keyToValue(str.mid(2).toLatin1().constData(), &ok);
+ if (!ok || value < 0)
+ return Theme::Normal;
+ return static_cast<Theme::TextStyle>(value);
+}
+
+FormatPrivate* FormatPrivate::detachAndGet(Format &format)
+{
+ format.d.detach();
+ return format.d.data();
+}
+
+TextStyleData FormatPrivate::styleOverride(const Theme &theme) const
+{
+ const auto themeData = ThemeData::get(theme);
+ if (themeData)
+ return themeData->textStyleOverride(definition.definition().name(), name);
+ return TextStyleData();
+}
+
+static QExplicitlySharedDataPointer<FormatPrivate> &sharedDefaultPrivate()
+{
+ static QExplicitlySharedDataPointer<FormatPrivate> def(new FormatPrivate);
+ return def;
+}
+
+Format::Format() : d(sharedDefaultPrivate())
+{
+}
+
+Format::Format(const Format &other) :
+ d(other.d)
+{
+}
+
+Format::~Format()
+{
+}
+
+Format& Format::operator=(const Format& other)
+{
+ d = other.d;
+ return *this;
+}
+
+bool Format::isValid() const
+{
+ return !d->name.isEmpty();
+}
+
+QString Format::name() const
+{
+ return d->name;
+}
+
+quint16 Format::id() const
+{
+ return d->id;
+}
+
+Theme::TextStyle Format::textStyle() const
+{
+ return d->defaultStyle;
+}
+
+bool Format::isDefaultTextStyle(const Theme &theme) const
+{
+ return (!hasTextColor(theme))
+ && (!hasBackgroundColor(theme))
+ && (selectedTextColor(theme) == theme.selectedTextColor(Theme::Normal))
+ && (selectedBackgroundColor(theme) == theme.selectedBackgroundColor(Theme::Normal))
+ && (isBold(theme) == theme.isBold(Theme::Normal))
+ && (isItalic(theme) == theme.isItalic(Theme::Normal))
+ && (isUnderline(theme) == theme.isUnderline(Theme::Normal))
+ && (isStrikeThrough(theme) == theme.isStrikeThrough(Theme::Normal));
+}
+
+bool Format::hasTextColor(const Theme &theme) const
+{
+ const auto overrideStyle = d->styleOverride(theme);
+ return textColor(theme) != theme.textColor(Theme::Normal)
+ && (d->style.textColor || theme.textColor(d->defaultStyle) || overrideStyle.textColor);
+}
+
+QColor Format::textColor(const Theme &theme) const
+{
+ const auto overrideStyle = d->styleOverride(theme);
+ if (overrideStyle.textColor)
+ return overrideStyle.textColor;
+ return d->style.textColor ? d->style.textColor : theme.textColor(d->defaultStyle);
+}
+
+QColor Format::selectedTextColor(const Theme &theme) const
+{
+ const auto overrideStyle = d->styleOverride(theme);
+ if (overrideStyle.selectedTextColor)
+ return overrideStyle.selectedTextColor;
+ return d->style.selectedTextColor ? d->style.selectedTextColor : theme.selectedTextColor(d->defaultStyle);
+}
+
+bool Format::hasBackgroundColor(const Theme &theme) const
+{
+ const auto overrideStyle = d->styleOverride(theme);
+ return backgroundColor(theme) != theme.backgroundColor(Theme::Normal)
+ && (d->style.backgroundColor || theme.backgroundColor(d->defaultStyle) || overrideStyle.backgroundColor);
+}
+
+QColor Format::backgroundColor(const Theme &theme) const
+{
+ const auto overrideStyle = d->styleOverride(theme);
+ if (overrideStyle.backgroundColor)
+ return overrideStyle.backgroundColor;
+ return d->style.backgroundColor ? d->style.backgroundColor : theme.backgroundColor(d->defaultStyle);
+}
+
+QColor Format::selectedBackgroundColor(const Theme &theme) const
+{
+ const auto overrideStyle = d->styleOverride(theme);
+ if (overrideStyle.selectedBackgroundColor)
+ return overrideStyle.selectedBackgroundColor;
+ return d->style.selectedBackgroundColor ? d->style.selectedBackgroundColor
+ : theme.selectedBackgroundColor(d->defaultStyle);
+}
+
+bool Format::isBold(const Theme &theme) const
+{
+ const auto overrideStyle = d->styleOverride(theme);
+ if (overrideStyle.hasBold)
+ return overrideStyle.bold;
+ return d->style.hasBold ? d->style.bold : theme.isBold(d->defaultStyle);
+}
+
+bool Format::isItalic(const Theme &theme) const
+{
+ const auto overrideStyle = d->styleOverride(theme);
+ if (overrideStyle.hasItalic)
+ return overrideStyle.italic;
+ return d->style.hasItalic ? d->style.italic : theme.isItalic(d->defaultStyle);
+}
+
+bool Format::isUnderline(const Theme &theme) const
+{
+ const auto overrideStyle = d->styleOverride(theme);
+ if (overrideStyle.hasUnderline)
+ return overrideStyle.underline;
+ return d->style.hasUnderline ? d->style.underline : theme.isUnderline(d->defaultStyle);
+}
+
+bool Format::isStrikeThrough(const Theme &theme) const
+{
+ const auto overrideStyle = d->styleOverride(theme);
+ if (overrideStyle.hasStrikeThrough)
+ return overrideStyle.strikeThrough;
+ return d->style.hasStrikeThrough ? d->style.strikeThrough : theme.isStrikeThrough(d->defaultStyle);
+}
+
+bool Format::spellCheck() const
+{
+ return d->spellCheck;
+}
+
+
+void FormatPrivate::load(QXmlStreamReader& reader)
+{
+ name = reader.attributes().value(QStringLiteral("name")).toString();
+ defaultStyle = stringToDefaultFormat(reader.attributes().value(QStringLiteral("defStyleNum")));
+
+ QStringRef ref = reader.attributes().value(QStringLiteral("color"));
+ if (!ref.isEmpty()) {
+ style.textColor = QColor(ref.toString()).rgba();
+ }
+
+ ref = reader.attributes().value(QStringLiteral("selColor"));
+ if (!ref.isEmpty()) {
+ style.selectedTextColor = QColor(ref.toString()).rgba();
+ }
+
+ ref = reader.attributes().value(QStringLiteral("backgroundColor"));
+ if (!ref.isEmpty()) {
+ style.backgroundColor = QColor(ref.toString()).rgba();
+ }
+
+ ref = reader.attributes().value(QStringLiteral("selBackgroundColor"));
+ if (!ref.isEmpty()) {
+ style.selectedBackgroundColor = QColor(ref.toString()).rgba();
+ }
+
+ ref = reader.attributes().value(QStringLiteral("italic"));
+ if (!ref.isEmpty()) {
+ style.hasItalic = true;
+ style.italic = Xml::attrToBool(ref);
+ }
+
+ ref = reader.attributes().value(QStringLiteral("bold"));
+ if (!ref.isEmpty()) {
+ style.hasBold = true;
+ style.bold = Xml::attrToBool(ref);
+ }
+
+ ref = reader.attributes().value(QStringLiteral("underline"));
+ if (!ref.isEmpty()) {
+ style.hasUnderline = true;
+ style.underline = Xml::attrToBool(ref);
+ }
+
+ ref = reader.attributes().value(QStringLiteral("strikeOut"));
+ if (!ref.isEmpty()) {
+ style.hasStrikeThrough = true;
+ style.strikeThrough = Xml::attrToBool(ref);
+ }
+
+ ref = reader.attributes().value(QStringLiteral("spellChecking"));
+ if (!ref.isEmpty()) {
+ spellCheck = Xml::attrToBool(ref);
+ }
+}
diff --git a/src/libs/3rdparty/syntax-highlighting/src/lib/format.h b/src/libs/3rdparty/syntax-highlighting/src/lib/format.h
new file mode 100644
index 0000000000..24c58e73f6
--- /dev/null
+++ b/src/libs/3rdparty/syntax-highlighting/src/lib/format.h
@@ -0,0 +1,152 @@
+/*
+ Copyright (C) 2016 Volker Krause <vkrause@kde.org>
+
+ Permission is hereby granted, free of charge, to any person obtaining
+ a copy of this software and associated documentation files (the
+ "Software"), to deal in the Software without restriction, including
+ without limitation the rights to use, copy, modify, merge, publish,
+ distribute, sublicense, and/or sell copies of the Software, and to
+ permit persons to whom the Software is furnished to do so, subject to
+ the following conditions:
+
+ The above copyright notice and this permission notice shall be included
+ in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+#ifndef KSYNTAXHIGHLIGHTING_FORMAT_H
+#define KSYNTAXHIGHLIGHTING_FORMAT_H
+
+#include "ksyntaxhighlighting_export.h"
+#include "theme.h"
+
+#include <QExplicitlySharedDataPointer>
+#include <QTypeInfo>
+
+QT_BEGIN_NAMESPACE
+class QColor;
+class QString;
+class QXmlStreamReader;
+QT_END_NAMESPACE
+
+namespace KSyntaxHighlighting {
+
+class DefinitionRef;
+class FormatPrivate;
+
+/** Describes the format to be used for a specific text fragment.
+ * The actual format used for displaying is merged from the format information
+ * in the syntax definition file, and a theme.
+ *
+ * @see Theme
+ * @since 5.28
+ */
+class KSYNTAXHIGHLIGHTING_EXPORT Format
+{
+public:
+ /** Creates an empty/invalid format. */
+ Format();
+ Format(const Format &other);
+ ~Format();
+
+ Format& operator=(const Format &other);
+
+ /** Returns @c true if this is a valid format, ie. one that
+ * was read from a syntax definition file.
+ */
+ bool isValid() const;
+
+ /** The name of this format as used in the syntax definition file. */
+ QString name() const;
+
+ /** Returns a unique identifier of this format.
+ * This is useful for efficient storing of formats in a text line. The
+ * identifier is unique per Repository instance, but will change when
+ * the repository is reloaded (which also invalidatess the corresponding
+ * Definition anyway).
+ */
+ quint16 id() const;
+
+ /** Returns the underlying TextStyle of this Format.
+ * Every Theme::TextStyle is visually defined by a Theme. A Format uses one
+ * of the Theme::TextStyle%s and on top allows modifications such as setting
+ * a different foreground color etc.
+ * @see Theme::TextStyle
+ * @since 5.49
+ */
+ Theme::TextStyle textStyle() const;
+
+ /** Returns @c true if the combination of this format and the theme @p theme
+ * do not change the default text format in any way.
+ * This is useful for output formats where changing formatting implies cost,
+ * and thus benefit from optimizing the default case of not having any format
+ * applied. If you make use of this, make sure to set the default text style
+ * to what the corresponding theme sets for Theme::Normal.
+ */
+ bool isDefaultTextStyle(const Theme &theme) const;
+
+ /** Returns @c true if the combination of this format and the theme @p theme
+ * change the foreground color compared to the default format.
+ */
+ bool hasTextColor(const Theme &theme) const;
+ /** Returns the foreground color of the combination of this format and the
+ * given theme.
+ */
+ QColor textColor(const Theme &theme) const;
+ /** Returns the foreground color for selected text of the combination of
+ * this format and the given theme.
+ */
+ QColor selectedTextColor(const Theme &theme) const;
+ /** Returns @c true if the combination of this format and the theme @p theme
+ * change the background color compared to the default format.
+ */
+ bool hasBackgroundColor(const Theme &theme) const;
+ /** Returns the background color of the combination of this format and the
+ * given theme.
+ */
+ QColor backgroundColor(const Theme &theme) const;
+ /** Returns the background color of selected text of the combination of
+ * this format and the given theme.
+ */
+ QColor selectedBackgroundColor(const Theme &theme) const;
+
+ /** Returns @c true if the combination of this format and the given theme
+ * results in bold text formatting.
+ */
+ bool isBold(const Theme &theme) const;
+ /** Returns @c true if the combination of this format and the given theme
+ * results in italic text formatting.
+ */
+ bool isItalic(const Theme &theme) const;
+ /** Returns @c true if the combination of this format and the given theme
+ * results in underlined text.
+ */
+ bool isUnderline(const Theme &theme) const;
+ /** Returns @c true if the combination of this format and the given theme
+ * results in struck through text.
+ */
+ bool isStrikeThrough(const Theme &theme) const;
+
+ /**
+ * Returns whether characters with this format should be spell checked.
+ */
+ bool spellCheck() const;
+
+private:
+ friend class FormatPrivate;
+ QExplicitlySharedDataPointer<FormatPrivate> d;
+};
+}
+
+QT_BEGIN_NAMESPACE
+Q_DECLARE_TYPEINFO(KSyntaxHighlighting::Format, Q_MOVABLE_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
new file mode 100644
index 0000000000..e79b26b6a7
--- /dev/null
+++ b/src/libs/3rdparty/syntax-highlighting/src/lib/format_p.h
@@ -0,0 +1,55 @@
+/*
+ Copyright (C) 2016 Volker Krause <vkrause@kde.org>
+
+ Permission is hereby granted, free of charge, to any person obtaining
+ a copy of this software and associated documentation files (the
+ "Software"), to deal in the Software without restriction, including
+ without limitation the rights to use, copy, modify, merge, publish,
+ distribute, sublicense, and/or sell copies of the Software, and to
+ permit persons to whom the Software is furnished to do so, subject to
+ the following conditions:
+
+ The above copyright notice and this permission notice shall be included
+ in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+#ifndef KSYNTAXHIGHLIGHTING_FORMAT_P_H
+#define KSYNTAXHIGHLIGHTING_FORMAT_P_H
+
+#include "definitionref_p.h"
+#include "textstyledata_p.h"
+#include "theme.h"
+
+#include <QSharedData>
+#include <QString>
+
+namespace KSyntaxHighlighting {
+
+class FormatPrivate : public QSharedData
+{
+public:
+ FormatPrivate() = default;
+ static FormatPrivate* detachAndGet(Format &format);
+
+ TextStyleData styleOverride(const Theme &theme) const;
+ void load(QXmlStreamReader &reader);
+
+ DefinitionRef definition;
+ QString name;
+ TextStyleData style;
+ Theme::TextStyle defaultStyle = Theme::Normal;
+ quint16 id = 0;
+ bool spellCheck = true;
+};
+
+}
+
+#endif
diff --git a/src/libs/3rdparty/syntax-highlighting/src/lib/htmlhighlighter.cpp b/src/libs/3rdparty/syntax-highlighting/src/lib/htmlhighlighter.cpp
new file mode 100644
index 0000000000..4ebd465b77
--- /dev/null
+++ b/src/libs/3rdparty/syntax-highlighting/src/lib/htmlhighlighter.cpp
@@ -0,0 +1,161 @@
+/*
+ Copyright (C) 2016 Volker Krause <vkrause@kde.org>
+ Copyright (C) 2018 Christoph Cullmann <cullmann@kde.org>
+
+ Permission is hereby granted, free of charge, to any person obtaining
+ a copy of this software and associated documentation files (the
+ "Software"), to deal in the Software without restriction, including
+ without limitation the rights to use, copy, modify, merge, publish,
+ distribute, sublicense, and/or sell copies of the Software, and to
+ permit persons to whom the Software is furnished to do so, subject to
+ the following conditions:
+
+ The above copyright notice and this permission notice shall be included
+ in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+#include "htmlhighlighter.h"
+#include "definition.h"
+#include "format.h"
+#include "state.h"
+#include "theme.h"
+#include "ksyntaxhighlighting_logging.h"
+
+#include <QDebug>
+#include <QFile>
+#include <QFileInfo>
+#include <QTextStream>
+#include <QVarLengthArray>
+
+using namespace KSyntaxHighlighting;
+
+class KSyntaxHighlighting::HtmlHighlighterPrivate
+{
+public:
+ std::unique_ptr<QTextStream> out;
+ std::unique_ptr<QFile> file;
+ QString currentLine;
+};
+
+HtmlHighlighter::HtmlHighlighter()
+ : d(new HtmlHighlighterPrivate())
+{
+}
+
+HtmlHighlighter::~HtmlHighlighter()
+{
+}
+
+void HtmlHighlighter::setOutputFile(const QString& fileName)
+{
+ 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()));
+ d->out->setCodec("UTF-8");
+}
+
+void HtmlHighlighter::setOutputFile(FILE *fileHandle)
+{
+ d->out.reset(new QTextStream(fileHandle, QIODevice::WriteOnly));
+ d->out->setCodec("UTF-8");
+}
+
+void HtmlHighlighter::highlightFile(const QString& fileName, const QString& title)
+{
+ QFileInfo fi(fileName);
+ QFile f(fileName);
+ if (!f.open(QFile::ReadOnly)) {
+ qCWarning(Log) << "Failed to open input file" << fileName << ":" << f.errorString();
+ return;
+ }
+
+ if (title.isEmpty())
+ highlightData(&f, fi.fileName());
+ else
+ highlightData(&f, title);
+}
+
+void HtmlHighlighter::highlightData(QIODevice *dev, const QString& title)
+{
+ if (!d->out) {
+ qCWarning(Log) << "No output stream defined!";
+ return;
+ }
+
+ QString htmlTitle;
+ if (title.isEmpty())
+ htmlTitle = QStringLiteral("Kate Syntax Highlighter");
+ else
+ htmlTitle = title.toHtmlEscaped();
+
+ State state;
+ *d->out << "<!DOCTYPE html>\n";
+ *d->out << "<html><head>\n";
+ *d->out << "<meta http-equiv=\"Content-Type\" content=\"text/html; charset=UTF-8\"/>\n";
+ *d->out << "<title>" << htmlTitle << "</title>\n";
+ *d->out << "<meta name=\"generator\" content=\"KF5::SyntaxHighlighting (" << definition().name() << ")\"/>\n";
+ *d->out << "</head><body";
+ if (theme().textColor(Theme::Normal))
+ *d->out << " style=\"color:" << QColor(theme().textColor(Theme::Normal)).name() << "\"";
+ *d->out << "><pre>\n";
+
+ QTextStream in(dev);
+ in.setCodec("UTF-8");
+ while (!in.atEnd()) {
+ d->currentLine = in.readLine();
+ state = highlightLine(d->currentLine, state);
+ *d->out << "\n";
+ }
+
+ *d->out << "</pre></body></html>\n";
+ d->out->flush();
+
+ d->out.reset();
+ d->file.reset();
+}
+
+void HtmlHighlighter::applyFormat(int offset, int length, const Format& format)
+{
+ if (length == 0)
+ return;
+
+ // collect potential output, cheaper than thinking about "is there any?"
+ QVarLengthArray<QString, 16> formatOutput;
+ if (format.hasTextColor(theme()))
+ formatOutput << QStringLiteral("color:") << format.textColor(theme()).name() << QStringLiteral(";");
+ if (format.hasBackgroundColor(theme()))
+ formatOutput << QStringLiteral("background-color:") << format.backgroundColor(theme()).name() << 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;");
+
+ if (!formatOutput.isEmpty()) {
+ *d->out << "<span style=\"";
+ for (const auto &out : qAsConst(formatOutput)) {
+ *d->out << out;
+ }
+ *d->out << "\">";
+ }
+
+ *d->out << d->currentLine.mid(offset, length).toHtmlEscaped();
+
+ if (!formatOutput.isEmpty()) {
+ *d->out << "</span>";
+ }
+}
diff --git a/src/libs/3rdparty/syntax-highlighting/src/lib/htmlhighlighter.h b/src/libs/3rdparty/syntax-highlighting/src/lib/htmlhighlighter.h
new file mode 100644
index 0000000000..b7eda02d54
--- /dev/null
+++ b/src/libs/3rdparty/syntax-highlighting/src/lib/htmlhighlighter.h
@@ -0,0 +1,64 @@
+/*
+ Copyright (C) 2016 Volker Krause <vkrause@kde.org>
+
+ Permission is hereby granted, free of charge, to any person obtaining
+ a copy of this software and associated documentation files (the
+ "Software"), to deal in the Software without restriction, including
+ without limitation the rights to use, copy, modify, merge, publish,
+ distribute, sublicense, and/or sell copies of the Software, and to
+ permit persons to whom the Software is furnished to do so, subject to
+ the following conditions:
+
+ The above copyright notice and this permission notice shall be included
+ in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+#ifndef KSYNTAXHIGHLIGHTING_HTMLHIGHLIGHTER_H
+#define KSYNTAXHIGHLIGHTING_HTMLHIGHLIGHTER_H
+
+#include "ksyntaxhighlighting_export.h"
+#include "abstracthighlighter.h"
+
+#include <QString>
+#include <QIODevice>
+
+#include <memory>
+
+QT_BEGIN_NAMESPACE
+class QFile;
+class QTextStream;
+QT_END_NAMESPACE
+
+namespace KSyntaxHighlighting {
+
+class HtmlHighlighterPrivate;
+
+class KSYNTAXHIGHLIGHTING_EXPORT HtmlHighlighter : public AbstractHighlighter
+{
+public:
+ HtmlHighlighter();
+ ~HtmlHighlighter() override;
+
+ void highlightFile(const QString &fileName, const QString &title = QString());
+ void highlightData(QIODevice *device, const QString &title = QString());
+
+ void setOutputFile(const QString &fileName);
+ void setOutputFile(FILE *fileHandle);
+
+protected:
+ void applyFormat(int offset, int length, const Format &format) override;
+
+private:
+ std::unique_ptr<HtmlHighlighterPrivate> d;
+};
+}
+
+#endif // KSYNTAXHIGHLIGHTING_HTMLHIGHLIGHTER_H
diff --git a/src/libs/3rdparty/syntax-highlighting/src/lib/keywordlist.cpp b/src/libs/3rdparty/syntax-highlighting/src/lib/keywordlist.cpp
new file mode 100644
index 0000000000..fe5f77586a
--- /dev/null
+++ b/src/libs/3rdparty/syntax-highlighting/src/lib/keywordlist.cpp
@@ -0,0 +1,104 @@
+/*
+ Copyright (C) 2016 Volker Krause <vkrause@kde.org>
+
+ Permission is hereby granted, free of charge, to any person obtaining
+ a copy of this software and associated documentation files (the
+ "Software"), to deal in the Software without restriction, including
+ without limitation the rights to use, copy, modify, merge, publish,
+ distribute, sublicense, and/or sell copies of the Software, and to
+ permit persons to whom the Software is furnished to do so, subject to
+ the following conditions:
+
+ The above copyright notice and this permission notice shall be included
+ in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+#include "keywordlist_p.h"
+
+#include <QDebug>
+#include <QXmlStreamReader>
+
+#include <algorithm>
+
+using namespace KSyntaxHighlighting;
+
+bool KeywordList::contains(const QStringRef &str, Qt::CaseSensitivity caseSensitive) const
+{
+ /**
+ * get right vector to search in
+ */
+ const auto &vectorToSearch = (caseSensitive == Qt::CaseSensitive) ? m_keywordsSortedCaseSensitive : m_keywordsSortedCaseInsensitive;
+
+ /**
+ * search with right predicate
+ */
+ return std::binary_search(vectorToSearch.begin(), vectorToSearch.end(), str, [caseSensitive] (const QStringRef &a, const QStringRef &b) { return a.compare(b, caseSensitive) < 0; });
+}
+
+void KeywordList::load(QXmlStreamReader& reader)
+{
+ Q_ASSERT(reader.name() == QLatin1String("list"));
+ Q_ASSERT(reader.tokenType() == QXmlStreamReader::StartElement);
+
+ m_name = reader.attributes().value(QStringLiteral("name")).toString();
+
+ while (!reader.atEnd()) {
+ switch (reader.tokenType()) {
+ case QXmlStreamReader::StartElement:
+ if (reader.name() == QLatin1String("item")) {
+ m_keywords.append(reader.readElementText().trimmed());
+ reader.readNextStartElement();
+ break;
+ }
+ reader.readNext();
+ break;
+ case QXmlStreamReader::EndElement:
+ reader.readNext();
+ return;
+ default:
+ reader.readNext();
+ break;
+ }
+ }
+}
+
+void KeywordList::setCaseSensitivity(Qt::CaseSensitivity caseSensitive)
+{
+ /**
+ * remember default case-sensitivity and init lookup for it
+ */
+ m_caseSensitive = caseSensitive;
+ initLookupForCaseSensitivity(m_caseSensitive);
+}
+
+void KeywordList::initLookupForCaseSensitivity(Qt::CaseSensitivity caseSensitive)
+{
+ /**
+ * get right vector to sort, if non-empty, we are done
+ */
+ auto &vectorToSort = (caseSensitive == Qt::CaseSensitive) ? m_keywordsSortedCaseSensitive : m_keywordsSortedCaseInsensitive;
+ if (!vectorToSort.empty()) {
+ return;
+ }
+
+ /**
+ * fill vector with refs to keywords
+ */
+ vectorToSort.reserve(m_keywords.size());
+ for (const auto &keyword : qAsConst(m_keywords)) {
+ vectorToSort.push_back(&keyword);
+ }
+
+ /**
+ * sort with right predicate
+ */
+ std::sort(vectorToSort.begin(), vectorToSort.end(), [caseSensitive] (const QStringRef &a, const QStringRef &b) { return a.compare(b, caseSensitive) < 0; });
+}
diff --git a/src/libs/3rdparty/syntax-highlighting/src/lib/keywordlist_p.h b/src/libs/3rdparty/syntax-highlighting/src/lib/keywordlist_p.h
new file mode 100644
index 0000000000..8c41aabe0c
--- /dev/null
+++ b/src/libs/3rdparty/syntax-highlighting/src/lib/keywordlist_p.h
@@ -0,0 +1,101 @@
+/*
+ Copyright (C) 2016 Volker Krause <vkrause@kde.org>
+
+ Permission is hereby granted, free of charge, to any person obtaining
+ a copy of this software and associated documentation files (the
+ "Software"), to deal in the Software without restriction, including
+ without limitation the rights to use, copy, modify, merge, publish,
+ distribute, sublicense, and/or sell copies of the Software, and to
+ permit persons to whom the Software is furnished to do so, subject to
+ the following conditions:
+
+ The above copyright notice and this permission notice shall be included
+ in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+#ifndef KSYNTAXHIGHLIGHTING_KEYWORDLIST_P_H
+#define KSYNTAXHIGHLIGHTING_KEYWORDLIST_P_H
+
+#include <QSet>
+#include <QString>
+#include <QVector>
+
+#include <vector>
+
+QT_BEGIN_NAMESPACE
+class QXmlStreamReader;
+QT_END_NAMESPACE
+
+namespace KSyntaxHighlighting {
+
+class KeywordList
+{
+public:
+ KeywordList() = default;
+ ~KeywordList() = default;
+
+ bool isEmpty() const
+ {
+ return m_keywords.isEmpty();
+ }
+
+ const QString &name() const
+ {
+ return m_name;
+ }
+
+ const QStringList &keywords() const
+ {
+ return m_keywords;
+ }
+
+ /** Checks if @p str is a keyword in this list. */
+ bool contains(const QStringRef &str) const
+ {
+ return contains(str, m_caseSensitive);
+ }
+
+ /** Checks if @p str is a keyword in this list, overriding the global case-sensitivity setting. */
+ bool contains(const QStringRef &str, Qt::CaseSensitivity caseSensitive) const;
+
+ void load(QXmlStreamReader &reader);
+ void setCaseSensitivity(Qt::CaseSensitivity caseSensitive);
+ void initLookupForCaseSensitivity(Qt::CaseSensitivity caseSensitive);
+
+private:
+ /**
+ * name of keyword list as in XML
+ */
+ QString m_name;
+
+ /**
+ * raw list of keywords, as seen in XML (but trimmed)
+ */
+ QStringList m_keywords;
+
+ /**
+ * default case-sensitivity setting
+ */
+ Qt::CaseSensitivity m_caseSensitive = Qt::CaseSensitive;
+
+ /**
+ * case-sensitive sorted string references to m_keywords for lookup
+ */
+ std::vector<QStringRef> m_keywordsSortedCaseSensitive;
+
+ /**
+ * case-insensitive sorted string references to m_keywords for lookup
+ */
+ std::vector<QStringRef> m_keywordsSortedCaseInsensitive;
+};
+}
+
+#endif // KSYNTAXHIGHLIGHTING_KEYWORDLIST_P_H
diff --git a/src/libs/3rdparty/syntax-highlighting/src/lib/ksyntaxhighlighting_export.h b/src/libs/3rdparty/syntax-highlighting/src/lib/ksyntaxhighlighting_export.h
new file mode 100644
index 0000000000..a39adb5ed6
--- /dev/null
+++ b/src/libs/3rdparty/syntax-highlighting/src/lib/ksyntaxhighlighting_export.h
@@ -0,0 +1,34 @@
+/****************************************************************************
+**
+** Copyright (C) 2018 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt Creator.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+****************************************************************************/
+
+#pragma once
+
+#include <QtGlobal>
+
+#if defined(KSYNTAXHIGHLIGHTING_LIBRARY)
+# define KSYNTAXHIGHLIGHTING_EXPORT Q_DECL_EXPORT
+#else
+# define KSYNTAXHIGHLIGHTING_EXPORT Q_DECL_IMPORT
+#endif
diff --git a/src/libs/3rdparty/syntax-highlighting/src/lib/matchresult_p.h b/src/libs/3rdparty/syntax-highlighting/src/lib/matchresult_p.h
new file mode 100644
index 0000000000..b1a05ee636
--- /dev/null
+++ b/src/libs/3rdparty/syntax-highlighting/src/lib/matchresult_p.h
@@ -0,0 +1,113 @@
+/*
+ Copyright (C) 2016 Volker Krause <vkrause@kde.org>
+
+ Permission is hereby granted, free of charge, to any person obtaining
+ a copy of this software and associated documentation files (the
+ "Software"), to deal in the Software without restriction, including
+ without limitation the rights to use, copy, modify, merge, publish,
+ distribute, sublicense, and/or sell copies of the Software, and to
+ permit persons to whom the Software is furnished to do so, subject to
+ the following conditions:
+
+ The above copyright notice and this permission notice shall be included
+ in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+#ifndef KSYNTAXHIGHLIGHTING_MATCHRESULT_P_H
+#define KSYNTAXHIGHLIGHTING_MATCHRESULT_P_H
+
+#include <QStringList>
+
+namespace KSyntaxHighlighting {
+
+/**
+ * Storage for match result of a Rule.
+ * Heavily used internally during highlightLine, therefore completely inline.
+ */
+class MatchResult
+{
+public:
+ /**
+ * Match at given offset found.
+ * @param offset offset of match
+ */
+ MatchResult(const int offset)
+ : m_offset(offset)
+ {
+ }
+
+ /**
+ * Match at given offset found with additional skip offset.
+ */
+ explicit MatchResult(const int offset, const int skipOffset)
+ : m_offset(offset)
+ , m_skipOffset(skipOffset)
+ {
+ }
+
+ /**
+ * Match at given offset found with additional captures.
+ * @param offset offset of match
+ * @param captures captures of the match
+ */
+ explicit MatchResult(const int offset, const QStringList &captures)
+ : m_offset(offset)
+ , m_captures(captures)
+ {
+ }
+
+ /**
+ * Offset of the match
+ * @return offset of the match
+ */
+ int offset() const
+ {
+ return m_offset;
+ }
+
+
+ /**
+ * Skip offset of the match
+ * @return skip offset of the match, no match possible until this offset is reached
+ */
+ int skipOffset() const
+ {
+ return m_skipOffset;
+ }
+
+ /**
+ * Captures of the match.
+ * @return captured text of this match
+ */
+ const QStringList &captures() const
+ {
+ return m_captures;
+ }
+
+private:
+ /**
+ * match offset, filled in all constructors
+ */
+ int m_offset;
+
+ /**
+ * skip offset, optional
+ */
+ int m_skipOffset = 0;
+
+ /**
+ * captures, optional
+ */
+ QStringList m_captures;
+};
+}
+
+#endif // KSYNTAXHIGHLIGHTING_MATCHRESULT_P_H
diff --git a/src/libs/3rdparty/syntax-highlighting/src/lib/repository.cpp b/src/libs/3rdparty/syntax-highlighting/src/lib/repository.cpp
new file mode 100644
index 0000000000..6b2fabd07a
--- /dev/null
+++ b/src/libs/3rdparty/syntax-highlighting/src/lib/repository.cpp
@@ -0,0 +1,325 @@
+/*
+ Copyright (C) 2016 Volker Krause <vkrause@kde.org>
+
+ Permission is hereby granted, free of charge, to any person obtaining
+ a copy of this software and associated documentation files (the
+ "Software"), to deal in the Software without restriction, including
+ without limitation the rights to use, copy, modify, merge, publish,
+ distribute, sublicense, and/or sell copies of the Software, and to
+ permit persons to whom the Software is furnished to do so, subject to
+ the following conditions:
+
+ The above copyright notice and this permission notice shall be included
+ in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+#include "repository.h"
+#include "repository_p.h"
+#include "definition.h"
+#include "definition_p.h"
+#include "theme.h"
+#include "themedata_p.h"
+#include "ksyntaxhighlighting_logging.h"
+#include "wildcardmatcher_p.h"
+
+#include <QDebug>
+#include <QDirIterator>
+#include <QFile>
+#include <QFileInfo>
+#include <QJsonDocument>
+#include <QJsonObject>
+
+#ifndef NO_STANDARD_PATHS
+#include <QStandardPaths>
+#endif
+
+#include <limits>
+
+using namespace KSyntaxHighlighting;
+
+static void initResource()
+{
+#ifdef HAS_SYNTAX_RESOURCE
+ Q_INIT_RESOURCE(syntax_data);
+#endif
+ Q_INIT_RESOURCE(theme_data);
+}
+
+RepositoryPrivate* RepositoryPrivate::get(Repository *repo)
+{
+ return repo->d.get();
+}
+
+Repository::Repository() :
+ d(new RepositoryPrivate)
+{
+ initResource();
+ d->load(this);
+}
+
+Repository::~Repository()
+{
+ // reset repo so we can detect in still alive definition instances
+ // that the repo was deleted
+ foreach (const auto &def, d->m_sortedDefs)
+ DefinitionData::get(def)->repo = nullptr;
+}
+
+Definition Repository::definitionForName(const QString& defName) const
+{
+ return d->m_defs.value(defName);
+}
+
+static Definition bestCandidate(QVector<Definition>& candidates)
+{
+ if (candidates.isEmpty())
+ return Definition();
+
+ std::partial_sort(candidates.begin(), candidates.begin() + 1, candidates.end(), [](const Definition &lhs, const Definition &rhs) {
+ return lhs.priority() > rhs.priority();
+ });
+
+ return candidates.at(0);
+}
+
+Definition Repository::definitionForFileName(const QString& fileName) const
+{
+ QFileInfo fi(fileName);
+ const auto name = fi.fileName();
+
+ QVector<Definition> candidates;
+ for (auto it = d->m_defs.constBegin(); it != d->m_defs.constEnd(); ++it) {
+ auto def = it.value();
+ foreach (const auto &pattern, def.extensions()) {
+ if (WildcardMatcher::exactMatch(name, pattern)) {
+ candidates.push_back(def);
+ break;
+ }
+ }
+ }
+
+ return bestCandidate(candidates);
+}
+
+Definition Repository::definitionForMimeType(const QString& mimeType) const
+{
+ QVector<Definition> candidates;
+ for (auto it = d->m_defs.constBegin(); it != d->m_defs.constEnd(); ++it) {
+ auto def = it.value();
+ foreach (const auto &matchType, def.mimeTypes()) {
+ if (mimeType == matchType) {
+ candidates.push_back(def);
+ break;
+ }
+ }
+ }
+
+ return bestCandidate(candidates);
+}
+
+QVector<Definition> Repository::definitions() const
+{
+ return d->m_sortedDefs;
+}
+
+QVector<Theme> Repository::themes() const
+{
+ return d->m_themes;
+}
+
+Theme Repository::theme(const QString &themeName) const
+{
+ for (const auto &theme : qAsConst(d->m_themes)) {
+ if (theme.name() == themeName) {
+ return theme;
+ }
+ }
+
+ return Theme();
+}
+
+Theme Repository::defaultTheme(Repository::DefaultTheme t)
+{
+ if (t == DarkTheme)
+ return theme(QLatin1String("Breeze Dark"));
+ return theme(QLatin1String("Default"));
+}
+
+void RepositoryPrivate::load(Repository *repo)
+{
+ // always add invalid default "None" highlighting
+ addDefinition(Definition());
+
+ // do lookup in standard paths, if not disabled
+#ifndef NO_STANDARD_PATHS
+ foreach (const auto &dir, QStandardPaths::locateAll(QStandardPaths::GenericDataLocation, QStringLiteral("org.kde.syntax-highlighting/syntax"), QStandardPaths::LocateDirectory))
+ loadSyntaxFolder(repo, dir);
+
+ // backward compatibility with Kate
+ foreach (const auto &dir, QStandardPaths::locateAll(QStandardPaths::GenericDataLocation, QStringLiteral("katepart5/syntax"), QStandardPaths::LocateDirectory))
+ loadSyntaxFolder(repo, dir);
+#endif
+
+ // default resources are always used
+ loadSyntaxFolder(repo, QStringLiteral(":/org.kde.syntax-highlighting/syntax"));
+
+ // user given extra paths
+ foreach (const auto &path, m_customSearchPaths)
+ loadSyntaxFolder(repo, path + QStringLiteral("/syntax"));
+
+ m_sortedDefs.reserve(m_defs.size());
+ for (auto it = m_defs.constBegin(); it != m_defs.constEnd(); ++it)
+ m_sortedDefs.push_back(it.value());
+ std::sort(m_sortedDefs.begin(), m_sortedDefs.end(), [](const Definition &left, const Definition &right) {
+ auto comparison = left.translatedSection().compare(right.translatedSection(), Qt::CaseInsensitive);
+ if (comparison == 0)
+ comparison = left.translatedName().compare(right.translatedName(), Qt::CaseInsensitive);
+ return comparison < 0;
+ });
+
+ // load themes
+
+ // do lookup in standard paths, if not disabled
+#ifndef NO_STANDARD_PATHS
+ foreach (const auto &dir, QStandardPaths::locateAll(QStandardPaths::GenericDataLocation, QStringLiteral("org.kde.syntax-highlighting/themes"), QStandardPaths::LocateDirectory))
+ loadThemeFolder(dir);
+#endif
+
+ // default resources are always used
+ loadThemeFolder(QStringLiteral(":/org.kde.syntax-highlighting/themes"));
+
+ // user given extra paths
+ foreach (const auto &path, m_customSearchPaths)
+ loadThemeFolder(path + QStringLiteral("/themes"));
+}
+
+void RepositoryPrivate::loadSyntaxFolder(Repository *repo, const QString &path)
+{
+ if (loadSyntaxFolderFromIndex(repo, path))
+ return;
+
+ QDirIterator it(path, QStringList() << QLatin1String("*.xml"), QDir::Files);
+ while (it.hasNext()) {
+ Definition def;
+ auto defData = DefinitionData::get(def);
+ defData->repo = repo;
+ if (defData->loadMetaData(it.next()))
+ addDefinition(def);
+ }
+}
+
+bool RepositoryPrivate::loadSyntaxFolderFromIndex(Repository *repo, const QString &path)
+{
+ QFile indexFile(path + QLatin1String("/index.katesyntax"));
+ if (!indexFile.open(QFile::ReadOnly))
+ return false;
+
+ const auto indexDoc(QJsonDocument::fromBinaryData(indexFile.readAll()));
+ const auto index = indexDoc.object();
+ for (auto it = index.begin(); it != index.end(); ++it) {
+ if (!it.value().isObject())
+ continue;
+ const auto fileName = QString(path + QLatin1Char('/') + it.key());
+ const auto defMap = it.value().toObject();
+ Definition def;
+ auto defData = DefinitionData::get(def);
+ defData->repo = repo;
+ if (defData->loadMetaData(fileName, defMap))
+ addDefinition(def);
+ }
+ return true;
+}
+
+void RepositoryPrivate::addDefinition(const Definition &def)
+{
+ const auto it = m_defs.constFind(def.name());
+ if (it == m_defs.constEnd()) {
+ m_defs.insert(def.name(), def);
+ return;
+ }
+
+ if (it.value().version() >= def.version())
+ return;
+ m_defs.insert(def.name(), def);
+}
+
+void RepositoryPrivate::loadThemeFolder(const QString &path)
+{
+ QDirIterator it(path, QStringList() << QLatin1String("*.theme"), QDir::Files);
+ while (it.hasNext()) {
+ auto themeData = std::unique_ptr<ThemeData>(new ThemeData);
+ if (themeData->load(it.next()))
+ addTheme(Theme(themeData.release()));
+ }
+}
+
+static int themeRevision(const Theme &theme)
+{
+ auto data = ThemeData::get(theme);
+ return data->revision();
+}
+
+void RepositoryPrivate::addTheme(const Theme &theme)
+{
+ const auto it = std::lower_bound(m_themes.begin(), m_themes.end(), theme, [](const Theme &lhs, const Theme &rhs) {
+ return lhs.name() < rhs.name();
+ });
+ if (it == m_themes.end() || (*it).name() != theme.name()) {
+ m_themes.insert(it, theme);
+ return;
+ }
+ if (themeRevision(*it) < themeRevision(theme))
+ *it = theme;
+}
+
+quint16 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();
+ m_foldingRegionIds.insert(qMakePair(defName, foldName), ++m_foldingRegionId);
+ return m_foldingRegionId;
+}
+
+quint16 RepositoryPrivate::nextFormatId()
+{
+ Q_ASSERT(m_formatId < std::numeric_limits<quint16>::max());
+ return ++m_formatId;
+}
+
+void Repository::reload()
+{
+ qCDebug(Log) << "Reloading syntax definitions!";
+ foreach (const auto &def, d->m_sortedDefs)
+ DefinitionData::get(def)->clear();
+ d->m_defs.clear();
+ d->m_sortedDefs.clear();
+
+ d->m_themes.clear();
+
+ d->m_foldingRegionId = 0;
+ d->m_foldingRegionIds.clear();
+
+ d->m_formatId = 0;
+
+ d->load(this);
+}
+
+void Repository::addCustomSearchPath(const QString &path)
+{
+ d->m_customSearchPaths.append(path);
+ reload();
+}
+
+QVector<QString> Repository::customSearchPaths() const
+{
+ return d->m_customSearchPaths;
+}
diff --git a/src/libs/3rdparty/syntax-highlighting/src/lib/repository.h b/src/libs/3rdparty/syntax-highlighting/src/lib/repository.h
new file mode 100644
index 0000000000..c35da5ec37
--- /dev/null
+++ b/src/libs/3rdparty/syntax-highlighting/src/lib/repository.h
@@ -0,0 +1,257 @@
+/*
+ Copyright (C) 2016 Volker Krause <vkrause@kde.org>
+
+ Permission is hereby granted, free of charge, to any person obtaining
+ a copy of this software and associated documentation files (the
+ "Software"), to deal in the Software without restriction, including
+ without limitation the rights to use, copy, modify, merge, publish,
+ distribute, sublicense, and/or sell copies of the Software, and to
+ permit persons to whom the Software is furnished to do so, subject to
+ the following conditions:
+
+ The above copyright notice and this permission notice shall be included
+ in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+#ifndef KSYNTAXHIGHLIGHTING_REPOSITORY_H
+#define KSYNTAXHIGHLIGHTING_REPOSITORY_H
+
+#include "ksyntaxhighlighting_export.h"
+
+#include <qglobal.h>
+#include <memory>
+
+QT_BEGIN_NAMESPACE
+class QString;
+template <typename T> class QVector;
+QT_END_NAMESPACE
+
+/**
+ * @namespace KSyntaxHighlighting
+ *
+ * Syntax highlighting engine for Kate syntax definitions.
+ * In order to access the syntax highlighting Definition files, use the
+ * class Repository.
+ *
+ * @see Repository
+ */
+namespace KSyntaxHighlighting {
+
+class Definition;
+class RepositoryPrivate;
+class Theme;
+
+/**
+ * @brief Syntax highlighting repository.
+ *
+ * @section repo_intro Introduction
+ *
+ * The Repository gives access to all syntax Definitions available on the
+ * system, typically described in *.xml files. The Definition files are read
+ * from the resource that is compiled into the executable, and from the file
+ * system. If a Definition exists in the resource and on the file system,
+ * then the one from the file system is chosen.
+ *
+ * @section repo_access Definitions and Themes
+ *
+ * Typically, only one instance of the Repository is needed. This single
+ * instance can be thought of as a singleton you keep alive throughout the
+ * lifetime of your application. Then, either call definitionForName() with the
+ * given language name (e.g. "QML" or "Java"), or definitionForFileName() to
+ * obtain a Definition based on the filename/mimetype of the file. The
+ * function definitions() returns a list of all available syntax Definition%s.
+ *
+ * In addition to Definitions, the Repository also provides a list of Themes.
+ * A Theme is defined by a set of default text style colors as well as editor
+ * colors. These colors together provide all required colros for drawing all
+ * primitives of a text editor. All available Theme%s can be queried through
+ * themes(), and a Theme with a specific name is obtained through theme().
+ * Additionally, defaultTheme() provides a way to obtain a default theme for
+ * either a light or a black color theme.
+ *
+ * @section repo_search_paths Search Paths
+ *
+ * All highlighting Definition and Theme files are compiled into the shared
+ * KSyntaxHighlighting library by using the Qt resource system. Loading
+ * additional files from disk is supported as well.
+ *
+ * Loading syntax Definition files works as follows:
+ *
+ * -# First, all syntax highlighting files are loaded that are located in
+ * QStandardPaths::locateAll(QStandardPaths::GenericDataLocation, QStringLiteral("org.kde.syntax-highlighting/syntax"), QStandardPaths::LocateDirectory);
+ * Under Unix, this uses $XDG_DATA_HOME and $XDG_DATA_DIRS, which could
+ * 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.
+ *
+ * -# Finally, the search path can be extended by calling addCustomSearchPath().
+ * A custom search path can either be a path on disk or again a path to
+ * a Qt resource.
+ *
+ * Similarly, loading Theme files works as follows:
+ *
+ * -# First, all Theme files are loaded that are located in
+ * QStandardPaths::locateAll(QStandardPaths::GenericDataLocation, QStringLiteral("org.kde.syntax-highlighting/themes"), QStandardPaths::LocateDirectory);
+ * Under Unix, this uses $XDG_DATA_HOME and $XDG_DATA_DIRS, which could
+ * map to $HOME/.local5/share/org.kde.syntax-highlighting/themes and
+ * /usr/share/org.kde.syntax-highlighting/themes.
+ *
+ * -# Then, all files compiled into the library through resources are loaded.
+ * The internal resource path is ":/org.kde.syntax-highlighting/themes".
+ * This path should never be touched by other applications.
+ *
+ * -# Finally, all Theme%s located in the paths added addCustomSearchPath()
+ * are loaded.
+ *
+ * @note Whenever a Definition or a Theme exists twice, the variant with
+ * higher version is used.
+ *
+ * @note The QStandardPaths lookup can be disabled by compiling the framework with the -DNO_STANDARD_PATHS define.
+ *
+ * @see Definition, Theme, AbstractHighlighter
+ * @since 5.28
+ */
+class KSYNTAXHIGHLIGHTING_EXPORT Repository
+{
+public:
+ /**
+ * Create a new syntax definition repository.
+ * This will read the meta data information of all available syntax
+ * definition, which is a moderately expensive operation, it's therefore
+ * recommended to keep a single instance of Repository around as long
+ * as you need highlighting in your application.
+ */
+ Repository();
+ ~Repository();
+
+ /**
+ * Returns the Definition named @p defName.
+ *
+ * If no Definition is found, Definition::isValid() of the returned instance
+ * returns false.
+ *
+ * @note This uses case sensitive, untranslated names. For instance,
+ * the javascript.xml definition file sets its name to @e JavaScript.
+ * Therefore, only the string "JavaScript" will return a valid
+ * Definition file.
+ */
+ Definition definitionForName(const QString &defName) const;
+
+ /**
+ * Returns the best matching Definition for the file named @p fileName.
+ * The match is performed based on the \e extensions and @e mimetype of
+ * the definition files. If multiple matches are found, the one with the
+ * highest priority is returned.
+ *
+ * If no match is found, Definition::isValid() of the returned instance
+ * returns false.
+ */
+ Definition definitionForFileName(const QString &fileName) const;
+
+ /**
+ * Returns the best matching Definition to the type named @p mimeType
+ *
+ * If no match is found, Definition::isValid() of the returned instance
+ * returns false.
+ *
+ * @since 5.50
+ */
+ Definition definitionForMimeType(const QString &mimeType) const;
+
+ /**
+ * Returns all available Definition%s.
+ * Definition%ss are ordered by translated section and translated names,
+ * for consistent displaying.
+ */
+ QVector<Definition> definitions() const;
+
+ /**
+ * Returns all available color themes.
+ * The returned list should never be empty.
+ */
+ QVector<Theme> 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;
+
+ /**
+ * Built-in default theme types.
+ * @see defaultTheme()
+ */
+ enum DefaultTheme {
+ //! Theme with a light background color.
+ LightTheme,
+ //! Theme with a dark background color.
+ DarkTheme
+ };
+
+ /**
+ * Returns a default theme instance of the given type.
+ * The returned Theme is guaranteed to be a valid theme.
+ */
+ Theme defaultTheme(DefaultTheme t = LightTheme);
+
+ /**
+ * Reloads the repository.
+ * This is a moderately expensive operations and should thus only be
+ * triggered when the installed syntax definition files changed.
+ */
+ void reload();
+
+ /**
+ * Add a custom search path to the repository.
+ * This path will be searched in addition to the usual locations for syntax
+ * and theme definition files. Both locations on disk as well as Qt
+ * resource paths are supported.
+ *
+ * @note Internally, the two sub-folders @p path/syntax as well as
+ * @p path/themes are searched for additional Definition%s and
+ * Theme%s. Do not append @e syntax or @e themes to @p path
+ * yourself.
+ *
+ * @note Calling this triggers a reload() of the repository.
+ *
+ * @since 5.39
+ */
+ void addCustomSearchPath(const QString &path);
+
+ /**
+ * Returns the list of custom search paths added to the repository.
+ * By default, this list is empty.
+ *
+ * @see addCustomSearchPath()
+ * @since 5.39
+ */
+ QVector<QString> customSearchPaths() const;
+
+private:
+ Q_DISABLE_COPY(Repository)
+ friend class RepositoryPrivate;
+ std::unique_ptr<RepositoryPrivate> d;
+};
+
+}
+
+#endif // KSYNTAXHIGHLIGHTING_REPOSITORY_H
diff --git a/src/libs/3rdparty/syntax-highlighting/src/lib/repository_p.h b/src/libs/3rdparty/syntax-highlighting/src/lib/repository_p.h
new file mode 100644
index 0000000000..9db876be59
--- /dev/null
+++ b/src/libs/3rdparty/syntax-highlighting/src/lib/repository_p.h
@@ -0,0 +1,72 @@
+/*
+ Copyright (C) 2016 Volker Krause <vkrause@kde.org>
+
+ Permission is hereby granted, free of charge, to any person obtaining
+ a copy of this software and associated documentation files (the
+ "Software"), to deal in the Software without restriction, including
+ without limitation the rights to use, copy, modify, merge, publish,
+ distribute, sublicense, and/or sell copies of the Software, and to
+ permit persons to whom the Software is furnished to do so, subject to
+ the following conditions:
+
+ The above copyright notice and this permission notice shall be included
+ in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+#ifndef KSYNTAXHIGHLIGHTING_REPOSITORY_P_H
+#define KSYNTAXHIGHLIGHTING_REPOSITORY_P_H
+
+#include <QHash>
+#include <QVector>
+
+QT_BEGIN_NAMESPACE
+class QString;
+QT_END_NAMESPACE
+
+namespace KSyntaxHighlighting {
+
+class Definition;
+class Repository;
+class Theme;
+
+class RepositoryPrivate
+{
+public:
+ RepositoryPrivate() = default;
+
+ static RepositoryPrivate* get(Repository *repo);
+
+ void load(Repository *repo);
+ void loadSyntaxFolder(Repository *repo, const QString &path);
+ bool loadSyntaxFolderFromIndex(Repository *repo, const QString &path);
+
+ void addDefinition(const Definition &def);
+
+ void loadThemeFolder(const QString &path);
+ void addTheme(const Theme &theme);
+
+ quint16 foldingRegionId(const QString &defName, const QString &foldName);
+ quint16 nextFormatId();
+
+ QVector<QString> m_customSearchPaths;
+
+ QHash<QString, Definition> m_defs;
+ QVector<Definition> m_sortedDefs;
+
+ QVector<Theme> m_themes;
+
+ QHash<QPair<QString, QString>, quint16> m_foldingRegionIds;
+ quint16 m_foldingRegionId = 0;
+ quint16 m_formatId = 0;
+};
+}
+
+#endif
diff --git a/src/libs/3rdparty/syntax-highlighting/src/lib/rule.cpp b/src/libs/3rdparty/syntax-highlighting/src/lib/rule.cpp
new file mode 100644
index 0000000000..c48753bf0c
--- /dev/null
+++ b/src/libs/3rdparty/syntax-highlighting/src/lib/rule.cpp
@@ -0,0 +1,663 @@
+/*
+ Copyright (C) 2016 Volker Krause <vkrause@kde.org>
+ Copyright (C) 2018 Christoph Cullmann <cullmann@kde.org>
+
+ Permission is hereby granted, free of charge, to any person obtaining
+ a copy of this software and associated documentation files (the
+ "Software"), to deal in the Software without restriction, including
+ without limitation the rights to use, copy, modify, merge, publish,
+ distribute, sublicense, and/or sell copies of the Software, and to
+ permit persons to whom the Software is furnished to do so, subject to
+ the following conditions:
+
+ The above copyright notice and this permission notice shall be included
+ in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+#include "rule_p.h"
+#include "context_p.h"
+#include "definition_p.h"
+#include "ksyntaxhighlighting_logging.h"
+#include "xml_p.h"
+
+#include <QString>
+#include <QXmlStreamReader>
+
+using namespace KSyntaxHighlighting;
+
+static bool isOctalChar(QChar c)
+{
+ return c.isNumber() && c != QLatin1Char('9') && c != QLatin1Char('8');
+}
+
+static bool isHexChar(QChar c)
+{
+ return c.isNumber()
+ || c == QLatin1Char('a') || c == QLatin1Char('A')
+ || c == QLatin1Char('b') || c == QLatin1Char('B')
+ || c == QLatin1Char('c') || c == QLatin1Char('C')
+ || c == QLatin1Char('d') || c == QLatin1Char('D')
+ || c == QLatin1Char('e') || c == QLatin1Char('E')
+ || c == QLatin1Char('f') || c == QLatin1Char('F');
+}
+
+static int matchEscapedChar(const QString &text, int offset)
+{
+ if (text.at(offset) != QLatin1Char('\\') || text.size() < offset + 2)
+ return offset;
+
+ const auto c = text.at(offset + 1);
+ static const auto controlChars = QStringLiteral("abefnrtv\"'?\\");
+ if (controlChars.contains(c))
+ return offset + 2;
+
+ if (c == QLatin1Char('x')) { // hex encoded character
+ auto newOffset = offset + 2;
+ for (int i = 0; i < 2 && newOffset + i < text.size(); ++i, ++newOffset) {
+ if (!isHexChar(text.at(newOffset)))
+ break;
+ }
+ if (newOffset == offset + 2)
+ return offset;
+ return newOffset;
+ }
+
+ if (isOctalChar(c)) { // octal encoding
+ auto newOffset = offset + 2;
+ for (int i = 0; i < 2 && newOffset + i < text.size(); ++i, ++newOffset) {
+ if (!isOctalChar(text.at(newOffset)))
+ break;
+ }
+ if (newOffset == offset + 2)
+ return offset;
+ return newOffset;
+ }
+
+ return 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));
+ }
+ return result;
+}
+
+Definition Rule::definition() const
+{
+ return m_def.definition();
+}
+
+void Rule::setDefinition(const Definition &def)
+{
+ m_def = def;
+
+ // cache for DefinitionData::wordDelimiters, is accessed VERY often
+ m_wordDelimiter = &DefinitionData::get(m_def.definition())->wordDelimiters;
+}
+
+bool Rule::load(QXmlStreamReader &reader)
+{
+ Q_ASSERT(reader.tokenType() == QXmlStreamReader::StartElement);
+
+ m_attribute = reader.attributes().value(QStringLiteral("attribute")).toString();
+ if (reader.name() != QLatin1String("IncludeRules")) // IncludeRules uses this with a different semantic
+ m_context.parse(reader.attributes().value(QStringLiteral("context")));
+ m_firstNonSpace = Xml::attrToBool(reader.attributes().value(QStringLiteral("firstNonSpace")));
+ m_lookAhead = Xml::attrToBool(reader.attributes().value(QStringLiteral("lookAhead")));
+ bool colOk = false;
+ m_column = reader.attributes().value(QStringLiteral("column")).toInt(&colOk);
+ if (!colOk)
+ m_column = -1;
+
+ auto regionName = reader.attributes().value(QLatin1String("beginRegion"));
+ if (!regionName.isEmpty())
+ m_beginRegion = FoldingRegion(FoldingRegion::Begin, DefinitionData::get(m_def.definition())->foldingRegionId(regionName.toString()));
+ regionName = reader.attributes().value(QLatin1String("endRegion"));
+ if (!regionName.isEmpty())
+ m_endRegion = FoldingRegion(FoldingRegion::End, DefinitionData::get(m_def.definition())->foldingRegionId(regionName.toString()));
+
+ auto result = doLoad(reader);
+
+ if (m_lookAhead && m_context.isStay())
+ result = false;
+
+ // be done with this rule, skip all subelements, e.g. no longer supported sub-rules
+ reader.skipCurrentElement();
+ return result;
+}
+
+void Rule::resolveContext()
+{
+ m_context.resolve(m_def.definition());
+}
+
+void Rule::resolveAttributeFormat(Context *lookupContext)
+{
+ /**
+ * try to get our format from the definition we stem from
+ */
+ if (!m_attribute.isEmpty()) {
+ m_attributeFormat = DefinitionData::get(definition())->formatByName(m_attribute);
+ if (!m_attributeFormat.isValid()) {
+ qCWarning(Log) << "Rule: Unknown format" << m_attribute << "in context" << lookupContext->name() << "of definition" << definition().name();
+ }
+ }
+}
+
+bool Rule::doLoad(QXmlStreamReader& reader)
+{
+ Q_UNUSED(reader);
+ return true;
+}
+
+Rule::Ptr Rule::create(const QStringRef& name)
+{
+ Rule *rule = nullptr;
+ if (name == QLatin1String("AnyChar"))
+ rule = new AnyChar;
+ else if (name == QLatin1String("DetectChar"))
+ rule = new DetectChar;
+ else if (name == QLatin1String("Detect2Chars"))
+ rule = new Detect2Char;
+ else if (name == QLatin1String("DetectIdentifier"))
+ rule = new DetectIdentifier;
+ else if (name == QLatin1String("DetectSpaces"))
+ rule = new DetectSpaces;
+ else if (name == QLatin1String("Float"))
+ rule = new Float;
+ else if (name == QLatin1String("Int"))
+ rule = new Int;
+ else if (name == QLatin1String("HlCChar"))
+ rule = new HlCChar;
+ else if (name == QLatin1String("HlCHex"))
+ rule = new HlCHex;
+ else if (name == QLatin1String("HlCOct"))
+ rule = new HlCOct;
+ else if (name == QLatin1String("HlCStringChar"))
+ rule = new HlCStringChar;
+ else if (name == QLatin1String("IncludeRules"))
+ rule = new IncludeRules;
+ else if (name == QLatin1String("keyword"))
+ rule = new KeywordListRule;
+ else if (name == QLatin1String("LineContinue"))
+ rule = new LineContinue;
+ else if (name == QLatin1String("RangeDetect"))
+ rule = new RangeDetect;
+ else if (name == QLatin1String("RegExpr"))
+ rule = new RegExpr;
+ else if (name == QLatin1String("StringDetect"))
+ rule = new StringDetect;
+ else if (name == QLatin1String("WordDetect"))
+ rule = new WordDetect;
+ else
+ qCWarning(Log) << "Unknown rule type:" << name;
+
+ return Ptr(rule);
+}
+
+bool Rule::isWordDelimiter(QChar c) const
+{
+ // perf tells contains is MUCH faster than binary search here, very short array
+ return m_wordDelimiter.contains(c);
+}
+
+
+bool AnyChar::doLoad(QXmlStreamReader& reader)
+{
+ m_chars = reader.attributes().value(QStringLiteral("String")).toString();
+ if (m_chars.size() == 1)
+ qCDebug(Log) << "AnyChar rule with just one char: use DetectChar instead.";
+ return !m_chars.isEmpty();
+}
+
+MatchResult AnyChar::doMatch(const QString& text, int offset, const QStringList&) const
+{
+ if (m_chars.contains(text.at(offset)))
+ return offset + 1;
+ return offset;
+}
+
+
+bool DetectChar::doLoad(QXmlStreamReader& reader)
+{
+ const auto s = reader.attributes().value(QStringLiteral("char"));
+ if (s.isEmpty())
+ return false;
+ m_char = s.at(0);
+ m_dynamic = Xml::attrToBool(reader.attributes().value(QStringLiteral("dynamic")));
+ if (m_dynamic) {
+ m_captureIndex = m_char.digitValue();
+ }
+ return true;
+}
+
+MatchResult DetectChar::doMatch(const QString& text, int offset, const QStringList &captures) const
+{
+ if (m_dynamic) {
+ if (m_captureIndex == 0 || captures.size() <= m_captureIndex || captures.at(m_captureIndex).isEmpty())
+ return offset;
+ if (text.at(offset) == captures.at(m_captureIndex).at(0))
+ return offset + 1;
+ return offset;
+ }
+
+ if (text.at(offset) == m_char)
+ return offset + 1;
+ return offset;
+}
+
+
+bool Detect2Char::doLoad(QXmlStreamReader& reader)
+{
+ const auto s1 = reader.attributes().value(QStringLiteral("char"));
+ const auto s2 = reader.attributes().value(QStringLiteral("char1"));
+ if (s1.isEmpty() || s2.isEmpty())
+ return false;
+ m_char1 = s1.at(0);
+ m_char2 = s2.at(0);
+ return true;
+}
+
+MatchResult Detect2Char::doMatch(const QString& text, int offset, const QStringList &) const
+{
+ if (text.size() - offset < 2)
+ return offset;
+ if (text.at(offset) == m_char1 && text.at(offset + 1) == m_char2)
+ return offset + 2;
+ return offset;
+}
+
+
+MatchResult DetectIdentifier::doMatch(const QString& text, int offset, const QStringList&) const
+{
+ if (!text.at(offset).isLetter() && text.at(offset) != QLatin1Char('_'))
+ return offset;
+
+ for (int i = offset + 1; i < text.size(); ++i) {
+ const auto c = text.at(i);
+ if (!c.isLetterOrNumber() && c != QLatin1Char('_'))
+ return i;
+ }
+
+ return text.size();
+}
+
+
+MatchResult DetectSpaces::doMatch(const QString& text, int offset, const QStringList&) const
+{
+ while(offset < text.size() && text.at(offset).isSpace())
+ ++offset;
+ return offset;
+}
+
+
+MatchResult Float::doMatch(const QString& text, int offset, const QStringList&) const
+{
+ if (offset > 0 && !isWordDelimiter(text.at(offset - 1)))
+ return offset;
+
+ auto newOffset = offset;
+ while (newOffset < text.size() && text.at(newOffset).isDigit())
+ ++newOffset;
+
+ if (newOffset >= text.size() || text.at(newOffset) != QLatin1Char('.'))
+ return offset;
+ ++newOffset;
+
+ while (newOffset < text.size() && text.at(newOffset).isDigit())
+ ++newOffset;
+
+ if (newOffset == offset + 1) // we only found a decimal point
+ return offset;
+
+ auto expOffset = newOffset;
+ if (expOffset >= text.size() || (text.at(expOffset) != QLatin1Char('e') && text.at(expOffset) != QLatin1Char('E')))
+ return newOffset;
+ ++expOffset;
+
+ if (expOffset < text.size() && (text.at(expOffset) == QLatin1Char('+') || text.at(expOffset) == QLatin1Char('-')))
+ ++expOffset;
+ bool foundExpDigit = false;
+ while (expOffset < text.size() && text.at(expOffset).isDigit()) {
+ ++expOffset;
+ foundExpDigit = true;
+ }
+
+ if (!foundExpDigit)
+ return newOffset;
+ return expOffset;
+}
+
+
+MatchResult HlCChar::doMatch(const QString& text, int offset, const QStringList&) const
+{
+ if (text.size() < offset + 3)
+ return offset;
+
+ if (text.at(offset) != QLatin1Char('\'') || text.at(offset + 1) == QLatin1Char('\''))
+ return offset;
+
+ auto newOffset = matchEscapedChar(text, offset + 1);
+ if (newOffset == offset + 1) {
+ if (text.at(newOffset) == QLatin1Char('\\'))
+ return offset;
+ else
+ ++newOffset;
+ }
+ if (newOffset >= text.size())
+ return offset;
+
+ if (text.at(newOffset) == QLatin1Char('\''))
+ return newOffset + 1;
+
+ return offset;
+}
+
+
+MatchResult HlCHex::doMatch(const QString& text, int offset, const QStringList&) const
+{
+ if (offset > 0 && !isWordDelimiter(text.at(offset - 1)))
+ return offset;
+
+ if (text.size() < offset + 3)
+ return offset;
+
+ if (text.at(offset) != QLatin1Char('0') || (text.at(offset + 1) != QLatin1Char('x') && text.at(offset + 1) != QLatin1Char('X')))
+ return offset;
+
+ if (!isHexChar(text.at(offset + 2)))
+ return offset;
+
+ offset += 3;
+ while (offset < text.size() && isHexChar(text.at(offset)))
+ ++offset;
+
+ // TODO Kate matches U/L suffix, QtC does not?
+
+ return offset;
+}
+
+
+MatchResult HlCOct::doMatch(const QString& text, int offset, const QStringList&) const
+{
+ if (offset > 0 && !isWordDelimiter(text.at(offset - 1)))
+ return offset;
+
+ if (text.size() < offset + 2)
+ return offset;
+
+ if (text.at(offset) != QLatin1Char('0'))
+ return offset;
+
+ if (!isOctalChar(text.at(offset + 1)))
+ return offset;
+
+ offset += 2;
+ while (offset < text.size() && isOctalChar(text.at(offset)))
+ ++offset;
+
+ return offset;
+}
+
+
+MatchResult HlCStringChar::doMatch(const QString& text, int offset, const QStringList&) const
+{
+ return matchEscapedChar(text, offset);
+}
+
+
+QString IncludeRules::contextName() const
+{
+ return m_contextName;
+}
+
+QString IncludeRules::definitionName() const
+{
+ return m_defName;
+}
+
+bool IncludeRules::includeAttribute() const
+{
+ return m_includeAttribute;
+}
+
+bool IncludeRules::doLoad(QXmlStreamReader& reader)
+{
+ const auto s = reader.attributes().value(QLatin1String("context"));
+ const auto split = s.split(QLatin1String("##"), QString::KeepEmptyParts);
+ if (split.isEmpty())
+ return false;
+ m_contextName = split.at(0).toString();
+ if (split.size() > 1)
+ m_defName = split.at(1).toString();
+ m_includeAttribute = Xml::attrToBool(reader.attributes().value(QLatin1String("includeAttrib")));
+
+ return !m_contextName.isEmpty() || !m_defName.isEmpty();
+}
+
+MatchResult IncludeRules::doMatch(const QString& text, int offset, const QStringList&) const
+{
+ Q_UNUSED(text);
+ qCWarning(Log) << "Unresolved include rule for" << m_contextName << "##" << m_defName;
+ return offset;
+}
+
+
+MatchResult Int::doMatch(const QString& text, int offset, const QStringList &) const
+{
+ if (offset > 0 && !isWordDelimiter(text.at(offset - 1)))
+ return offset;
+
+ while(offset < text.size() && text.at(offset).isDigit())
+ ++offset;
+ return offset;
+}
+
+
+bool KeywordListRule::doLoad(QXmlStreamReader& reader)
+{
+ /**
+ * get our keyword list, if not found => bail out
+ */
+ auto defData = DefinitionData::get(definition());
+ m_keywordList = defData->keywordList(reader.attributes().value(QLatin1String("String")).toString());
+ if (!m_keywordList) {
+ return false;
+ }
+
+ /**
+ * we might overwrite the case sensitivity
+ * then we need to init the list for lookup of that sensitivity setting
+ */
+ if (reader.attributes().hasAttribute(QLatin1String("insensitive"))) {
+ m_hasCaseSensitivityOverride = true;
+ m_caseSensitivityOverride = Xml::attrToBool(reader.attributes().value(QLatin1String("insensitive"))) ?
+ Qt::CaseInsensitive : Qt::CaseSensitive;
+ m_keywordList->initLookupForCaseSensitivity(m_caseSensitivityOverride);
+ } else {
+ m_hasCaseSensitivityOverride = false;
+ }
+
+ return !m_keywordList->isEmpty();
+}
+
+MatchResult KeywordListRule::doMatch(const QString& text, int offset, const QStringList&) const
+{
+ auto newOffset = offset;
+ while (text.size() > newOffset && !isWordDelimiter(text.at(newOffset)))
+ ++newOffset;
+ if (newOffset == offset)
+ return offset;
+
+ if (m_hasCaseSensitivityOverride) {
+ if (m_keywordList->contains(text.midRef(offset, newOffset - offset), m_caseSensitivityOverride))
+ return newOffset;
+ } else {
+ if (m_keywordList->contains(text.midRef(offset, newOffset - offset)))
+ return newOffset;
+ }
+
+ // we don't match, but we can skip until newOffset as we can't start a keyword in-between
+ return MatchResult(offset, newOffset);
+}
+
+
+bool LineContinue::doLoad(QXmlStreamReader& reader)
+{
+ const auto s = reader.attributes().value(QStringLiteral("char"));
+ if (s.isEmpty())
+ m_char = QLatin1Char('\\');
+ else
+ m_char = s.at(0);
+ return true;
+}
+
+MatchResult LineContinue::doMatch(const QString& text, int offset, const QStringList&) const
+{
+ if (offset == text.size() - 1 && text.at(offset) == m_char)
+ return offset + 1;
+ return offset;
+}
+
+
+bool RangeDetect::doLoad(QXmlStreamReader& reader)
+{
+ const auto s1 = reader.attributes().value(QStringLiteral("char"));
+ const auto s2 = reader.attributes().value(QStringLiteral("char1"));
+ if (s1.isEmpty() || s2.isEmpty())
+ return false;
+ m_begin = s1.at(0);
+ m_end = s2.at(0);
+ return true;
+}
+
+MatchResult RangeDetect::doMatch(const QString& text, int offset, const QStringList&) const
+{
+ if (text.size() - offset < 2)
+ return offset;
+ if (text.at(offset) != m_begin)
+ return offset;
+
+ auto newOffset = offset + 1;
+ while (newOffset < text.size()) {
+ if (text.at(newOffset) == m_end)
+ return newOffset + 1;
+ ++newOffset;
+ }
+ return offset;
+}
+
+bool RegExpr::doLoad(QXmlStreamReader& reader)
+{
+ m_regexp.setPattern(reader.attributes().value(QStringLiteral("String")).toString());
+
+ const auto isMinimal = Xml::attrToBool(reader.attributes().value(QStringLiteral("minimal")));
+ const auto isCaseInsensitive = Xml::attrToBool(reader.attributes().value(QStringLiteral("insensitive")));
+ m_regexp.setPatternOptions(
+ (isMinimal ? QRegularExpression::InvertedGreedinessOption : QRegularExpression::NoPatternOption) |
+ (isCaseInsensitive ? QRegularExpression::CaseInsensitiveOption : QRegularExpression::NoPatternOption));
+
+ // optimize the pattern for the non-dynamic case, we use them OFTEN
+ m_dynamic = Xml::attrToBool(reader.attributes().value(QStringLiteral("dynamic")));
+ if (!m_dynamic) {
+ m_regexp.optimize();
+ }
+
+ // always using m_regexp.isValid() would be better, but parses the regexp and thus is way too expensive for release builds
+
+ if (Log().isDebugEnabled()) {
+ if (!m_regexp.isValid())
+ qCDebug(Log) << "Invalid regexp:" << m_regexp.pattern();
+ }
+ return !m_regexp.pattern().isEmpty();
+}
+
+MatchResult RegExpr::doMatch(const QString& text, int offset, const QStringList &captures) const
+{
+ /**
+ * for dynamic case: create new pattern with right instantiation
+ */
+ const auto &regexp = m_dynamic ? QRegularExpression(replaceCaptures(m_regexp.pattern(), captures, true), m_regexp.patternOptions()) : m_regexp;
+
+ /**
+ * match the pattern
+ */
+ const auto result = regexp.match(text, offset, QRegularExpression::NormalMatch, QRegularExpression::DontCheckSubjectStringMatchOption);
+ 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());
+ }
+
+ /**
+ * else: ignore the implicit 0 group we always capture, no need to allocate stuff for that
+ */
+ return MatchResult(offset + result.capturedLength());
+ }
+
+ /**
+ * no match
+ */
+ return MatchResult(offset, result.capturedStart());
+}
+
+
+bool StringDetect::doLoad(QXmlStreamReader& reader)
+{
+ m_string = reader.attributes().value(QStringLiteral("String")).toString();
+ m_caseSensitivity = Xml::attrToBool(reader.attributes().value(QStringLiteral("insensitive"))) ? Qt::CaseInsensitive : Qt::CaseSensitive;
+ m_dynamic = Xml::attrToBool(reader.attributes().value(QStringLiteral("dynamic")));
+ return !m_string.isEmpty();
+}
+
+MatchResult StringDetect::doMatch(const QString& text, int offset, const QStringList &captures) const
+{
+ /**
+ * for dynamic case: create new pattern with right instantiation
+ */
+ const auto &pattern = m_dynamic ? replaceCaptures(m_string, captures, false) : m_string;
+
+ if (text.midRef(offset, pattern.size()).compare(pattern, m_caseSensitivity) == 0)
+ return offset + pattern.size();
+ return offset;
+}
+
+
+bool WordDetect::doLoad(QXmlStreamReader& reader)
+{
+ m_word = reader.attributes().value(QStringLiteral("String")).toString();
+ m_caseSensitivity = Xml::attrToBool(reader.attributes().value(QStringLiteral("insensitive"))) ? Qt::CaseInsensitive : Qt::CaseSensitive;
+ return !m_word.isEmpty();
+}
+
+MatchResult WordDetect::doMatch(const QString& text, int offset, const QStringList &) const
+{
+ if (text.size() - offset < m_word.size())
+ return offset;
+
+ if (offset > 0 && !isWordDelimiter(text.at(offset - 1)))
+ return offset;
+
+ if (text.midRef(offset, m_word.size()).compare(m_word, m_caseSensitivity) != 0)
+ return offset;
+
+ if (text.size() == offset + m_word.size() || isWordDelimiter(text.at(offset + m_word.size())))
+ return 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
new file mode 100644
index 0000000000..538fdeda8a
--- /dev/null
+++ b/src/libs/3rdparty/syntax-highlighting/src/lib/rule_p.h
@@ -0,0 +1,291 @@
+/*
+ Copyright (C) 2016 Volker Krause <vkrause@kde.org>
+
+ Permission is hereby granted, free of charge, to any person obtaining
+ a copy of this software and associated documentation files (the
+ "Software"), to deal in the Software without restriction, including
+ without limitation the rights to use, copy, modify, merge, publish,
+ distribute, sublicense, and/or sell copies of the Software, and to
+ permit persons to whom the Software is furnished to do so, subject to
+ the following conditions:
+
+ The above copyright notice and this permission notice shall be included
+ in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+#ifndef KSYNTAXHIGHLIGHTING_RULE_P_H
+#define KSYNTAXHIGHLIGHTING_RULE_P_H
+
+#include "contextswitch_p.h"
+#include "definition.h"
+#include "definitionref_p.h"
+#include "foldingregion.h"
+#include "format.h"
+#include "keywordlist_p.h"
+#include "matchresult_p.h"
+
+#include <QRegularExpression>
+#include <QString>
+#include <QVector>
+
+#include <memory>
+
+QT_BEGIN_NAMESPACE
+class QXmlStreamReader;
+QT_END_NAMESPACE
+
+namespace KSyntaxHighlighting {
+
+class Rule
+{
+public:
+ Rule() = default;
+ virtual ~Rule() = default;
+
+ typedef std::shared_ptr<Rule> Ptr;
+
+ Definition definition() const;
+ void setDefinition(const Definition &def);
+
+ const Format &attributeFormat() const
+ {
+ return m_attributeFormat;
+ }
+
+ const ContextSwitch &context() const
+ {
+ return m_context;
+ }
+
+ bool isLookAhead() const
+ {
+ return m_lookAhead;
+ }
+
+ bool firstNonSpace() const
+ {
+ return m_firstNonSpace;
+ }
+
+ int requiredColumn() const
+ {
+ return m_column;
+ }
+
+ const FoldingRegion &beginRegion() const
+ {
+ return m_beginRegion;
+ }
+
+ const FoldingRegion &endRegion() const
+ {
+ return m_endRegion;
+ }
+
+ bool load(QXmlStreamReader &reader);
+ void resolveContext();
+ void resolveAttributeFormat(Context *lookupContext);
+
+ virtual MatchResult doMatch(const QString &text, int offset, const QStringList &captures) const = 0;
+
+ static Rule::Ptr create(const QStringRef &name);
+
+protected:
+ virtual bool doLoad(QXmlStreamReader &reader);
+
+ bool isWordDelimiter(QChar c) const;
+
+private:
+ Q_DISABLE_COPY(Rule)
+
+ DefinitionRef m_def;
+ QString m_attribute;
+ Format m_attributeFormat;
+ ContextSwitch m_context;
+ int m_column = -1;
+ FoldingRegion m_beginRegion;
+ FoldingRegion m_endRegion;
+ bool m_firstNonSpace = false;
+ bool m_lookAhead = false;
+
+ // cache for DefinitionData::wordDelimiters, is accessed VERY often
+ QStringRef m_wordDelimiter;
+};
+
+
+class AnyChar : public Rule
+{
+protected:
+ bool doLoad(QXmlStreamReader & reader) override;
+ MatchResult doMatch(const QString & text, int offset, const QStringList&) const override;
+
+private:
+ QString m_chars;
+};
+
+class DetectChar : public Rule
+{
+protected:
+ bool doLoad(QXmlStreamReader & reader) override;
+ MatchResult doMatch(const QString & text, int offset, const QStringList &captures) const override;
+
+private:
+ QChar m_char;
+ bool m_dynamic = false;
+ int m_captureIndex = 0;
+};
+
+class Detect2Char : public Rule
+{
+protected:
+ bool doLoad(QXmlStreamReader & reader) override;
+ MatchResult doMatch(const QString & text, int offset, const QStringList &captures) const override;
+
+private:
+ QChar m_char1;
+ QChar m_char2;
+};
+
+class DetectIdentifier : public Rule
+{
+protected:
+ MatchResult doMatch(const QString & text, int offset, const QStringList&) const override;
+};
+
+class DetectSpaces : public Rule
+{
+protected:
+ MatchResult doMatch(const QString & text, int offset, const QStringList&) const override;
+};
+
+class Float : public Rule
+{
+protected:
+ MatchResult doMatch(const QString & text, int offset, const QStringList&) const override;
+};
+
+class IncludeRules : public Rule
+{
+public:
+ QString contextName() const;
+ QString definitionName() const;
+ bool includeAttribute() const;
+
+protected:
+ bool doLoad(QXmlStreamReader & reader) override;
+ MatchResult doMatch(const QString & text, int offset, const QStringList&) const override;
+
+private:
+ QString m_contextName;
+ QString m_defName;
+ bool m_includeAttribute;
+};
+
+class Int : public Rule
+{
+protected:
+ MatchResult doMatch(const QString & text, int offset, const QStringList &captures) const override;
+};
+
+class HlCChar : public Rule
+{
+protected:
+ MatchResult doMatch(const QString & text, int offset, const QStringList&) const override;
+};
+
+class HlCHex : public Rule
+{
+protected:
+ MatchResult doMatch(const QString & text, int offset, const QStringList&) const override;
+};
+
+class HlCOct : public Rule
+{
+protected:
+ MatchResult doMatch(const QString & text, int offset, const QStringList&) const override;
+};
+
+class HlCStringChar : public Rule
+{
+protected:
+ MatchResult doMatch(const QString & text, int offset, const QStringList&) const override;
+};
+
+class KeywordListRule : public Rule
+{
+protected:
+ bool doLoad(QXmlStreamReader & reader) override;
+ MatchResult doMatch(const QString & text, int offset, const QStringList&) const override;
+
+private:
+ KeywordList *m_keywordList;
+ bool m_hasCaseSensitivityOverride;
+ Qt::CaseSensitivity m_caseSensitivityOverride;
+};
+
+class LineContinue : public Rule
+{
+protected:
+ bool doLoad(QXmlStreamReader & reader) override;
+ MatchResult doMatch(const QString & text, int offset, const QStringList&) const override;
+
+private:
+ QChar m_char;
+};
+
+class RangeDetect : public Rule
+{
+protected:
+ bool doLoad(QXmlStreamReader & reader) override;
+ MatchResult doMatch(const QString & text, int offset, const QStringList&) const override;
+
+private:
+ QChar m_begin;
+ QChar m_end;
+};
+
+class RegExpr : public Rule
+{
+protected:
+ bool doLoad(QXmlStreamReader & reader) override;
+ MatchResult doMatch(const QString & text, int offset, const QStringList &captures) const override;
+
+private:
+ QRegularExpression m_regexp;
+ bool m_dynamic = false;
+};
+
+class StringDetect : public Rule
+{
+protected:
+ bool doLoad(QXmlStreamReader & reader) override;
+ MatchResult doMatch(const QString & text, int offset, const QStringList &captures) const override;
+
+private:
+ QString m_string;
+ Qt::CaseSensitivity m_caseSensitivity;
+ bool m_dynamic = false;
+};
+
+class WordDetect : public Rule
+{
+protected:
+ bool doLoad(QXmlStreamReader & reader) override;
+ MatchResult doMatch(const QString & text, int offset, const QStringList &captures) const override;
+
+private:
+ QString m_word;
+ Qt::CaseSensitivity m_caseSensitivity;
+};
+
+}
+
+#endif // KSYNTAXHIGHLIGHTING_RULE_P_H
diff --git a/src/libs/3rdparty/syntax-highlighting/src/lib/state.cpp b/src/libs/3rdparty/syntax-highlighting/src/lib/state.cpp
new file mode 100644
index 0000000000..f970e13f8b
--- /dev/null
+++ b/src/libs/3rdparty/syntax-highlighting/src/lib/state.cpp
@@ -0,0 +1,123 @@
+/*
+ Copyright (C) 2016 Volker Krause <vkrause@kde.org>
+ Copyright (C) 2018 Christoph Cullmann <cullmann@kde.org>
+
+ Permission is hereby granted, free of charge, to any person obtaining
+ a copy of this software and associated documentation files (the
+ "Software"), to deal in the Software without restriction, including
+ without limitation the rights to use, copy, modify, merge, publish,
+ distribute, sublicense, and/or sell copies of the Software, and to
+ permit persons to whom the Software is furnished to do so, subject to
+ the following conditions:
+
+ The above copyright notice and this permission notice shall be included
+ in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+#include "state.h"
+#include "state_p.h"
+
+#include "context_p.h"
+
+#include <QStringList>
+
+using namespace KSyntaxHighlighting;
+
+StateData* StateData::get(State &state)
+{
+ state.d.detach();
+ return state.d.data();
+}
+
+bool StateData::isEmpty() const
+{
+ return m_contextStack.isEmpty();
+}
+
+void StateData::clear()
+{
+ m_contextStack.clear();
+}
+
+int StateData::size() const
+{
+ return m_contextStack.size();
+}
+
+void StateData::push(Context *context, const QStringList &captures)
+{
+ Q_ASSERT(context);
+ m_contextStack.push_back(qMakePair(context, captures));
+}
+
+bool StateData::pop(int popCount)
+{
+ // nop if nothing to pop
+ if (popCount <= 0) {
+ return true;
+ }
+
+ // keep the initial context alive in any case
+ Q_ASSERT(!isEmpty());
+ const bool initialContextSurvived = m_contextStack.size() > popCount;
+ m_contextStack.resize(std::max(1, m_contextStack.size() - popCount));
+ return initialContextSurvived;
+}
+
+Context* StateData::topContext() const
+{
+ Q_ASSERT(!isEmpty());
+ return m_contextStack.last().first;
+}
+
+const QStringList &StateData::topCaptures() const
+{
+ Q_ASSERT(!isEmpty());
+ return m_contextStack.last().second;
+}
+
+State::State() :
+ d(new StateData)
+{
+}
+
+State::State(const State &other) :
+ d(other.d)
+{
+}
+
+State::~State()
+{
+}
+
+State& State::operator=(const State &other)
+{
+ d = other.d;
+ return *this;
+}
+
+bool State::operator==(const State &other) const
+{
+ // use pointer equal as shortcut for shared states
+ return (d == other.d) || (d->m_contextStack == other.d->m_contextStack && d->m_defRef == other.d->m_defRef);
+}
+
+bool State::operator!=(const State &other) const
+{
+ return !(*this == other);
+}
+
+bool State::indentationBasedFoldingEnabled() const
+{
+ if (d->m_contextStack.isEmpty())
+ return false;
+ return d->m_contextStack.last().first->indentationBasedFoldingEnabled();
+}
diff --git a/src/libs/3rdparty/syntax-highlighting/src/lib/state.h b/src/libs/3rdparty/syntax-highlighting/src/lib/state.h
new file mode 100644
index 0000000000..fce4bc71e8
--- /dev/null
+++ b/src/libs/3rdparty/syntax-highlighting/src/lib/state.h
@@ -0,0 +1,86 @@
+/*
+ Copyright (C) 2016 Volker Krause <vkrause@kde.org>
+
+ Permission is hereby granted, free of charge, to any person obtaining
+ a copy of this software and associated documentation files (the
+ "Software"), to deal in the Software without restriction, including
+ without limitation the rights to use, copy, modify, merge, publish,
+ distribute, sublicense, and/or sell copies of the Software, and to
+ permit persons to whom the Software is furnished to do so, subject to
+ the following conditions:
+
+ The above copyright notice and this permission notice shall be included
+ in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+#ifndef KSYNTAXHIGHLIGHTING_STATE_H
+#define KSYNTAXHIGHLIGHTING_STATE_H
+
+#include "ksyntaxhighlighting_export.h"
+
+#include <QExplicitlySharedDataPointer>
+#include <QTypeInfo>
+
+namespace KSyntaxHighlighting {
+
+class StateData;
+
+/** 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
+ * line for fast re-highlighting of specific lines (e.g. during editing).
+ *
+ * @since 5.28
+ */
+class KSYNTAXHIGHLIGHTING_EXPORT State
+{
+public:
+ /** Creates an initial state, ie. what should be used for the first line
+ * in a document.
+ */
+ State();
+ State(const State &other);
+ ~State();
+ State& operator=(const State &rhs);
+
+ /** Compares two states for equality.
+ * For two equal states and identical text input, AbstractHighlighter
+ * guarantees to produce equal results. This can be used to only
+ * re-highlight as many lines as necessary during editing.
+ */
+ bool operator==(const State &other) const;
+ /** Compares two states for inequality.
+ * This is the opposite of operator==().
+ */
+ bool operator!=(const State &other) const;
+
+ /**
+ * Returns whether or not indentation-based folding is enabled in this state.
+ * When using a Definition with indentation-based folding, use
+ * this method to check if indentation-based folding has been
+ * suspended in the current line.
+ *
+ * @see Definition::indentationBasedFoldingEnabled()
+ */
+ bool indentationBasedFoldingEnabled() const;
+
+private:
+ friend class StateData;
+ QExplicitlySharedDataPointer<StateData> d;
+};
+
+}
+
+QT_BEGIN_NAMESPACE
+Q_DECLARE_TYPEINFO(KSyntaxHighlighting::State, Q_MOVABLE_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
new file mode 100644
index 0000000000..a99192b4c6
--- /dev/null
+++ b/src/libs/3rdparty/syntax-highlighting/src/lib/state_p.h
@@ -0,0 +1,81 @@
+/*
+ Copyright (C) 2016 Volker Krause <vkrause@kde.org>
+ Copyright (C) 2018 Christoph Cullmann <cullmann@kde.org>
+
+ Permission is hereby granted, free of charge, to any person obtaining
+ a copy of this software and associated documentation files (the
+ "Software"), to deal in the Software without restriction, including
+ without limitation the rights to use, copy, modify, merge, publish,
+ distribute, sublicense, and/or sell copies of the Software, and to
+ permit persons to whom the Software is furnished to do so, subject to
+ the following conditions:
+
+ The above copyright notice and this permission notice shall be included
+ in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+#ifndef KSYNTAXHIGHLIGHTING_STATE_P_H
+#define KSYNTAXHIGHLIGHTING_STATE_P_H
+
+#include <QSharedData>
+#include <QVector>
+
+#include "definitionref_p.h"
+
+QT_BEGIN_NAMESPACE
+class QStringList;
+QT_END_NAMESPACE
+
+namespace KSyntaxHighlighting
+{
+
+class Context;
+
+class StateData : public QSharedData
+{
+ friend class State;
+ friend class AbstractHighlighter;
+
+public:
+ StateData() = default;
+ static StateData* get(State &state);
+
+ bool isEmpty() const;
+ void clear();
+ int size() const;
+ void push(Context *context, const QStringList &captures);
+
+ /**
+ * Pop the number of elements given from the top of the current stack.
+ * Will not pop the initial element.
+ * @param popCount number of elements to pop
+ * @return false if one has tried to pop the initial context, else true
+ */
+ bool pop(int popCount);
+
+ Context* topContext() const;
+ const QStringList &topCaptures() const;
+
+private:
+ /**
+ * weak reference to the used definition to filter out invalid states
+ */
+ DefinitionRef m_defRef;
+
+ /**
+ * the context stack combines the active context + valid captures
+ */
+ QVector<QPair<Context *, QStringList>> m_contextStack;
+};
+
+}
+
+#endif
diff --git a/src/libs/3rdparty/syntax-highlighting/src/lib/syntaxhighlighter.cpp b/src/libs/3rdparty/syntax-highlighting/src/lib/syntaxhighlighter.cpp
new file mode 100644
index 0000000000..2bb61a7ae6
--- /dev/null
+++ b/src/libs/3rdparty/syntax-highlighting/src/lib/syntaxhighlighter.cpp
@@ -0,0 +1,198 @@
+/*
+ Copyright (C) 2016 Volker Krause <vkrause@kde.org>
+
+ Permission is hereby granted, free of charge, to any person obtaining
+ a copy of this software and associated documentation files (the
+ "Software"), to deal in the Software without restriction, including
+ without limitation the rights to use, copy, modify, merge, publish,
+ distribute, sublicense, and/or sell copies of the Software, and to
+ permit persons to whom the Software is furnished to do so, subject to
+ the following conditions:
+
+ The above copyright notice and this permission notice shall be included
+ in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+#include "syntaxhighlighter.h"
+#include "abstracthighlighter_p.h"
+#include "definition.h"
+#include "foldingregion.h"
+#include "format.h"
+#include "state.h"
+#include "theme.h"
+
+#include <QDebug>
+
+Q_DECLARE_METATYPE(QTextBlock)
+
+using namespace KSyntaxHighlighting;
+
+namespace KSyntaxHighlighting {
+class TextBlockUserData : public QTextBlockUserData
+{
+public:
+ State state;
+ QVector<FoldingRegion> foldingRegions;
+};
+
+class SyntaxHighlighterPrivate : public AbstractHighlighterPrivate
+{
+public:
+ static FoldingRegion foldingRegion(const QTextBlock &startBlock);
+ QVector<FoldingRegion> foldingRegions;
+};
+
+}
+
+FoldingRegion SyntaxHighlighterPrivate::foldingRegion(const QTextBlock& startBlock)
+{
+ const auto data = dynamic_cast<TextBlockUserData*>(startBlock.userData());
+ if (!data)
+ return FoldingRegion();
+ for (int i = data->foldingRegions.size() - 1; i >= 0; --i) {
+ if (data->foldingRegions.at(i).type() == FoldingRegion::Begin)
+ return data->foldingRegions.at(i);
+ }
+ return FoldingRegion();
+}
+
+SyntaxHighlighter::SyntaxHighlighter(QObject* parent) :
+ QSyntaxHighlighter(parent),
+ AbstractHighlighter(new SyntaxHighlighterPrivate)
+{
+ qRegisterMetaType<QTextBlock>();
+}
+
+SyntaxHighlighter::SyntaxHighlighter(QTextDocument *document) :
+ QSyntaxHighlighter(document),
+ AbstractHighlighter(new SyntaxHighlighterPrivate)
+{
+ qRegisterMetaType<QTextBlock>();
+}
+
+SyntaxHighlighter::~SyntaxHighlighter()
+{
+}
+
+void SyntaxHighlighter::setDefinition(const Definition& def)
+{
+ const auto needsRehighlight = definition() != def;
+ AbstractHighlighter::setDefinition(def);
+ if (needsRehighlight)
+ rehighlight();
+}
+
+bool SyntaxHighlighter::startsFoldingRegion(const QTextBlock &startBlock) const
+{
+ return SyntaxHighlighterPrivate::foldingRegion(startBlock).type() == FoldingRegion::Begin;
+}
+
+QTextBlock SyntaxHighlighter::findFoldingRegionEnd(const QTextBlock &startBlock) const
+{
+ const auto region = SyntaxHighlighterPrivate::foldingRegion(startBlock);
+
+ auto block = startBlock;
+ int depth = 1;
+ while (block.isValid()) {
+ block = block.next();
+ const auto data = dynamic_cast<TextBlockUserData*>(block.userData());
+ if (!data)
+ continue;
+ for (auto it = data->foldingRegions.constBegin(); it != data->foldingRegions.constEnd(); ++it) {
+ if ((*it).id() != region.id())
+ continue;
+ if ((*it).type() == FoldingRegion::End)
+ --depth;
+ else if ((*it).type() == FoldingRegion::Begin)
+ ++depth;
+ if (depth == 0)
+ return block;
+ }
+ }
+
+ return QTextBlock();
+}
+
+void SyntaxHighlighter::highlightBlock(const QString& text)
+{
+ Q_D(SyntaxHighlighter);
+
+ State state;
+ if (currentBlock().position() > 0) {
+ const auto prevBlock = currentBlock().previous();
+ const auto prevData = dynamic_cast<TextBlockUserData*>(prevBlock.userData());
+ if (prevData)
+ state = prevData->state;
+ }
+ d->foldingRegions.clear();
+ state = highlightLine(text, state);
+
+ auto data = dynamic_cast<TextBlockUserData*>(currentBlockUserData());
+ if (!data) { // first time we highlight this
+ data = new TextBlockUserData;
+ data->state = state;
+ 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
+ return;
+ data->state = state;
+ data->foldingRegions = d->foldingRegions;
+
+ const auto nextBlock = currentBlock().next();
+ if (nextBlock.isValid())
+ QMetaObject::invokeMethod(this, "rehighlightBlock", Qt::QueuedConnection, Q_ARG(QTextBlock, nextBlock));
+}
+
+void SyntaxHighlighter::applyFormat(int offset, int length, const KSyntaxHighlighting::Format& format)
+{
+ if (format.isDefaultTextStyle(theme()) || length == 0)
+ return;
+
+ QTextCharFormat tf;
+ if (format.hasTextColor(theme()))
+ tf.setForeground(format.textColor(theme()));
+ 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);
+
+ QSyntaxHighlighter::setFormat(offset, length, tf);
+}
+
+void SyntaxHighlighter::applyFolding(int offset, int length, FoldingRegion region)
+{
+ Q_UNUSED(offset);
+ Q_UNUSED(length);
+ Q_D(SyntaxHighlighter);
+
+ if (region.type() == FoldingRegion::Begin)
+ d->foldingRegions.push_back(region);
+
+ if (region.type() == FoldingRegion::End) {
+ for (int i = d->foldingRegions.size() - 1; i >= 0; --i) {
+ if (d->foldingRegions.at(i).id() != region.id() || d->foldingRegions.at(i).type() != FoldingRegion::Begin)
+ continue;
+ d->foldingRegions.remove(i);
+ return;
+ }
+ d->foldingRegions.push_back(region);
+ }
+}
diff --git a/src/libs/3rdparty/syntax-highlighting/src/lib/syntaxhighlighter.h b/src/libs/3rdparty/syntax-highlighting/src/lib/syntaxhighlighter.h
new file mode 100644
index 0000000000..f5d2a5e219
--- /dev/null
+++ b/src/libs/3rdparty/syntax-highlighting/src/lib/syntaxhighlighter.h
@@ -0,0 +1,85 @@
+/*
+ Copyright (C) 2016 Volker Krause <vkrause@kde.org>
+
+ Permission is hereby granted, free of charge, to any person obtaining
+ a copy of this software and associated documentation files (the
+ "Software"), to deal in the Software without restriction, including
+ without limitation the rights to use, copy, modify, merge, publish,
+ distribute, sublicense, and/or sell copies of the Software, and to
+ permit persons to whom the Software is furnished to do so, subject to
+ the following conditions:
+
+ The above copyright notice and this permission notice shall be included
+ in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+#ifndef KSYNTAXHIGHLIGHTING_QSYNTAXHIGHLIGHTER_H
+#define KSYNTAXHIGHLIGHTING_QSYNTAXHIGHLIGHTER_H
+
+#include "ksyntaxhighlighting_export.h"
+
+#include "abstracthighlighter.h"
+
+#include <QSyntaxHighlighter>
+
+namespace KSyntaxHighlighting {
+
+class SyntaxHighlighterPrivate;
+
+/** A QSyntaxHighlighter implementation for use with QTextDocument.
+ * This supports partial re-highlighting during editing and
+ * tracks syntax-based code folding regions.
+ *
+ * @since 5.28
+ */
+class KSYNTAXHIGHLIGHTING_EXPORT SyntaxHighlighter : public QSyntaxHighlighter, public AbstractHighlighter
+{
+ Q_OBJECT
+public:
+ explicit SyntaxHighlighter(QObject *parent = nullptr);
+ explicit SyntaxHighlighter(QTextDocument *document);
+ ~SyntaxHighlighter() override;
+
+ void setDefinition(const Definition &def) override;
+
+ /** Returns whether there is a folding region beginning at @p startBlock.
+ * This only considers syntax-based folding regions,
+ * not indention-based ones as e.g. found in Python.
+ *
+ * @see findFoldingRegionEnd
+ */
+ bool startsFoldingRegion(const QTextBlock &startBlock) const;
+
+ /** Finds the end of the folding region starting at @p startBlock.
+ * If multiple folding regions begin at @p startBlock, the end of
+ * the last/innermost one is returned.
+ * This returns an invalid block if no folding region end is found,
+ * which typically indicates an unterminated region and thus folding
+ * until the document end.
+ * This method performs a sequential search starting at @p startBlock
+ * for the matching folding region end, which is a potentially expensive
+ * operation.
+ *
+ * @see startsFoldingRegion
+ */
+ QTextBlock findFoldingRegionEnd(const QTextBlock &startBlock) const;
+
+protected:
+ void highlightBlock(const QString & text) override;
+ void applyFormat(int offset, int length, const Format &format) override;
+ void applyFolding(int offset, int length, FoldingRegion region) override;
+
+private:
+ Q_DECLARE_PRIVATE_D(AbstractHighlighter::d_ptr, SyntaxHighlighter)
+};
+}
+
+#endif // KSYNTAXHIGHLIGHTING_QSYNTAXHIGHLIGHTER_H
diff --git a/src/libs/3rdparty/syntax-highlighting/src/lib/textstyledata_p.h b/src/libs/3rdparty/syntax-highlighting/src/lib/textstyledata_p.h
new file mode 100644
index 0000000000..40c5ef679e
--- /dev/null
+++ b/src/libs/3rdparty/syntax-highlighting/src/lib/textstyledata_p.h
@@ -0,0 +1,63 @@
+/*
+ Copyright (C) 2016 Volker Krause <vkrause@kde.org>
+
+ Permission is hereby granted, free of charge, to any person obtaining
+ a copy of this software and associated documentation files (the
+ "Software"), to deal in the Software without restriction, including
+ without limitation the rights to use, copy, modify, merge, publish,
+ distribute, sublicense, and/or sell copies of the Software, and to
+ permit persons to whom the Software is furnished to do so, subject to
+ the following conditions:
+
+ The above copyright notice and this permission notice shall be included
+ in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+#ifndef KSYNTAXHIGHLIGHTING_TEXTSTYLEDATA_P_H
+#define KSYNTAXHIGHLIGHTING_TEXTSTYLEDATA_P_H
+
+#include <QColor>
+
+namespace KSyntaxHighlighting {
+
+class TextStyleData
+{
+public:
+ // Constructor initializing all data.
+ TextStyleData()
+ : bold(false)
+ , italic(false)
+ , underline(false)
+ , strikeThrough(false)
+ , hasBold(false)
+ , hasItalic(false)
+ , hasUnderline(false)
+ , hasStrikeThrough(false)
+ {}
+
+ QRgb textColor = 0x0;
+ QRgb backgroundColor = 0x0;
+ QRgb selectedTextColor = 0x0;
+ QRgb selectedBackgroundColor = 0x0;
+ bool bold :1;
+ bool italic :1;
+ bool underline :1;
+ bool strikeThrough :1;
+
+ bool hasBold :1;
+ bool hasItalic :1;
+ bool hasUnderline :1;
+ bool hasStrikeThrough :1;
+};
+
+}
+
+#endif
diff --git a/src/libs/3rdparty/syntax-highlighting/src/lib/theme.cpp b/src/libs/3rdparty/syntax-highlighting/src/lib/theme.cpp
new file mode 100644
index 0000000000..57f62ef6ab
--- /dev/null
+++ b/src/libs/3rdparty/syntax-highlighting/src/lib/theme.cpp
@@ -0,0 +1,124 @@
+/*
+ Copyright (C) 2016 Volker Krause <vkrause@kde.org>
+
+ Permission is hereby granted, free of charge, to any person obtaining
+ a copy of this software and associated documentation files (the
+ "Software"), to deal in the Software without restriction, including
+ without limitation the rights to use, copy, modify, merge, publish,
+ distribute, sublicense, and/or sell copies of the Software, and to
+ permit persons to whom the Software is furnished to do so, subject to
+ the following conditions:
+
+ The above copyright notice and this permission notice shall be included
+ in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+#include "theme.h"
+#include "themedata_p.h"
+
+#include <QCoreApplication>
+
+using namespace KSyntaxHighlighting;
+
+Theme::Theme()
+{
+}
+
+Theme::Theme(const Theme &copy)
+{
+ m_data = copy.m_data;
+}
+
+Theme::Theme(ThemeData* data)
+ : m_data(data)
+{
+}
+
+Theme::~Theme()
+{
+}
+
+Theme &Theme::operator=(const Theme &other)
+{
+ m_data = other.m_data;
+ return *this;
+}
+
+bool Theme::isValid() const
+{
+ return m_data.data();
+}
+
+QString Theme::name() const
+{
+ return m_data ? m_data->name() : QString();
+}
+
+QString Theme::translatedName() const
+{
+ return m_data ? QCoreApplication::instance()->translate("Theme", m_data->name().toUtf8().constData())
+ : QString();
+}
+
+bool Theme::isReadOnly() const
+{
+ return m_data ? m_data->isReadOnly() : false;
+}
+
+QString Theme::filePath() const
+{
+ return m_data ? m_data->filePath() : QString();
+}
+
+QRgb Theme::textColor(TextStyle style) const
+{
+ return m_data ? m_data->textColor(style) : 0;
+}
+
+QRgb Theme::selectedTextColor(TextStyle style) const
+{
+ return m_data ? m_data->selectedTextColor(style) : 0;
+}
+
+QRgb Theme::backgroundColor(TextStyle style) const
+{
+ return m_data ? m_data->backgroundColor(style) : 0;
+}
+
+QRgb Theme::selectedBackgroundColor(TextStyle style) const
+{
+ return m_data ? m_data->selectedBackgroundColor(style) : 0;
+}
+
+bool Theme::isBold(TextStyle style) const
+{
+ return m_data ? m_data->isBold(style) : false;
+}
+
+bool Theme::isItalic(TextStyle style) const
+{
+ return m_data ? m_data->isItalic(style) : false;
+}
+
+bool Theme::isUnderline(TextStyle style) const
+{
+ return m_data ? m_data->isUnderline(style) : false;
+}
+
+bool Theme::isStrikeThrough(TextStyle style) const
+{
+ return m_data ? m_data->isStrikeThrough(style) : false;
+}
+
+QRgb Theme::editorColor(EditorColorRole role) const
+{
+ return m_data ? m_data->editorColor(role) : 0;
+}
diff --git a/src/libs/3rdparty/syntax-highlighting/src/lib/theme.h b/src/libs/3rdparty/syntax-highlighting/src/lib/theme.h
new file mode 100644
index 0000000000..adb8431f6a
--- /dev/null
+++ b/src/libs/3rdparty/syntax-highlighting/src/lib/theme.h
@@ -0,0 +1,378 @@
+/*
+ Copyright (C) 2016 Volker Krause <vkrause@kde.org>
+
+ Permission is hereby granted, free of charge, to any person obtaining
+ a copy of this software and associated documentation files (the
+ "Software"), to deal in the Software without restriction, including
+ without limitation the rights to use, copy, modify, merge, publish,
+ distribute, sublicense, and/or sell copies of the Software, and to
+ permit persons to whom the Software is furnished to do so, subject to
+ the following conditions:
+
+ The above copyright notice and this permission notice shall be included
+ in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+#ifndef KSYNTAXHIGHLIGHTING_THEME_H
+#define KSYNTAXHIGHLIGHTING_THEME_H
+
+#include "ksyntaxhighlighting_export.h"
+
+#include <QColor>
+#include <QExplicitlySharedDataPointer>
+#include <qobjectdefs.h>
+#include <QTypeInfo>
+
+namespace KSyntaxHighlighting {
+
+class ThemeData;
+class RepositoryPrivate;
+
+/**
+ * Color theme definition used for highlighting.
+ *
+ * @section theme_intro Introduction
+ *
+ * The Theme provides a full color theme for painting the highlighted text.
+ * One Theme is defined either as a *.theme file on disk, or as a file compiled
+ * into the SyntaxHighlighting library by using Qt's resource system. Each
+ * Theme has a unique name(), including a translatedName() if put into the UI.
+ * Themes shipped by default are typically read-only, see isReadOnly().
+ *
+ * A Theme defines two sets of colors:
+ * - Text colors, including foreground and background colors, colors for
+ * selected text, and properties such as bold and italic. These colors are
+ * used e.g. by the SyntaxHighlighter.
+ * - Editor colors, including a background color for the entire editor widget,
+ * the line number color, code folding colors, etc.
+ *
+ * @section theme_text_colors Text Colors and the Class Format
+ *
+ * The text colors are used for syntax highlighting.
+ * // TODO: elaborate more and explain relation to Format class
+ *
+ * @section theme_editor_colors Editor Colors
+ *
+ * If you want to use the SyntaxHighlighting framework to write your own text
+ * editor, you also need to paint the background of the editing widget. In
+ * addition, the editor may support showing line numbers, a folding bar, a
+ * highlight for the current text line, and similar features. All these colors
+ * are defined in terms of the "editor colors" and accessible by calling
+ * editorColor() with the desired enum EditorColorRole.
+ *
+ * @section theme_access Accessing a Theme
+ *
+ * All available Theme%s are accessed through the Repository. These themes are
+ * typically valid themes. If you create a Theme on your own, isValid() will
+ * return @e false, and all colors provided by this Theme are in fact invalid
+ * and therefore unusable.
+ *
+ * @see Format
+ * @since 5.28
+ */
+class KSYNTAXHIGHLIGHTING_EXPORT Theme
+{
+ Q_GADGET
+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
+ * combination with the EditorColorRole%s.
+ */
+ enum TextStyle {
+ //! Default text style for normal text and source code without
+ //! special highlighting.
+ Normal = 0,
+ //! Text style for language keywords.
+ Keyword,
+ //! Text style for function definitions and function calls.
+ Function,
+ //! Text style for variables, if applicable. For instance, variables in
+ //! PHP typically start with a '$', so all identifiers following the
+ //! pattern $foo are highlighted as variable.
+ Variable,
+ //! Text style for control flow highlighting, such as @e if, @e then,
+ //! @e else, @e return, or @e continue.
+ ControlFlow,
+ //! Text style for operators such as +, -, *, / and :: etc.
+ Operator,
+ //! Text style for built-in language classes and functions.
+ BuiltIn,
+ //! Text style for well-known extensions, such as Qt or boost.
+ Extension,
+ //! Text style for preprocessor statements.
+ Preprocessor,
+ //! Text style for attributes of functions or objects, e.g. \@override
+ //! in Java, or __declspec(...) and __attribute__((...)) in C++.
+ Attribute,
+ //! Text style for single characters such as 'a'.
+ Char,
+ //! Text style for escaped characters in strings, such as "hello\n".
+ SpecialChar,
+ //! Text style for strings, for instance "hello world".
+ String,
+ //! Text style for verbatim strings such as HERE docs.
+ VerbatimString,
+ //! Text style for special strings such as regular expressions in
+ //! ECMAScript or the LaTeX math mode.
+ SpecialString,
+ //! Text style for includes, imports, modules, or LaTeX packages.
+ Import,
+ //! Text style for data types such as int, char, float etc.
+ DataType,
+ //! Text style for decimal values.
+ DecVal,
+ //! Text style for numbers with base other than 10.
+ BaseN,
+ //! Text style for floating point numbers.
+ Float,
+ //! Text style for language constants, e.g. True, False, None in Python
+ //! or nullptr in C/C++.
+ Constant,
+ //! Text style for normal comments.
+ Comment,
+ //! Text style for comments that reflect API documentation, such as
+ //! doxygen /** */ comments.
+ Documentation,
+ //! Text style for annotations in comments, such as \@param in Doxygen
+ //! or JavaDoc.
+ Annotation,
+ //! Text style that refers to variables in a comment, such as after
+ //! \@param \<identifier\> in Doxygen or JavaDoc.
+ CommentVar,
+ //! Text style for region markers, typically defined by BEGIN/END.
+ RegionMarker,
+ //! Text style for information, such as the keyword \@note in Doxygen.
+ Information,
+ //! Text style for warnings, such as the keyword \@warning in Doxygen.
+ Warning,
+ //! Text style for comment specials such as TODO and WARNING in
+ //! comments.
+ Alert,
+ //! Text style indicating wrong syntax.
+ Error,
+ //! Text style for attributes that do not match any of the other default
+ //! styles.
+ Others
+ };
+ Q_ENUM(TextStyle)
+
+ /**
+ * Editor color roles, used to paint line numbers, editor background etc.
+ * The colors typically should have good contrast with the colors used
+ * in the TextStyle%s.
+ */
+ enum EditorColorRole {
+ //! Background color for the editing area.
+ BackgroundColor = 0,
+ //! Background color for selected text.
+ TextSelection,
+ //! Background color for the line of the current text cursor.
+ CurrentLine,
+ //! Background color for matching text while searching.
+ SearchHighlight,
+ //! Background color for replaced text for a search & replace action.
+ ReplaceHighlight,
+ //! Background color for matching bracket pairs (including quotes)
+ BracketMatching,
+ //! Foreground color for visualizing tabs and trailing spaces.
+ TabMarker,
+ //! Color used to underline spell check errors.
+ SpellChecking,
+ //! Color used to draw vertical indentation levels, typically a line.
+ IndentationLine,
+ //! Background color for the icon border.
+ IconBorder,
+ //! Background colors for code folding regions in the text area, as well
+ //! as code folding indicators in the code folding border.
+ CodeFolding,
+ //! Foreground color for drawing the line numbers. This should have a
+ //! good contrast with the IconBorder background color.
+ LineNumbers,
+ //! Foreground color for drawing the current line number. This should
+ //! have a good contrast with the IconBorder background color.
+ CurrentLineNumber,
+ //! Color used in the icon border to indicate dynamically wrapped lines.
+ //! This color should have a good contrast with the IconBorder
+ //! background color.
+ WordWrapMarker,
+ //! Color used to draw a vertical line for marking changed lines.
+ ModifiedLines,
+ //! Color used to draw a vertical line for marking saved lines.
+ SavedLines,
+ //! Line color used to draw separator lines, e.g. at column 80 in the
+ //! text editor area.
+ Separator,
+ //! Background color for bookmarks.
+ MarkBookmark,
+ //! Background color for active breakpoints.
+ MarkBreakpointActive,
+ //! Background color for a reached breakpoint.
+ MarkBreakpointReached,
+ //! Background color for inactive (disabled) breakpoints.
+ MarkBreakpointDisabled,
+ //! Background color for marking the current execution position.
+ MarkExecution,
+ //! Background color for general warning marks.
+ MarkWarning,
+ //! Background color for general error marks.
+ MarkError,
+ //! Background color for text templates (snippets).
+ TemplateBackground,
+ //! Background color for all editable placeholders in text templates.
+ TemplatePlaceholder,
+ //! Background color for the currently active placeholder in text
+ //! templates.
+ TemplateFocusedPlaceholder,
+ //! Background color for read-only placeholders in text templates.
+ TemplateReadOnlyPlaceholder
+ };
+ Q_ENUM(EditorColorRole)
+
+ /**
+ * Default constructor, creating an invalid Theme, see isValid().
+ */
+ Theme();
+
+ /**
+ * Copy constructor, sharing the Theme data with @p copy.
+ */
+ Theme(const Theme &copy);
+
+ /**
+ * Destructor.
+ */
+ ~Theme();
+
+ /**
+ * Assignment operator, sharing the Theme data with @p other.
+ */
+ Theme &operator=(const Theme &other);
+
+ /**
+ * Returns @c true if this is a valid Theme.
+ * If the theme is invalid, none of the returned colors are well-defined.
+ */
+ bool isValid() const;
+
+ /**
+ * Returns the unique name of this Theme.
+ * @see translatedName()
+ */
+ QString name() const;
+
+ /**
+ * Returns the translated name of this Theme. The translated name can be
+ * used in the user interface.
+ */
+ QString translatedName() const;
+
+ /**
+ * Returns @c true if this Theme is read-only.
+ *
+ * A Theme is read-only, if the filePath() points to a non-writable file.
+ * This is typically the case for Themes that are compiled into the executable
+ * as resource file, as well as for theme files that are installed in read-only
+ * system locations (e.g. /usr/share/).
+ */
+ bool isReadOnly() const;
+
+ /**
+ * Returns the full path and file name to this Theme.
+ * Themes from the Qt resource return the Qt resource path.
+ * Themes from disk return the local path.
+ *
+ * If the theme is invalid (isValid()), an empty string is returned.
+ */
+ QString filePath() const;
+
+ /**
+ * Returns the text color to be used for @p style.
+ * @c 0 is returned for styles that do not specify a text color,
+ * use the default text color in that case.
+ */
+ QRgb textColor(TextStyle style) const;
+
+ /**
+ * Returns the selected text color to be used for @p style.
+ * @c 0 is returned for styles that do not specify a selected text color,
+ * use the default textColor() in that case.
+ */
+ QRgb selectedTextColor(TextStyle style) const;
+
+ /**
+ * Returns the background color to be used for @p style.
+ * @c 0 is returned for styles that do not specify a background color,
+ * use the default background color in that case.
+ */
+ QRgb backgroundColor(TextStyle style) const;
+
+ /**
+ * Returns the background color to be used for selected text for @p style.
+ * @c 0 is returned for styles that do not specify a background color,
+ * use the default backgroundColor() in that case.
+ */
+ QRgb selectedBackgroundColor(TextStyle style) const;
+
+ /**
+ * Returns whether the given style should be shown in bold.
+ */
+ bool isBold(TextStyle style) const;
+
+ /**
+ * Returns whether the given style should be shown in italic.
+ */
+ bool isItalic(TextStyle style) const;
+
+ /**
+ * Returns whether the given style should be shown underlined.
+ */
+ bool isUnderline(TextStyle style) const;
+
+ /**
+ * Returns whether the given style should be shown struck through.
+ */
+ bool isStrikeThrough(TextStyle style) const;
+
+public:
+ /**
+ * Returns the editor color for the requested @p role.
+ */
+ QRgb editorColor(EditorColorRole role) const;
+
+private:
+ /**
+ * Constructor taking a shared ThemeData instance.
+ */
+ explicit Theme(ThemeData* data);
+ friend class RepositoryPrivate;
+ friend class ThemeData;
+
+private:
+ /**
+ * Shared data holder.
+ */
+ QExplicitlySharedDataPointer<ThemeData> m_data;
+};
+
+}
+
+QT_BEGIN_NAMESPACE
+Q_DECLARE_TYPEINFO(KSyntaxHighlighting::Theme, Q_MOVABLE_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
new file mode 100644
index 0000000000..eac9a92264
--- /dev/null
+++ b/src/libs/3rdparty/syntax-highlighting/src/lib/themedata.cpp
@@ -0,0 +1,255 @@
+/*
+ Copyright (C) 2016 Volker Krause <vkrause@kde.org>
+ Copyright (C) 2016 Dominik Haumann <dhaumann@kde.org>
+
+ Permission is hereby granted, free of charge, to any person obtaining
+ a copy of this software and associated documentation files (the
+ "Software"), to deal in the Software without restriction, including
+ without limitation the rights to use, copy, modify, merge, publish,
+ distribute, sublicense, and/or sell copies of the Software, and to
+ permit persons to whom the Software is furnished to do so, subject to
+ the following conditions:
+
+ The above copyright notice and this permission notice shall be included
+ in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+#include "themedata_p.h"
+#include "ksyntaxhighlighting_logging.h"
+
+#include <QFile>
+#include <QFileInfo>
+#include <QJsonDocument>
+#include <QJsonObject>
+#include <QJsonValue>
+#include <QMetaEnum>
+
+#include <QDebug>
+
+using namespace KSyntaxHighlighting;
+
+ThemeData* ThemeData::get(const Theme &theme)
+{
+ return theme.m_data.data();
+}
+
+ThemeData::ThemeData()
+{
+ memset(m_editorColors, 0, sizeof(m_editorColors));
+}
+
+/**
+ * Convert QJsonValue @p val into a color, if possible. Valid colors are only
+ * in hex format: #rrggbb. On error, returns 0x00000000.
+ */
+static inline QRgb readColor(const QJsonValue &val)
+{
+ const QRgb unsetColor = 0;
+ if (!val.isString()) {
+ return unsetColor;
+ }
+ const QString str = val.toString();
+ if (str.isEmpty() || str[0] != QLatin1Char('#')) {
+ return unsetColor;
+ }
+ const QColor color(str);
+ return color.isValid() ? color.rgb() : unsetColor;
+}
+
+static inline TextStyleData readThemeData(const QJsonObject &obj)
+{
+ TextStyleData td;
+
+ td.textColor = readColor(obj.value(QLatin1String("text-color")));
+ td.backgroundColor = readColor(obj.value(QLatin1String("background-color")));
+ td.selectedTextColor = readColor(obj.value(QLatin1String("selected-text-color")));
+ td.selectedBackgroundColor = readColor(obj.value(QLatin1String("selected-background-color")));
+
+ auto val = obj.value(QLatin1String("bold"));
+ if (val.isBool()) {
+ td.bold = val.toBool();
+ td.hasBold = true;
+ }
+ val = obj.value(QLatin1String("italic"));
+ if (val.isBool()) {
+ td.italic = val.toBool();
+ td.hasItalic = true;
+ }
+ val = obj.value(QLatin1String("underline"));
+ if (val.isBool()) {
+ td.underline = val.toBool();
+ td.hasUnderline = true;
+ }
+ val = obj.value(QLatin1String("strike-through"));
+ if (val.isBool()) {
+ td.strikeThrough = val.toBool();
+ td.hasStrikeThrough = true;
+ }
+
+ return td;
+}
+
+bool ThemeData::load(const QString &filePath)
+{
+ QFile loadFile(filePath);
+ if (!loadFile.open(QIODevice::ReadOnly)) {
+ return false;
+ }
+ 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" << filePath << ":" << parseError.errorString();
+ return false;
+ }
+
+ m_filePath = filePath;
+
+ QJsonObject obj = jsonDoc.object();
+
+ // read metadata
+ const QJsonObject metadata = obj.value(QLatin1String("metadata")).toObject();
+ m_name = metadata.value(QLatin1String("name")).toString();
+ m_revision = metadata.value(QLatin1String("revision")).toInt();
+
+ // read text styles
+ static const auto idx = Theme::staticMetaObject.indexOfEnumerator("TextStyle");
+ Q_ASSERT(idx >= 0);
+ const auto metaEnum = Theme::staticMetaObject.enumerator(idx);
+ const QJsonObject textStyles = obj.value(QLatin1String("text-styles")).toObject();
+ for (int i = 0; i < metaEnum.keyCount(); ++i) {
+ Q_ASSERT(i == metaEnum.value(i));
+ m_textStyles[i] = readThemeData(textStyles.value(QLatin1String(metaEnum.key(i))).toObject());
+ }
+
+ // read editor area colors
+ const QJsonObject editorColors = obj.value(QLatin1String("editor-colors")).toObject();
+ m_editorColors[Theme::BackgroundColor] = readColor(editorColors.value(QLatin1String("background-color")));
+ m_editorColors[Theme::TextSelection] = readColor(editorColors.value(QLatin1String("selection")));
+ m_editorColors[Theme::CurrentLine] = readColor(editorColors.value(QLatin1String("current-line")));
+ m_editorColors[Theme::SearchHighlight] = readColor(editorColors.value(QLatin1String("search-highlight")));
+ m_editorColors[Theme::ReplaceHighlight] = readColor(editorColors.value(QLatin1String("replace-highlight")));
+ m_editorColors[Theme::BracketMatching] = readColor(editorColors.value(QLatin1String("bracket-matching")));
+ m_editorColors[Theme::TabMarker] = readColor(editorColors.value(QLatin1String("tab-marker")));
+ m_editorColors[Theme::SpellChecking] = readColor(editorColors.value(QLatin1String("spell-checking")));
+ m_editorColors[Theme::IndentationLine] = readColor(editorColors.value(QLatin1String("indentation-line")));
+ m_editorColors[Theme::IconBorder] = readColor(editorColors.value(QLatin1String("icon-border")));
+ m_editorColors[Theme::CodeFolding] = readColor(editorColors.value(QLatin1String("code-folding")));
+ m_editorColors[Theme::LineNumbers] = readColor(editorColors.value(QLatin1String("line-numbers")));
+ m_editorColors[Theme::CurrentLineNumber] = readColor(editorColors.value(QLatin1String("current-line-number")));
+ m_editorColors[Theme::WordWrapMarker] = readColor(editorColors.value(QLatin1String("word-wrap-marker")));
+ m_editorColors[Theme::ModifiedLines] = readColor(editorColors.value(QLatin1String("modified-lines")));
+ m_editorColors[Theme::SavedLines] = readColor(editorColors.value(QLatin1String("saved-lines")));
+ m_editorColors[Theme::Separator] = readColor(editorColors.value(QLatin1String("separator")));
+ m_editorColors[Theme::MarkBookmark] = readColor(editorColors.value(QLatin1String("mark-bookmark")));
+ m_editorColors[Theme::MarkBreakpointActive] = readColor(editorColors.value(QLatin1String("mark-breakpoint-active")));
+ m_editorColors[Theme::MarkBreakpointReached] = readColor(editorColors.value(QLatin1String("mark-breakpoint-reached")));
+ m_editorColors[Theme::MarkBreakpointDisabled] = readColor(editorColors.value(QLatin1String("mark-breakpoint-disabled")));
+ m_editorColors[Theme::MarkExecution] = readColor(editorColors.value(QLatin1String("mark-execution")));
+ m_editorColors[Theme::MarkWarning] = readColor(editorColors.value(QLatin1String("mark-warning")));
+ m_editorColors[Theme::MarkError] = readColor(editorColors.value(QLatin1String("mark-error")));
+ m_editorColors[Theme::TemplateBackground] = readColor(editorColors.value(QLatin1String("template-background")));
+ m_editorColors[Theme::TemplatePlaceholder] = readColor(editorColors.value(QLatin1String("template-placeholder")));
+ m_editorColors[Theme::TemplateFocusedPlaceholder] = readColor(editorColors.value(QLatin1String("template-focused-placeholder")));
+ m_editorColors[Theme::TemplateReadOnlyPlaceholder] = readColor(editorColors.value(QLatin1String("template-read-only-placeholder")));
+
+ // read per-definition style overrides
+ const auto customStyles = obj.value(QLatin1String("custom-styles")).toObject();
+ for (auto it = customStyles.begin(); it != customStyles.end(); ++it) {
+ const auto obj = it.value().toObject();
+ QHash<QString, TextStyleData> overrideStyle;
+ for (auto it2 = obj.begin(); it2 != obj.end(); ++it2)
+ overrideStyle.insert(it2.key(), readThemeData(it2.value().toObject()));
+ m_textStyleOverrides.insert(it.key(), overrideStyle);
+ }
+
+ return true;
+}
+
+QString ThemeData::name() const
+{
+ return m_name;
+}
+
+int ThemeData::revision() const
+{
+ return m_revision;
+}
+
+bool ThemeData::isReadOnly() const
+{
+ return !QFileInfo(m_filePath).isWritable();
+}
+
+QString ThemeData::filePath() const
+{
+ return m_filePath;
+}
+
+QRgb ThemeData::textColor(Theme::TextStyle style) const
+{
+ Q_ASSERT(static_cast<int>(style) >= 0 && static_cast<int>(style) <= static_cast<int>(Theme::Others));
+ return m_textStyles[style].textColor;
+}
+
+QRgb ThemeData::selectedTextColor(Theme::TextStyle style) const
+{
+ Q_ASSERT(static_cast<int>(style) >= 0 && static_cast<int>(style) <= static_cast<int>(Theme::Others));
+ return m_textStyles[style].selectedTextColor;
+}
+
+QRgb ThemeData::backgroundColor(Theme::TextStyle style) const
+{
+ Q_ASSERT(static_cast<int>(style) >= 0 && static_cast<int>(style) <= static_cast<int>(Theme::Others));
+ return m_textStyles[style].backgroundColor;
+}
+
+QRgb ThemeData::selectedBackgroundColor(Theme::TextStyle style) const
+{
+ Q_ASSERT(static_cast<int>(style) >= 0 && static_cast<int>(style) <= static_cast<int>(Theme::Others));
+ return m_textStyles[style].selectedBackgroundColor;
+}
+
+bool ThemeData::isBold(Theme::TextStyle style) const
+{
+ Q_ASSERT(static_cast<int>(style) >= 0 && static_cast<int>(style) <= static_cast<int>(Theme::Others));
+ return m_textStyles[style].bold;
+}
+
+bool ThemeData::isItalic(Theme::TextStyle style) const
+{
+ Q_ASSERT(static_cast<int>(style) >= 0 && static_cast<int>(style) <= static_cast<int>(Theme::Others));
+ return m_textStyles[style].italic;
+}
+
+bool ThemeData::isUnderline(Theme::TextStyle style) const
+{
+ Q_ASSERT(static_cast<int>(style) >= 0 && static_cast<int>(style) <= static_cast<int>(Theme::Others));
+ return m_textStyles[style].underline;
+}
+
+bool ThemeData::isStrikeThrough(Theme::TextStyle style) const
+{
+ Q_ASSERT(static_cast<int>(style) >= 0 && static_cast<int>(style) <= static_cast<int>(Theme::Others));
+ return m_textStyles[style].strikeThrough;
+}
+
+QRgb ThemeData::editorColor(Theme::EditorColorRole role) const
+{
+ Q_ASSERT(static_cast<int>(role) >= 0 && static_cast<int>(role) <= static_cast<int>(Theme::TemplateReadOnlyPlaceholder));
+ return m_editorColors[role];
+}
+
+TextStyleData ThemeData::textStyleOverride(const QString& definitionName, const QString& attributeName) const
+{
+ return m_textStyleOverrides.value(definitionName).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
new file mode 100644
index 0000000000..3b5f4637a9
--- /dev/null
+++ b/src/libs/3rdparty/syntax-highlighting/src/lib/themedata_p.h
@@ -0,0 +1,170 @@
+/*
+ Copyright (C) 2016 Volker Krause <vkrause@kde.org>
+ Copyright (C) 2016 Dominik Haumann <dhaumann@kde.org>
+
+ Permission is hereby granted, free of charge, to any person obtaining
+ a copy of this software and associated documentation files (the
+ "Software"), to deal in the Software without restriction, including
+ without limitation the rights to use, copy, modify, merge, publish,
+ distribute, sublicense, and/or sell copies of the Software, and to
+ permit persons to whom the Software is furnished to do so, subject to
+ the following conditions:
+
+ The above copyright notice and this permission notice shall be included
+ in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+#ifndef KSYNTAXHIGHLIGHTING_THEMEDATA_P_H
+#define KSYNTAXHIGHLIGHTING_THEMEDATA_P_H
+
+#include "theme.h"
+#include "textstyledata_p.h"
+
+#include <QHash>
+#include <QSharedData>
+
+namespace KSyntaxHighlighting {
+
+/**
+ * Data container for a Theme.
+ */
+class ThemeData : public QSharedData
+{
+public:
+ static ThemeData* get(const Theme &theme);
+
+ /**
+ * Default constructor, creating an uninitialized ThemeData instance.
+ */
+ ThemeData();
+
+ /**
+ * Load the Theme data from the file @p filePath.
+ * Note, that @p filePath either is a local file, or a qt resource location.
+ */
+ bool load(const QString &filePath);
+
+ /**
+ * Returns the unique name of this Theme.
+ */
+ QString name() const;
+
+ /**
+ * Returns the revision of this Theme.
+ * The revision in a .theme file should be increased with every change.
+ */
+ int revision() const;
+
+ /**
+ * Returns @c true if this Theme is read-only.
+ * Typically, themes that are shipped by default are read-only.
+ */
+ bool isReadOnly() const;
+
+ /**
+ * Returns the full path and filename to this Theme.
+ * Themes from the Qt resource return the Qt resource path.
+ * Themes from disk return the local path.
+ *
+ * If the theme is invalid (isValid()), an empty string is returned.
+ */
+ QString filePath() const;
+
+ /**
+ * Returns the text color to be used for @p style.
+ * @c 0 is returned for styles that do not specify a text color,
+ * use the default text color in that case.
+ */
+ QRgb textColor(Theme::TextStyle style) const;
+
+ /**
+ * Returns the text color for selected to be used for @p style.
+ * @c 0 is returned for styles that do not specify a selected text color,
+ * use the textColor() in that case.
+ */
+ QRgb selectedTextColor(Theme::TextStyle style) const;
+
+ /**
+ * Returns the background color to be used for @p style.
+ * @c 0 is returned for styles that do not specify a background color,
+ * use the default background color in that case.
+ */
+ QRgb backgroundColor(Theme::TextStyle style) const;
+
+ /**
+ * Returns the background color for selected text to be used for @p style.
+ * @c 0 is returned for styles that do not specify a selected background
+ * color, use the default backgroundColor() in that case.
+ */
+ QRgb selectedBackgroundColor(Theme::TextStyle style) const;
+
+ /**
+ * Returns whether the given style should be shown in bold.
+ */
+ bool isBold(Theme::TextStyle style) const;
+
+ /**
+ * Returns whether the given style should be shown in italic.
+ */
+ bool isItalic(Theme::TextStyle style) const;
+
+ /**
+ * Returns whether the given style should be shown underlined.
+ */
+ bool isUnderline(Theme::TextStyle style) const;
+
+ /**
+ * Returns whether the given style should be shown struck through.
+ */
+ bool isStrikeThrough(Theme::TextStyle style) const;
+
+public:
+ /**
+ * Returns the editor color for the requested @p role.
+ */
+ QRgb editorColor(Theme::EditorColorRole role) const;
+
+ /**
+ * Returns the TextStyle override of a specific "itemData" with attributeName
+ * in the syntax definition called definitionName.
+ *
+ * If no override exists, a valid TextStyleData with the respective default
+ * TextStyle will be used, so the returned value is always valid.
+ */
+ TextStyleData textStyleOverride(const QString &definitionName, const QString &attributeName) const;
+
+private:
+ int m_revision = 0;
+ QString m_name;
+
+ //! Path to the file where the theme came from.
+ //! This is either a resource location (":/themes/Default.theme"), or a file
+ //! on disk (in a read-only or a writeable location).
+ QString m_filePath;
+
+ //! TextStyles
+ TextStyleData m_textStyles[Theme::Others + 1];
+
+ //! style overrides for individual itemData entries
+ //! definition name -> attribute name -> style
+ QHash<QString, QHash<QString, TextStyleData> > m_textStyleOverrides;
+
+ //! Editor area colors
+ QRgb m_editorColors[Theme::TemplateReadOnlyPlaceholder + 1];
+};
+
+}
+
+QT_BEGIN_NAMESPACE
+Q_DECLARE_TYPEINFO(KSyntaxHighlighting::TextStyleData, Q_MOVABLE_TYPE);
+QT_END_NAMESPACE
+
+#endif // KSYNTAXHIGHLIGHTING_THEMEDATA_P_H
diff --git a/src/libs/3rdparty/syntax-highlighting/src/lib/wildcardmatcher.cpp b/src/libs/3rdparty/syntax-highlighting/src/lib/wildcardmatcher.cpp
new file mode 100644
index 0000000000..167295a930
--- /dev/null
+++ b/src/libs/3rdparty/syntax-highlighting/src/lib/wildcardmatcher.cpp
@@ -0,0 +1,83 @@
+/*
+ Copyright (C) 2007 Sebastian Pipping <webmaster@hartwork.org>
+
+ Permission is hereby granted, free of charge, to any person obtaining
+ a copy of this software and associated documentation files (the
+ "Software"), to deal in the Software without restriction, including
+ without limitation the rights to use, copy, modify, merge, publish,
+ distribute, sublicense, and/or sell copies of the Software, and to
+ permit persons to whom the Software is furnished to do so, subject to
+ the following conditions:
+
+ The above copyright notice and this permission notice shall be included
+ in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+#include "wildcardmatcher_p.h"
+
+using namespace KSyntaxHighlighting;
+
+#include <QString>
+#include <QChar>
+
+static bool exactMatch(const QString &candidate, const QString &wildcard, int candidatePosFromRight,
+ int wildcardPosFromRight, bool caseSensitive = true)
+{
+ for (; wildcardPosFromRight >= 0; wildcardPosFromRight--) {
+ const auto ch = wildcard.at(wildcardPosFromRight).unicode();
+ switch (ch) {
+ case L'*':
+ if (candidatePosFromRight == -1) {
+ break;
+ }
+
+ if (wildcardPosFromRight == 0) {
+ return true;
+ }
+
+ // Eat all we can and go back as far as we have to
+ for (int j = -1; j <= candidatePosFromRight; j++) {
+ if (exactMatch(candidate, wildcard, j, wildcardPosFromRight - 1)) {
+ return true;
+ }
+ }
+ return false;
+
+ case L'?':
+ if (candidatePosFromRight == -1) {
+ return false;
+ }
+
+ candidatePosFromRight--;
+ break;
+
+ default:
+ if (candidatePosFromRight == -1) {
+ return false;
+ }
+
+ const auto candidateCh = candidate.at(candidatePosFromRight).unicode();
+ const auto match = caseSensitive ? (candidateCh == ch) : (QChar::toLower(candidateCh) == QChar::toLower(ch));
+ if (match) {
+ candidatePosFromRight--;
+ } else {
+ return false;
+ }
+ }
+ }
+ return true;
+}
+
+bool WildcardMatcher::exactMatch(const QString &candidate, const QString &wildcard,
+ bool caseSensitive)
+{
+ return ::exactMatch(candidate, wildcard, candidate.length() - 1, wildcard.length() - 1, caseSensitive);
+}
diff --git a/src/libs/3rdparty/syntax-highlighting/src/lib/wildcardmatcher_p.h b/src/libs/3rdparty/syntax-highlighting/src/lib/wildcardmatcher_p.h
new file mode 100644
index 0000000000..016b10fe66
--- /dev/null
+++ b/src/libs/3rdparty/syntax-highlighting/src/lib/wildcardmatcher_p.h
@@ -0,0 +1,51 @@
+/*
+ Copyright (C) 2007 Sebastian Pipping <webmaster@hartwork.org>
+
+ Permission is hereby granted, free of charge, to any person obtaining
+ a copy of this software and associated documentation files (the
+ "Software"), to deal in the Software without restriction, including
+ without limitation the rights to use, copy, modify, merge, publish,
+ distribute, sublicense, and/or sell copies of the Software, and to
+ permit persons to whom the Software is furnished to do so, subject to
+ the following conditions:
+
+ The above copyright notice and this permission notice shall be included
+ in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+#ifndef KSYNTAXHIGHLIGHTING_WILDCARDMATCHER_P_H
+#define KSYNTAXHIGHLIGHTING_WILDCARDMATCHER_P_H
+
+#include <QtGlobal>
+
+QT_BEGIN_NAMESPACE
+class QString;
+QT_END_NAMESPACE
+
+namespace KSyntaxHighlighting {
+
+namespace WildcardMatcher
+{
+ /**
+ * Matches a string against a given wildcard.
+ * The wildcard supports '*' (".*" in regex) and '?' ("." in regex), not more.
+ *
+ * @param candidate Text to match
+ * @param wildcard Wildcard to use
+ * @param caseSensitive Case-sensitivity flag
+ * @return True for an exact match, false otherwise
+ */
+ bool exactMatch(const QString &candidate, const QString &wildcard, bool caseSensitive = true);
+}
+
+}
+
+#endif // KSYNTAXHIGHLIGHTING_WILDCARDMATCHER_P_H
diff --git a/src/libs/3rdparty/syntax-highlighting/src/lib/xml_p.h b/src/libs/3rdparty/syntax-highlighting/src/lib/xml_p.h
new file mode 100644
index 0000000000..5f1f066dfd
--- /dev/null
+++ b/src/libs/3rdparty/syntax-highlighting/src/lib/xml_p.h
@@ -0,0 +1,42 @@
+/*
+ Copyright (C) 2016 Volker Krause <vkrause@kde.org>
+
+ Permission is hereby granted, free of charge, to any person obtaining
+ a copy of this software and associated documentation files (the
+ "Software"), to deal in the Software without restriction, including
+ without limitation the rights to use, copy, modify, merge, publish,
+ distribute, sublicense, and/or sell copies of the Software, and to
+ permit persons to whom the Software is furnished to do so, subject to
+ the following conditions:
+
+ The above copyright notice and this permission notice shall be included
+ in all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
+ IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
+ CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
+ TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
+ SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
+*/
+
+#ifndef KSYNTAXHIGHLIGHTING_XML_P_H
+#define KSYNTAXHIGHLIGHTING_XML_P_H
+
+#include <QString>
+
+namespace KSyntaxHighlighting {
+/** Utilities for XML parsing. */
+namespace Xml {
+
+/** Parse a xs:boolean attribute. */
+inline bool attrToBool(const QStringRef &str)
+{
+ return str == QLatin1String("1") || str.compare(QLatin1String("true"), Qt::CaseInsensitive) == 0;
+}
+
+}
+}
+
+#endif