diff --git a/src/models/highlightedtext.cpp b/src/models/highlightedtext.cpp index 21e606a8..9b4dfd61 100644 --- a/src/models/highlightedtext.cpp +++ b/src/models/highlightedtext.cpp @@ -27,6 +27,8 @@ #include "formattingutils.h" +using LineFormat = QVector; + #if KFSyntaxHighlighting_FOUND // highlighter using KSyntaxHighlighting class HighlightingImplementation : public KSyntaxHighlighting::AbstractHighlighter @@ -38,13 +40,23 @@ class HighlightingImplementation : public KSyntaxHighlighting::AbstractHighlight } ~HighlightingImplementation() override = default; - virtual QVector format(const QString& text) + void formatText(const QStringList& text) { + if (m_lines != text) { + m_lines = text; + } + m_formats.clear(); + m_state = {}; - highlightLine(text, {}); + for (const auto& line : text) { + m_formats.push_back(formatLine(line)); + } + } - return m_formats; + virtual LineFormat format(int lineIndex) const + { + return m_formats.at(lineIndex); } virtual void themeChanged() @@ -66,6 +78,7 @@ class HighlightingImplementation : public KSyntaxHighlighting::AbstractHighlight virtual void setHighlightingDefinition(const KSyntaxHighlighting::Definition& definition) { setDefinition(definition); + formatText(m_lines); } virtual QString definitionName() const @@ -73,30 +86,49 @@ class HighlightingImplementation : public KSyntaxHighlighting::AbstractHighlight return definition().name(); } + virtual LineFormat formatLine(const QString& line) + { + m_lineFormat.clear(); + m_state = highlightLine(line, m_state); + return m_lineFormat; + } + protected: void applyFormat(int offset, int length, const KSyntaxHighlighting::Format& format) override { QTextCharFormat textCharFormat; textCharFormat.setForeground(format.textColor(theme())); textCharFormat.setFontWeight(format.isBold(theme()) ? QFont::Bold : QFont::Normal); - m_formats.push_back({offset, length, textCharFormat}); + m_lineFormat.push_back({offset, length, textCharFormat}); } private: KSyntaxHighlighting::Repository* m_repository; - QVector m_formats; + KSyntaxHighlighting::State m_state; + QStringList m_lines; // for reformatting if definition changes + LineFormat m_lineFormat; + QVector m_formats; }; #else -// stub incase KSyntaxHighlighting is not available +// stub in case KSyntaxHighlighting is not available class HighlightingImplementation { public: HighlightingImplementation(KSyntaxHighlighting::Repository* /*repository*/) { } virtual ~HighlightingImplementation() = default; - virtual QVector format(const QString& /*text*/) + void formatText(const QStringList& text) { - return {}; + m_formats.clear(); + + for (const auto& line : text) { + m_formats.push_back(formatLine(line)); + } + } + + LineFormat format(int lineIndex) const + { + return m_formats.at(lineIndex); } virtual void themeChanged() { } @@ -105,7 +137,17 @@ class HighlightingImplementation virtual QString definitionName() const { return {}; + }; + +private: + // stub implementation necessary for testing + virtual LineFormat formatLine(const QString& line) + { + return {{QTextLayout::FormatRange {0, line.length(), {}}}}; } + + Q_DISABLE_COPY(HighlightingImplementation) + QVector m_formats; }; #endif @@ -118,7 +160,19 @@ class AnsiHighlightingImplementation : public HighlightingImplementation } ~AnsiHighlightingImplementation() override = default; - QVector format(const QString& text) final + void themeChanged() override + { + m_colorScheme = KColorScheme(QPalette::Normal, KColorScheme::Complementary); + } + + void setHighlightingDefinition(const KSyntaxHighlighting::Definition& /*definition*/) override { } + QString definitionName() const override + { + return {}; + } + +private: + LineFormat formatLine(const QString& text) override { QVector formats; @@ -167,18 +221,6 @@ class AnsiHighlightingImplementation : public HighlightingImplementation return formats; } - void themeChanged() override - { - m_colorScheme = KColorScheme(QPalette::Normal, KColorScheme::Complementary); - } - - void setHighlightingDefinition(const KSyntaxHighlighting::Definition& /*definition*/) override { } - QString definitionName() const override - { - return {}; - } - -private: KColorScheme m_colorScheme; }; @@ -186,9 +228,10 @@ class AnsiHighlightingImplementation : public HighlightingImplementation class HighlightedLine { public: - HighlightedLine(HighlightingImplementation* highlighter, QString text) + HighlightedLine(HighlightingImplementation* highlighter, const QString& text, int index) : m_highlighter(highlighter) - , m_text(std::move(text)) + , m_text(Util::removeAnsi(text)) + , m_index(index) , m_layout(nullptr) { } @@ -216,12 +259,10 @@ class HighlightedLine if (!m_layout) { m_layout = std::make_unique(); m_layout->setFont(QFontDatabase::systemFont(QFontDatabase::FixedFont)); - const auto& ansiFreeLine = Util::removeAnsi(m_text); - m_layout->setText(ansiFreeLine); + m_layout->setText(m_text); } - m_layout->setFormats(m_highlighter->format(m_text)); - + m_layout->setFormats(m_highlighter->format(m_index)); m_layout->beginLayout(); // there is at most one line, so we don't need to check this multiple times @@ -234,6 +275,7 @@ class HighlightedLine HighlightingImplementation* m_highlighter; QString m_text; + int m_index; std::unique_ptr m_layout; }; @@ -241,6 +283,7 @@ HighlightedText::HighlightedText(KSyntaxHighlighting::Repository* repository, QO : QObject(parent) , m_repository(repository) { + Q_UNUSED(repository); } HighlightedText::~HighlightedText() = default; @@ -262,9 +305,12 @@ void HighlightedText::setText(const QStringList& text) } m_highlightedLines.reserve(text.size()); - std::transform(text.cbegin(), text.cend(), std::back_inserter(m_highlightedLines), [this](const QString& text) { - return HighlightedLine {m_highlighter.get(), text}; - }); + m_highlighter->formatText(text); + int index = 0; + std::transform(text.cbegin(), text.cend(), std::back_inserter(m_highlightedLines), + [this, &index](const QString& text) { + return HighlightedLine {m_highlighter.get(), text, index++}; + }); connect(this, &HighlightedText::definitionChanged, this, &HighlightedText::updateHighlighting);