Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix multiline highlighting was ~add ci test for non optional build~ #594

Merged
merged 2 commits into from
Apr 15, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
103 changes: 76 additions & 27 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)
{
m_formats.clear();

for (const auto& line : text) {
m_formats.push_back(formatLine(line));
}
}

LineFormat format(int lineIndex) const
{
return {{QTextLayout::FormatRange {0, text.length(), {}}}};
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,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;
};

Expand All @@ -187,9 +229,11 @@ class HighlightedLine
{
public:
HighlightedLine() = default;
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 All @@ -209,11 +253,12 @@ class HighlightedLine
private:
std::unique_ptr<QTextLayout> buildLayout() const
{
Q_ASSERT(m_index != -1);
auto layout = std::make_unique<QTextLayout>();

layout->setFont(QFontDatabase::systemFont(QFontDatabase::FixedFont));
layout->setText(Util::removeAnsi(m_text));
layout->setFormats(m_highlighter->format(m_text));
layout->setText(m_text);
layout->setFormats(m_highlighter->format(m_index));

layout->beginLayout();

Expand All @@ -230,6 +275,7 @@ class HighlightedLine

HighlightingImplementation* m_highlighter = nullptr;
QString m_text;
int m_index = -1;
mutable std::unique_ptr<QTextLayout> m_layout;
};
static_assert(std::is_nothrow_move_constructible_v<HighlightedLine>);
Expand All @@ -239,6 +285,7 @@ HighlightedText::HighlightedText(KSyntaxHighlighting::Repository* repository, QO
: QObject(parent)
, m_repository(repository)
{
Q_UNUSED(repository);
}

HighlightedText::~HighlightedText() = default;
Expand All @@ -260,8 +307,10 @@ void HighlightedText::setText(const QStringList& text)
}

m_highlightedLines.resize(text.size());
std::transform(text.cbegin(), text.cend(), m_highlightedLines.begin(), [this](const QString& text) {
return HighlightedLine {m_highlighter.get(), text};
m_highlighter->formatText(text);
int index = 0;
std::transform(text.cbegin(), text.cend(), m_highlightedLines.begin(), [this, &index](const QString& text) {
return HighlightedLine {m_highlighter.get(), text, index++};
});

m_cleanedLines = text;
Expand Down
46 changes: 46 additions & 0 deletions tests/modeltests/tst_formatting.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,11 @@

#include "../testutils.h"

#if KFSyntaxHighlighting_FOUND
#include <KSyntaxHighlighting/Definition>
#include <KSyntaxHighlighting/Repository>
#endif

Q_DECLARE_METATYPE(QVector<QTextLayout::FormatRange>)

class TestFormatting : public QObject
Expand Down Expand Up @@ -83,6 +88,47 @@ private slots:
}
}
}

void testMultilineHighlighting()
{
#if KFSyntaxHighlighting_FOUND
const auto testfunc =
QStringList({QStringLiteral("int test() {"), QStringLiteral("/* A"), QStringLiteral(" * very"),
QStringLiteral(" * long"), QStringLiteral(" * comment */"), QStringLiteral("return 0;"),
QStringLiteral("}")});

auto repository = std::make_unique<KSyntaxHighlighting::Repository>();

HighlightedText text(repository.get());
text.setText(testfunc);
text.setDefinition(repository->definitionForFileName(QStringLiteral("test.cpp")));

// get formatting for line 2 (first commented line)
const auto formats = text.layoutForLine(1)->formats();
Q_ASSERT(!formats.empty());
const auto commentFormat = formats[0].format;

// ensure all other lines have the same format
for (int line = 2; line < 5; line++) {
const auto formats = text.layoutForLine(line)->formats();

for (const auto& format : formats) {
QCOMPARE(format.format, commentFormat);
}
}

{
// ensure that the last line (return 0;) is not formatted in the comment style
const auto formats = text.layoutForLine(5)->formats();

for (const auto& format : formats) {
QVERIFY(format.format != commentFormat);
}
}
#else
QSKIP("Test requires KSyntaxHighlighting");
#endif // KFSyntaxHighlighting_FOUND
}
};

HOTSPOT_GUITEST_MAIN(TestFormatting)
Expand Down
Loading