diff options
Diffstat (limited to 'src/libs/3rdparty/syntax-highlighting/src/lib/syntaxhighlighter.cpp')
-rw-r--r-- | src/libs/3rdparty/syntax-highlighting/src/lib/syntaxhighlighter.cpp | 223 |
1 files changed, 148 insertions, 75 deletions
diff --git a/src/libs/3rdparty/syntax-highlighting/src/lib/syntaxhighlighter.cpp b/src/libs/3rdparty/syntax-highlighting/src/lib/syntaxhighlighter.cpp index 4987dc95f0..70b26a79bf 100644 --- a/src/libs/3rdparty/syntax-highlighting/src/lib/syntaxhighlighter.cpp +++ b/src/libs/3rdparty/syntax-highlighting/src/lib/syntaxhighlighter.cpp @@ -1,79 +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. + SPDX-FileCopyrightText: 2016 Volker Krause <vkrause@kde.org> + + SPDX-License-Identifier: MIT */ #include "syntaxhighlighter.h" #include "abstracthighlighter_p.h" #include "definition.h" +#include "definition_p.h" #include "foldingregion.h" #include "format.h" +#include "format_p.h" #include "state.h" #include "theme.h" - -#include <QDebug> +#include "themedata_p.h" Q_DECLARE_METATYPE(QTextBlock) using namespace KSyntaxHighlighting; -namespace KSyntaxHighlighting { +namespace KSyntaxHighlighting +{ class TextBlockUserData : public QTextBlockUserData { public: State state; - QVector<FoldingRegion> foldingRegions; + QList<FoldingRegion> foldingRegions; }; class SyntaxHighlighterPrivate : public AbstractHighlighterPrivate { public: static FoldingRegion foldingRegion(const QTextBlock &startBlock); - QVector<FoldingRegion> foldingRegions; + void initTextFormat(QTextCharFormat &tf, const Format &format); + void computeTextFormats(); + + struct TextFormat { + QTextCharFormat tf; + /** + * id to check that the format belongs to the definition + */ + std::intptr_t ptrId; + }; + + QList<FoldingRegion> foldingRegions; + std::vector<TextFormat> tfs; }; } -FoldingRegion SyntaxHighlighterPrivate::foldingRegion(const QTextBlock& startBlock) +FoldingRegion SyntaxHighlighterPrivate::foldingRegion(const QTextBlock &startBlock) { - const auto data = dynamic_cast<TextBlockUserData*>(startBlock.userData()); - if (!data) + 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) + if (data->foldingRegions.at(i).type() == FoldingRegion::Begin) { return data->foldingRegions.at(i); + } } return FoldingRegion(); } -SyntaxHighlighter::SyntaxHighlighter(QObject* parent) : - QSyntaxHighlighter(parent), - AbstractHighlighter(new SyntaxHighlighterPrivate) +void SyntaxHighlighterPrivate::initTextFormat(QTextCharFormat &tf, const Format &format) +{ + // always set the foreground color to avoid palette issues + tf.setForeground(format.textColor(m_theme)); + + if (format.hasBackgroundColor(m_theme)) { + tf.setBackground(format.backgroundColor(m_theme)); + } + if (format.isBold(m_theme)) { + tf.setFontWeight(QFont::Bold); + } + if (format.isItalic(m_theme)) { + tf.setFontItalic(true); + } + if (format.isUnderline(m_theme)) { + tf.setFontUnderline(true); + } + if (format.isStrikeThrough(m_theme)) { + tf.setFontStrikeOut(true); + } +} + +void SyntaxHighlighterPrivate::computeTextFormats() +{ + auto definitions = m_definition.includedDefinitions(); + definitions.append(m_definition); + + int maxId = 0; + for (const auto &definition : std::as_const(definitions)) { + for (const auto &format : std::as_const(DefinitionData::get(definition)->formats)) { + maxId = qMax(maxId, format.id()); + } + } + tfs.clear(); + tfs.resize(maxId + 1); + + // initialize tfs + for (const auto &definition : std::as_const(definitions)) { + for (const auto &format : std::as_const(DefinitionData::get(definition)->formats)) { + auto &tf = tfs[format.id()]; + tf.ptrId = FormatPrivate::ptrId(format); + initTextFormat(tf.tf, format); + } + } +} + +SyntaxHighlighter::SyntaxHighlighter(QObject *parent) + : QSyntaxHighlighter(parent) + , AbstractHighlighter(new SyntaxHighlighterPrivate) { qRegisterMetaType<QTextBlock>(); } -SyntaxHighlighter::SyntaxHighlighter(QTextDocument *document) : - QSyntaxHighlighter(document), - AbstractHighlighter(new SyntaxHighlighterPrivate) +SyntaxHighlighter::SyntaxHighlighter(QTextDocument *document) + : QSyntaxHighlighter(document) + , AbstractHighlighter(new SyntaxHighlighterPrivate) { qRegisterMetaType<QTextBlock>(); } @@ -82,12 +127,27 @@ SyntaxHighlighter::~SyntaxHighlighter() { } -void SyntaxHighlighter::setDefinition(const Definition& def) +void SyntaxHighlighter::setDefinition(const Definition &def) { - const auto needsRehighlight = definition() != def; - AbstractHighlighter::setDefinition(def); - if (needsRehighlight) + Q_D(SyntaxHighlighter); + + const auto needsRehighlight = d->m_definition != def; + if (DefinitionData::get(d->m_definition) != DefinitionData::get(def)) { + d->m_definition = def; + d->tfs.clear(); + } + if (needsRehighlight) { rehighlight(); + } +} + +void SyntaxHighlighter::setTheme(const Theme &theme) +{ + Q_D(SyntaxHighlighter); + if (ThemeData::get(d->m_theme) != ThemeData::get(theme)) { + d->m_theme = theme; + d->tfs.clear(); + } } bool SyntaxHighlighter::startsFoldingRegion(const QTextBlock &startBlock) const @@ -103,78 +163,87 @@ QTextBlock SyntaxHighlighter::findFoldingRegionEnd(const QTextBlock &startBlock) int depth = 1; while (block.isValid()) { block = block.next(); - const auto data = dynamic_cast<TextBlockUserData*>(block.userData()); - if (!data) + 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()) + } + for (const auto &foldingRegion : std::as_const(data->foldingRegions)) { + if (foldingRegion.id() != region.id()) { continue; - if ((*it).type() == FoldingRegion::End) + } + if (foldingRegion.type() == FoldingRegion::End) { --depth; - else if ((*it).type() == FoldingRegion::Begin) + } else if (foldingRegion.type() == FoldingRegion::Begin) { ++depth; - if (depth == 0) + } + if (depth == 0) { return block; + } } } return QTextBlock(); } -void SyntaxHighlighter::highlightBlock(const QString& text) +void SyntaxHighlighter::highlightBlock(const QString &text) { Q_D(SyntaxHighlighter); - State state; + static const State emptyState; + const State *previousState = &emptyState; if (currentBlock().position() > 0) { const auto prevBlock = currentBlock().previous(); - const auto prevData = dynamic_cast<TextBlockUserData*>(prevBlock.userData()); - if (prevData) - state = prevData->state; + const auto prevData = dynamic_cast<TextBlockUserData *>(prevBlock.userData()); + if (prevData) { + previousState = &prevData->state; + } } d->foldingRegions.clear(); - state = highlightLine(text, state); + auto newState = highlightLine(text, *previousState); - auto data = dynamic_cast<TextBlockUserData*>(currentBlockUserData()); + auto data = dynamic_cast<TextBlockUserData *>(currentBlockUserData()); if (!data) { // first time we highlight this data = new TextBlockUserData; - data->state = state; + data->state = std::move(newState); data->foldingRegions = d->foldingRegions; setCurrentBlockUserData(data); return; } - if (data->state == state && data->foldingRegions == d->foldingRegions) // we ended up in the same state, so we are done here + if (data->state == newState && data->foldingRegions == d->foldingRegions) { // we ended up in the same state, so we are done here return; - data->state = state; + } + data->state = std::move(newState); data->foldingRegions = d->foldingRegions; const auto nextBlock = currentBlock().next(); - if (nextBlock.isValid()) + if (nextBlock.isValid()) { QMetaObject::invokeMethod(this, "rehighlightBlock", Qt::QueuedConnection, Q_ARG(QTextBlock, nextBlock)); + } } -void SyntaxHighlighter::applyFormat(int offset, int length, const KSyntaxHighlighting::Format& format) +void SyntaxHighlighter::applyFormat(int offset, int length, const Format &format) { - if (length == 0) + if (length == 0) { return; + } - QTextCharFormat tf; - // always set the foreground color to avoid palette issues - tf.setForeground(format.textColor(theme())); + Q_D(SyntaxHighlighter); - if (format.hasBackgroundColor(theme())) - tf.setBackground(format.backgroundColor(theme())); - if (format.isBold(theme())) - tf.setFontWeight(QFont::Bold); - if (format.isItalic(theme())) - tf.setFontItalic(true); - if (format.isUnderline(theme())) - tf.setFontUnderline(true); - if (format.isStrikeThrough(theme())) - tf.setFontStrikeOut(true); + if (Q_UNLIKELY(d->tfs.empty())) { + d->computeTextFormats(); + } - QSyntaxHighlighter::setFormat(offset, length, tf); + const auto id = static_cast<std::size_t>(format.id()); + // This doesn't happen when format comes from the definition. + // But as the user can override the function to pass any format, this is a possible scenario. + if (id < d->tfs.size() && d->tfs[id].ptrId == FormatPrivate::ptrId(format)) { + QSyntaxHighlighter::setFormat(offset, length, d->tfs[id].tf); + } else { + QTextCharFormat tf; + d->initTextFormat(tf, format); + QSyntaxHighlighter::setFormat(offset, length, tf); + } } void SyntaxHighlighter::applyFolding(int offset, int length, FoldingRegion region) @@ -183,16 +252,20 @@ void SyntaxHighlighter::applyFolding(int offset, int length, FoldingRegion regio Q_UNUSED(length); Q_D(SyntaxHighlighter); - if (region.type() == FoldingRegion::Begin) + 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) + 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); } } + +#include "moc_syntaxhighlighter.cpp" |