Skip to content

Commit

Permalink
don't reset KSyntaxhigHlighter state every line
Browse files Browse the repository at this point in the history
If the state is reset every line KSyntaxHighlighter will be unable to
highlight multi line comments (for example). This patch changes that by
highlighting everyting at once.
  • Loading branch information
lievenhey committed Jan 22, 2024
1 parent 5a974a4 commit f13a9e2
Showing 1 changed file with 76 additions and 30 deletions.
106 changes: 76 additions & 30 deletions src/models/highlightedtext.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,8 @@

#include "formattingutils.h"

using LineFormat = QVector<QTextLayout::FormatRange>;

#if KFSyntaxHighlighting_FOUND
// highlighter using KSyntaxHighlighting
class HighlightingImplementation : public KSyntaxHighlighting::AbstractHighlighter
Expand All @@ -38,13 +40,23 @@ class HighlightingImplementation : public KSyntaxHighlighting::AbstractHighlight
}
~HighlightingImplementation() override = default;

virtual QVector<QTextLayout::FormatRange> 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()
Expand All @@ -66,37 +78,57 @@ class HighlightingImplementation : public KSyntaxHighlighting::AbstractHighlight
virtual void setHighlightingDefinition(const KSyntaxHighlighting::Definition& definition)
{
setDefinition(definition);
formatText(m_lines);
}

virtual QString definitionName() const
{
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<QTextLayout::FormatRange> m_formats;
KSyntaxHighlighting::State m_state;
QStringList m_lines; // for reformatting if definition changes
LineFormat m_lineFormat;
QVector<LineFormat> 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<QTextLayout::FormatRange> 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() { }
Expand All @@ -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<LineFormat> m_formats;
};
#endif

Expand All @@ -118,7 +160,19 @@ class AnsiHighlightingImplementation : public HighlightingImplementation
}
~AnsiHighlightingImplementation() override = default;

QVector<QTextLayout::FormatRange> 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<QTextLayout::FormatRange> formats;

Expand Down Expand Up @@ -167,28 +221,17 @@ 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;
};

// QTextLayout is slow, this class acts as a cache that only creates and fills the QTextLayout on demand
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)
{
}
Expand Down Expand Up @@ -216,12 +259,10 @@ class HighlightedLine
if (!m_layout) {
m_layout = std::make_unique<QTextLayout>();
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
Expand All @@ -234,13 +275,15 @@ class HighlightedLine

HighlightingImplementation* m_highlighter;
QString m_text;
int m_index;
std::unique_ptr<QTextLayout> m_layout;
};

HighlightedText::HighlightedText(KSyntaxHighlighting::Repository* repository, QObject* parent)
: QObject(parent)
, m_repository(repository)
{
Q_UNUSED(repository);
}

HighlightedText::~HighlightedText() = default;
Expand All @@ -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);

Expand Down

0 comments on commit f13a9e2

Please sign in to comment.