diff --git a/src/models/CMakeLists.txt b/src/models/CMakeLists.txt index e0ab27021..fc7f1c7aa 100644 --- a/src/models/CMakeLists.txt +++ b/src/models/CMakeLists.txt @@ -11,8 +11,9 @@ add_library( disassemblyoutput.cpp eventmodel.cpp filterandzoomstack.cpp + formattingutils.cpp frequencymodel.cpp - highlighter.cpp + highlightedtext.cpp processfiltermodel.cpp processlist_unix.cpp processmodel.cpp diff --git a/src/models/disassemblymodel.cpp b/src/models/disassemblymodel.cpp index 6d2a58e25..58d8bcfa4 100644 --- a/src/models/disassemblymodel.cpp +++ b/src/models/disassemblymodel.cpp @@ -6,22 +6,15 @@ SPDX-License-Identifier: GPL-2.0-or-later */ -#include -#include -#include - #include "disassemblymodel.h" -#include "highlighter.hpp" #include "search.h" #include "sourcecodemodel.h" DisassemblyModel::DisassemblyModel(KSyntaxHighlighting::Repository* repository, QObject* parent) : QAbstractTableModel(parent) - , m_document(new QTextDocument(this)) - , m_highlighter(new Highlighter(m_document, repository, this)) + , m_highlightedText(repository) { - m_document->setUndoRedoEnabled(false); } DisassemblyModel::~DisassemblyModel() = default; @@ -56,17 +49,13 @@ void DisassemblyModel::setDisassembly(const DisassemblyOutput& disassemblyOutput m_results = results; m_numTypes = results.selfCosts.numTypes(); - m_document->clear(); - - QTextCursor cursor(m_document); - cursor.beginEditBlock(); - for (const auto& it : disassemblyOutput.disassemblyLines) { - cursor.insertText(it.disassembly); - cursor.insertBlock(); - } - cursor.endEditBlock(); + QStringList assemblyLines; + assemblyLines.reserve(disassemblyOutput.disassemblyLines.size()); + std::transform(disassemblyOutput.disassemblyLines.cbegin(), disassemblyOutput.disassemblyLines.cend(), + std::back_inserter(assemblyLines), + [](const DisassemblyOutput::DisassemblyLine& line) { return line.disassembly; }); - m_document->setTextWidth(m_document->idealWidth()); + m_highlightedText.setText(assemblyLines); endResetModel(); } @@ -110,6 +99,7 @@ QVariant DisassemblyModel::data(const QModelIndex& index, int role) const } const auto& data = m_data.disassemblyLines.at(index.row()); + const auto& line = m_highlightedText.textAt(index.row()); if (role == AddrRole) return data.addr; @@ -123,10 +113,10 @@ QVariant DisassemblyModel::data(const QModelIndex& index, int role) const } else if (index.column() == BranchColumn) { return data.branchVisualisation; } else if (index.column() == DisassemblyColumn) { - const auto block = m_document->findBlockByLineNumber(index.row()); - if (role == SyntaxHighlightRole) - return QVariant::fromValue(block.layout()->lineAt(0)); - return block.text(); + if (role == SyntaxHighlightRole) { + return QVariant::fromValue(m_highlightedText.lineAt(index.row())); + } + return m_highlightedText.textAt(index.row()); } } @@ -149,7 +139,7 @@ QVariant DisassemblyModel::data(const QModelIndex& index, int role) const return totalCost; } else if (role == Qt::ToolTipRole) { auto tooltip = tr("addr: %1
assembly: %2
disassembly: %3") - .arg(QString::number(data.addr, 16), data.disassembly); + .arg(QString::number(data.addr, 16), line); return Util::formatTooltip(tooltip, locationCost, m_results.selfCosts); } @@ -158,8 +148,7 @@ QVariant DisassemblyModel::data(const QModelIndex& index, int role) const return Util::formatCostRelative(costLine, totalCost, true); } else { if (role == Qt::ToolTipRole) - return tr("%1
No samples at this location.
") - .arg(data.disassembly.toHtmlEscaped()); + return tr("%1
No samples at this location.
").arg(line.toHtmlEscaped()); else return QString(); } diff --git a/src/models/disassemblymodel.h b/src/models/disassemblymodel.h index 6b1be8fea..83853a378 100644 --- a/src/models/disassemblymodel.h +++ b/src/models/disassemblymodel.h @@ -14,9 +14,7 @@ #include "data.h" #include "disassemblyoutput.h" - -class QTextDocument; -class Highlighter; +#include "highlightedtext.h" namespace KSyntaxHighlighting { class Definition; @@ -47,9 +45,9 @@ class DisassemblyModel : public QAbstractTableModel Data::FileLine fileLineForIndex(const QModelIndex& index) const; QModelIndex indexForFileLine(const Data::FileLine& line) const; - Highlighter* highlighter() const + HighlightedText* highlightedText() { - return m_highlighter; + return &m_highlightedText; } enum Columns @@ -81,8 +79,7 @@ public slots: void find(const QString& search, Direction direction, int offset); private: - QTextDocument* m_document; - Highlighter* m_highlighter; + HighlightedText m_highlightedText; DisassemblyOutput m_data; Data::CallerCalleeResults m_results; int m_numTypes = 0; diff --git a/src/models/disassemblyoutput.cpp b/src/models/disassemblyoutput.cpp index 19ad25a86..e9d5559ee 100644 --- a/src/models/disassemblyoutput.cpp +++ b/src/models/disassemblyoutput.cpp @@ -17,28 +17,46 @@ #include #include +#include "formattingutils.h" + namespace { Q_LOGGING_CATEGORY(disassemblyoutput, "hotspot.disassemblyoutput") -bool canVisualizeJumps(const QString& objdump) +QString objdumpHelp(const QString& objdump) { QProcess process; process.setProcessChannelMode(QProcess::ForwardedErrorChannel); process.start(objdump, {QStringLiteral("-H")}); if (!process.waitForFinished(1000)) { qCWarning(disassemblyoutput) << "failed to query objdump help output:" << objdump << process.errorString(); - return false; + return {}; } const auto help = process.readAllStandardOutput(); - return help.contains("--visualize-jumps"); + return QString::fromUtf8(help); +} + +bool canVisualizeJumps(const QString& objdump) +{ + return objdumpHelp(objdump).contains(QStringLiteral("--visualize-jumps")); +} + +bool canUseSyntaxHighlighting(const QString& objdump) +{ + return objdumpHelp(objdump).contains(QStringLiteral("--disassembler-color")); } -DisassemblyOutput::LinkedFunction extractLinkedFunction(const QString& disassembly) +DisassemblyOutput::LinkedFunction extractLinkedFunction(const QString& disassemblyWithAnsi) { DisassemblyOutput::LinkedFunction function = {}; + const auto escapeChar = QLatin1Char('\u001B'); + + const auto disassembly = + disassemblyWithAnsi.contains(escapeChar) ? utils::removeAnsi(disassemblyWithAnsi) : disassemblyWithAnsi; + const auto leftBracketIndex = disassembly.indexOf(QLatin1Char('<')); const auto rightBracketIndex = disassembly.indexOf(QLatin1Char('>')); + if (leftBracketIndex != -1 && rightBracketIndex != -1) { if (leftBracketIndex < rightBracketIndex) { function.name = disassembly.mid(leftBracketIndex + 1, rightBracketIndex - leftBracketIndex - 1); @@ -61,6 +79,7 @@ DisassemblyOutput::LinkedFunction extractLinkedFunction(const QString& disassemb } } } + return function; } @@ -300,6 +319,12 @@ DisassemblyOutput DisassemblyOutput::disassemble(const QString& objdump, const Q else qCInfo(disassemblyoutput) << "objdump binary does not support `--visualize-jumps`:" << processPath; + if (canUseSyntaxHighlighting(processPath)) { + arguments.append(QStringLiteral("--disassembler-color=color")); + } else { + qCInfo(disassemblyoutput) << "objdump binary does not support `--disassembler-color`:" << processPath; + } + auto binary = findBinaryForSymbol(debugPaths, extraLibPaths, symbol); if (binary.isEmpty()) { disassemblyOutput.errorMessage += diff --git a/src/models/formattingutils.cpp b/src/models/formattingutils.cpp new file mode 100644 index 000000000..f7e6f836c --- /dev/null +++ b/src/models/formattingutils.cpp @@ -0,0 +1,24 @@ +/* + SPDX-FileCopyrightText: Lieven Hey + SPDX-FileCopyrightText: 2023 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com + + SPDX-License-Identifier: GPL-2.0-or-later +*/ + +#include "formattingutils.h" + +QString utils::removeAnsi(const QString& stringWithAnsi) +{ + const static QChar escapeChar = QLatin1Char('\u001B'); + if (!stringWithAnsi.contains(escapeChar)) { + return stringWithAnsi; + } + + QString ansiFreeString = stringWithAnsi; + while (ansiFreeString.contains(escapeChar)) { + const auto escapeStart = ansiFreeString.indexOf(escapeChar); + const auto escapeEnd = ansiFreeString.indexOf(QLatin1Char('m'), escapeStart); + ansiFreeString.remove(escapeStart, escapeEnd - escapeStart + 1); + } + return ansiFreeString; +} diff --git a/src/models/formattingutils.h b/src/models/formattingutils.h new file mode 100644 index 000000000..9af4dc91b --- /dev/null +++ b/src/models/formattingutils.h @@ -0,0 +1,14 @@ +/* + SPDX-FileCopyrightText: Lieven Hey + SPDX-FileCopyrightText: 2023 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com + + SPDX-License-Identifier: GPL-2.0-or-later +*/ + +#pragma once + +#include + +namespace utils { +QString removeAnsi(const QString& stringWithAnsi); +} diff --git a/src/models/highlightedtext.cpp b/src/models/highlightedtext.cpp new file mode 100644 index 000000000..a2f2bff05 --- /dev/null +++ b/src/models/highlightedtext.cpp @@ -0,0 +1,259 @@ +/* + SPDX-FileCopyrightText: Lieven Hey + SPDX-FileCopyrightText: 2023 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com + + SPDX-License-Identifier: GPL-2.0-or-later +*/ + +#include "highlightedtext.h" + +#include + +#include + +#include +#if KFSyntaxHighlighting_FOUND +#include +#include +#include +#include +#include +#include +#include +#endif + +#include "formattingutils.h" + +namespace { +#if KFSyntaxHighlighting_FOUND +class KSyntaxHighlightingImplementation : public HighlightingImplementation, + public KSyntaxHighlighting::AbstractHighlighter +{ +public: + KSyntaxHighlightingImplementation(KSyntaxHighlighting::Repository* repository) + : m_repository(repository) + { + } + ~KSyntaxHighlightingImplementation() override = default; + + QVector format(const QStringList& text) override + { + m_formats.clear(); + m_offset = 0; + + KSyntaxHighlighting::State state; + for (const auto& line : text) { + state = highlightLine(line, state); + + // KSyntaxHighlighting uses line offsets but QTextLayout uses global offsets + // the +1 is for the newline at the end of the line + m_offset += line.size() + 1; + } + + return m_formats; + } + + void themeChanged() override + { + if (!m_repository) { + return; + } + + KSyntaxHighlighting::Repository::DefaultTheme theme; + if (QPalette().base().color().lightness() < 128) { + theme = KSyntaxHighlighting::Repository::DarkTheme; + } else { + theme = KSyntaxHighlighting::Repository::LightTheme; + } + setTheme(m_repository->defaultTheme(theme)); + } + + void setHighlightingDefinition(const KSyntaxHighlighting::Definition& definition) override + { + setDefinition(definition); + } + +protected: + void applyFormat(int offset, int length, const KSyntaxHighlighting::Format& format) override + { + QTextCharFormat textCharFormat; + textCharFormat.setForeground(format.textColor(theme())); + m_formats.push_back({m_offset + offset, length, textCharFormat}); + } + +private: + KSyntaxHighlighting::Repository* m_repository; + QVector m_formats; + int m_offset = 0; +}; +#else +class KSyntaxHighlightingImplementation : public HighlightingImplementation +{ +public: + KSyntaxHighlightingImplementation(KSyntaxHighlighting::Repository*) = default; + ~KSyntaxHighlightingImplementation() override = default; + + QVector format(const QStringList& text) override + { + return {}; + } + + void themeChanged() override { } + + void setHighlightingDefinition(const KSyntaxHighlighting::Definition& /*definition*/) override { } +}; +#endif + +class AnsiHighlightingImplementation : public HighlightingImplementation +{ +public: + AnsiHighlightingImplementation() = default; + ~AnsiHighlightingImplementation() override = default; + + QVector format(const QStringList& text) override + { + QVector formats; + + int offset = 0; + QTextLayout::FormatRange format; + + for (const auto& line : text) { + for (auto c = line.cbegin(); c != line.cend(); c++) { + if (*c == QLatin1Char('\u001B')) { + // the strings log like this: + // \e[33m - set color + // \e[0m - clear color + // so we can grab the next two chars and check if we can convert them into a number + // if not -> clear format + + std::advance(c, 1); + Q_ASSERT(*c == QLatin1Char('[')); + + auto color = line.mid(std::distance(line.cbegin(), c) + 1, 2); + bool ok = false; + uint8_t colorCode = color.toUInt(&ok); + if (ok) { + // only support the 8 default colors + Q_ASSERT(colorCode >= 30 && colorCode <= 37); + + format.start = offset; + const auto colorRole = static_cast(colorCode - 30); + format.format.setForeground(m_colorScheme.foreground(colorRole)); + + std::advance(c, 3); + + // make sure that there are no additional codes + Q_ASSERT(*c == QLatin1Char('m')); + } else { + // make sure we have a reset sequence + Q_ASSERT(color == QStringLiteral("0m")); + format.length = offset - format.start; + formats.push_back(format); + + std::advance(c, 2); + } + } else { + offset++; + } + } + offset++; + } + + return formats; + } + + void themeChanged() override + { + m_colorScheme = KColorScheme(QPalette::Normal, KColorScheme::Complementary); + } + + void setHighlightingDefinition(const KSyntaxHighlighting::Definition& /*definition*/) override + { // not used since we use ansi sequences for highlighting + } + +private: + KColorScheme m_colorScheme; +}; +} + +HighlightedText::HighlightedText(KSyntaxHighlighting::Repository* repository, QObject* parent) + : QObject(parent) +#if KFSyntaxHighlighting_FOUND + , m_repository(repository) +#endif + , m_layout(std::make_unique()) +{ + m_layout->setCacheEnabled(true); + m_layout->setFont(QFontDatabase::systemFont(QFontDatabase::FixedFont)); +} + +HighlightedText::~HighlightedText() = default; + +void HighlightedText::setText(const QStringList& text) +{ + bool usesAnsi = std::any_of(text.cbegin(), text.cend(), + [](const QString& line) { return line.contains(QLatin1Char('\u001B')); }); + + if (usesAnsi) { + m_highlighter = std::make_unique(); + } else { + m_highlighter = std::make_unique(m_repository); + } + + m_highlighter->themeChanged(); + m_highlighter->format(text); + + m_lines.clear(); + + QString formattedText; + + for (const auto& line : text) { + const auto& ansiFreeLine = utils::removeAnsi(line); + m_lines.push_back(line); + const auto& lineWithNewline = QLatin1String("%1%2").arg(ansiFreeLine, QChar::LineSeparator); + formattedText += lineWithNewline; + } + + m_layout->setText(formattedText); + + applyFormatting(); +} + +void HighlightedText::setDefinition(const KSyntaxHighlighting::Definition& definition) +{ + Q_ASSERT(m_highlighter); + m_highlighter->setHighlightingDefinition(definition); + applyFormatting(); +} + +QString HighlightedText::textAt(int index) const +{ + Q_ASSERT(m_highlighter); + Q_ASSERT(index < m_lines.size()); + return m_lines.at(index); +} + +QTextLine HighlightedText::lineAt(int index) const +{ + Q_ASSERT(m_layout); + return m_layout->lineAt(index); +} + +void HighlightedText::applyFormatting() +{ + Q_ASSERT(m_highlighter); + + m_layout->setFormats(m_highlighter->format(m_lines)); + + m_layout->clearLayout(); + m_layout->beginLayout(); + + while (true) { + QTextLine line = m_layout->createLine(); + if (!line.isValid()) + break; + + line.setPosition(QPointF(0, 0)); + } + m_layout->endLayout(); +} diff --git a/src/models/highlightedtext.h b/src/models/highlightedtext.h new file mode 100644 index 000000000..c614e8a47 --- /dev/null +++ b/src/models/highlightedtext.h @@ -0,0 +1,59 @@ +/* + SPDX-FileCopyrightText: Lieven Hey + SPDX-FileCopyrightText: 2023 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com + + SPDX-License-Identifier: GPL-2.0-or-later +*/ + +#pragma once + +#include +#include +#include + +#include "hotspot-config.h" + +namespace KSyntaxHighlighting { +class SyntaxHighlighter; +class Definition; +class Repository; +} + +class HighlightingImplementation +{ + Q_DISABLE_COPY(HighlightingImplementation) +public: + HighlightingImplementation() = default; + virtual ~HighlightingImplementation() = default; + + virtual QVector format(const QStringList& text) = 0; + virtual void themeChanged() = 0; + virtual void setHighlightingDefinition(const KSyntaxHighlighting::Definition& definition) = 0; +}; + +class HighlightedText : public QObject +{ + Q_OBJECT +public: + HighlightedText(KSyntaxHighlighting::Repository* repository, QObject* parent = nullptr); + ~HighlightedText() override; + + void setText(const QStringList& text); + void setDefinition(const KSyntaxHighlighting::Definition& definition); + + QString textAt(int index) const; + QTextLine lineAt(int index) const; + +private slots: + void applyFormatting(); + +private: + void updateHighlighting(); + +#if KFSyntaxHighlighting_FOUND + KSyntaxHighlighting::Repository* m_repository; +#endif + std::unique_ptr m_highlighter; + std::unique_ptr m_layout; + QStringList m_lines; +}; diff --git a/src/models/highlighter.cpp b/src/models/highlighter.cpp deleted file mode 100644 index f8e8241cd..000000000 --- a/src/models/highlighter.cpp +++ /dev/null @@ -1,82 +0,0 @@ -/* - SPDX-FileCopyrightText: Lieven Hey - SPDX-FileCopyrightText: 2022 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com - - SPDX-License-Identifier: GPL-2.0-or-later -*/ - -#include "highlighter.hpp" - -#include -#include -#include -#include - -#if KFSyntaxHighlighting_FOUND -#include -#include -#include -#include -#endif - -Highlighter::Highlighter(QTextDocument* document, KSyntaxHighlighting::Repository* repository, QObject* parent) - : QObject(parent) -#if KFSyntaxHighlighting_FOUND - , m_highlighter(new KSyntaxHighlighting::SyntaxHighlighter(document)) - , m_repository(repository) -#endif -{ -#if !KFSyntaxHighlighting_FOUND - Q_UNUSED(repository); -#endif - document->setDefaultFont(QFontDatabase::systemFont(QFontDatabase::FixedFont)); - - // if qApp is used, UBSAN complains - QApplication::instance()->installEventFilter(this); - - updateColorTheme(); -} - -Highlighter::~Highlighter() = default; - -void Highlighter::setDefinition(const KSyntaxHighlighting::Definition& definition) -{ -#if KFSyntaxHighlighting_FOUND - // don't reparse if definition hasn't changed - if (m_currentDefinition == definition.name()) - return; - - m_highlighter->setDefinition(definition); - m_currentDefinition = definition.name(); - emit definitionChanged(m_currentDefinition); -#else - Q_UNUSED(definition); -#endif -} - -bool Highlighter::eventFilter(QObject* /*watched*/, QEvent* event) -{ - if (event->type() == QEvent::Type::ApplicationPaletteChange) { - updateColorTheme(); - } - - return false; -} - -void Highlighter::updateColorTheme() -{ -#if KFSyntaxHighlighting_FOUND - if (!m_repository) { - return; - } - - KSyntaxHighlighting::Repository::DefaultTheme theme; - if (QPalette().base().color().lightness() < 128) { - theme = KSyntaxHighlighting::Repository::DarkTheme; - } else { - theme = KSyntaxHighlighting::Repository::LightTheme; - } - m_highlighter->setTheme(m_repository->defaultTheme(theme)); - m_highlighter->rehighlight(); -#endif -} diff --git a/src/models/highlighter.hpp b/src/models/highlighter.hpp deleted file mode 100644 index 3966497a3..000000000 --- a/src/models/highlighter.hpp +++ /dev/null @@ -1,56 +0,0 @@ -/* - SPDX-FileCopyrightText: Lieven Hey - SPDX-FileCopyrightText: 2022 Klarälvdalens Datakonsult AB, a KDAB Group company, info@kdab.com - - SPDX-License-Identifier: GPL-2.0-or-later -*/ - -#pragma once - -#include "hotspot-config.h" - -#include - -#include - -class QTextDocument; - -namespace KSyntaxHighlighting { -class SyntaxHighlighter; -class Definition; -class Repository; -} - -class Highlighter : public QObject -{ - Q_OBJECT -public: - Highlighter(QTextDocument* document, KSyntaxHighlighting::Repository* repository, QObject* parent = nullptr); - ~Highlighter(); - - void setDefinition(const KSyntaxHighlighting::Definition& definition); - - QString definition() const - { -#if KFSyntaxHighlighting_FOUND - return m_currentDefinition; -#else - return {}; -#endif - } - -signals: - void definitionChanged(const QString& definition); - -protected: - bool eventFilter(QObject* watched, QEvent* event) override; - -private: - void updateColorTheme(); - -#if KFSyntaxHighlighting_FOUND - KSyntaxHighlighting::SyntaxHighlighter* m_highlighter = nullptr; - KSyntaxHighlighting::Repository* m_repository = nullptr; - QString m_currentDefinition; -#endif -}; diff --git a/src/models/sourcecodemodel.cpp b/src/models/sourcecodemodel.cpp index 5bf71eb88..b7b7e1d3a 100644 --- a/src/models/sourcecodemodel.cpp +++ b/src/models/sourcecodemodel.cpp @@ -18,7 +18,6 @@ #include #include -#include "highlighter.hpp" #include "search.h" #include @@ -26,10 +25,8 @@ Q_LOGGING_CATEGORY(sourcecodemodel, "hotspot.sourcecodemodel", QtWarningMsg) SourceCodeModel::SourceCodeModel(KSyntaxHighlighting::Repository* repository, QObject* parent) : QAbstractTableModel(parent) - , m_document(new QTextDocument(this)) - , m_highlighter(new Highlighter(m_document, repository, this)) + , m_highlightedText(repository) { - m_document->setUndoRedoEnabled(false); qRegisterMetaType(); } @@ -38,7 +35,7 @@ SourceCodeModel::~SourceCodeModel() = default; void SourceCodeModel::clear() { beginResetModel(); - m_document->clear(); + m_highlightedText.setText({}); endResetModel(); } @@ -56,19 +53,6 @@ void SourceCodeModel::setDisassembly(const DisassemblyOutput& disassemblyOutput, return; } - QFile file(disassemblyOutput.realSourceFileName); - if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) { - return; - } - - const auto sourceCode = QString::fromUtf8(file.readAll()); - - m_sourceCodeLines.clear(); - m_document->clear(); - - m_document->setPlainText(sourceCode); - m_document->setTextWidth(m_document->idealWidth()); - int maxLineNumber = 0; int minLineNumber = std::numeric_limits::max(); @@ -123,15 +107,16 @@ void SourceCodeModel::setDisassembly(const DisassemblyOutput& disassemblyOutput, m_startLine = minLineNumber - 1; // convert to index m_numLines = maxLineNumber - minLineNumber + 1; // include minLineNumber - m_sourceCodeLines.reserve(m_numLines); + QFile file(disassemblyOutput.realSourceFileName); + if (!file.open(QIODevice::ReadOnly | QIODevice::Text)) { + return; + } - for (int i = m_startLine; i < m_startLine + m_numLines; i++) { - auto block = m_document->findBlockByLineNumber(i); - if (!block.isValid()) - continue; + const auto sourceCode = QString::fromUtf8(file.readAll()); - m_sourceCodeLines.push_back({block.text(), block.layout()->lineAt(0)}); - } + m_lines = sourceCode.split(QLatin1Char('\n')); + + m_highlightedText.setText(m_lines); } QVariant SourceCodeModel::headerData(int section, Qt::Orientation orientation, int role) const @@ -183,9 +168,11 @@ QVariant SourceCodeModel::data(const QModelIndex& index, int role) const return m_prettySymbol; } - if (role == SyntaxHighlightRole) - return QVariant::fromValue(m_sourceCodeLines[index.row() - 1].line); - return m_sourceCodeLines[index.row() - 1].text; + int lineNumber = m_startLine + index.row() - 1; + if (role == SyntaxHighlightRole) { + return QVariant::fromValue(m_highlightedText.lineAt(lineNumber)); + } + return m_highlightedText.textAt(lineNumber); } if (index.column() == SourceCodeLineNumber) { @@ -264,13 +251,11 @@ void SourceCodeModel::setSysroot(const QString& sysroot) void SourceCodeModel::find(const QString& search, Direction direction, int current) { - auto searchFunc = [&search](const SourceCodeLine& line) { - return line.text.indexOf(search, 0, Qt::CaseInsensitive) != -1; - }; + auto searchFunc = [&search](const QString& line) { return line.indexOf(search, 0, Qt::CaseInsensitive) != -1; }; auto endReached = [this] { emit searchEndReached(); }; - const int resultIndex = ::search(m_sourceCodeLines, current, direction, searchFunc, endReached); + const int resultIndex = ::search(m_lines, current, direction, searchFunc, endReached); if (resultIndex >= 0) { emit resultFound(createIndex(resultIndex + 1, SourceCodeColumn)); diff --git a/src/models/sourcecodemodel.h b/src/models/sourcecodemodel.h index 4aa3e0bd4..994ad9332 100644 --- a/src/models/sourcecodemodel.h +++ b/src/models/sourcecodemodel.h @@ -9,27 +9,17 @@ #include "data.h" #include "disassemblyoutput.h" +#include "highlightedtext.h" #include #include #include -class QTextDocument; - -class Highlighter; - namespace KSyntaxHighlighting { class Repository; class Definition; } -struct SourceCodeLine -{ - QString text; - QTextLine line; -}; -Q_DECLARE_TYPEINFO(SourceCodeLine, Q_MOVABLE_TYPE); - enum class Direction; Q_DECLARE_METATYPE(QTextLine) @@ -53,9 +43,9 @@ class SourceCodeModel : public QAbstractTableModel Data::FileLine fileLineForIndex(const QModelIndex& index) const; QModelIndex indexForFileLine(const Data::FileLine& line) const; - Highlighter* highlighter() const + HighlightedText* highlightedText() { - return m_highlighter; + return &m_highlightedText; } enum Columns @@ -88,14 +78,13 @@ public slots: private: QString m_sysroot; QSet m_validLineNumbers; - QTextDocument* m_document = nullptr; - QVector m_sourceCodeLines; - Highlighter* m_highlighter = nullptr; + HighlightedText m_highlightedText; Data::Costs m_selfCosts; Data::Costs m_inclusiveCosts; QString m_mainSourceFileName; QString m_prettySymbol; int m_startLine = 0; int m_numLines = 0; + QStringList m_lines; int m_highlightLine = 0; }; diff --git a/src/resultsdisassemblypage.cpp b/src/resultsdisassemblypage.cpp index 8f98db35c..11436a0e7 100644 --- a/src/resultsdisassemblypage.cpp +++ b/src/resultsdisassemblypage.cpp @@ -32,7 +32,6 @@ #include "resultsutil.h" #if KFSyntaxHighlighting_FOUND -#include "highlighter.hpp" #include #include #include @@ -435,14 +434,14 @@ ResultsDisassemblyPage::ResultsDisassemblyPage(CostContextMenu* costContextMenu, completer->setCompletionMode(QCompleter::PopupCompletion); box->setCompleter(completer); box->setModel(definitionModel); - box->setCurrentText(model->highlighter()->definition()); + // box->setCurrentText(model->highlighter()->definition()); connect(box, qOverload(&QComboBox::activated), this, [this, model, box]() { - model->highlighter()->setDefinition(m_repository->definitionForName(box->currentText())); + model->highlightedText()->setDefinition(m_repository->definitionForName(box->currentText())); }); - - connect(model->highlighter(), &Highlighter::definitionChanged, - [box](const QString& definition) { box->setCurrentText(definition); }); + // TODO: this + // connect(model->highlightedText(), &HighlightedText::definitionChanged, + // [box](const QString& definition) { box->setCurrentText(definition); }); }; connectCompletion(ui->sourceCodeComboBox, m_sourceCodeModel); @@ -533,12 +532,6 @@ void ResultsDisassemblyPage::showDisassembly(const DisassemblyOutput& disassembl Q_ASSERT(!m_symbolStack.isEmpty()); const auto& curSymbol = m_symbolStack[m_stackIndex]; -#if KFSyntaxHighlighting_FOUND - m_sourceCodeModel->highlighter()->setDefinition( - m_repository->definitionForFileName(disassemblyOutput.mainSourceFileName)); - m_disassemblyModel->highlighter()->setDefinition(m_repository->definitionForName(QStringLiteral("GNU Assembler"))); -#endif - const auto& entry = m_callerCalleeResults.entry(curSymbol); ui->filenameLabel->setText(disassemblyOutput.mainSourceFileName); @@ -557,6 +550,13 @@ void ResultsDisassemblyPage::showDisassembly(const DisassemblyOutput& disassembl m_disassemblyModel->setDisassembly(disassemblyOutput, m_callerCalleeResults); m_sourceCodeModel->setDisassembly(disassemblyOutput, m_callerCalleeResults); +#if KFSyntaxHighlighting_FOUND + m_sourceCodeModel->highlightedText()->setDefinition( + m_repository->definitionForFileName(disassemblyOutput.mainSourceFileName)); + m_disassemblyModel->highlightedText()->setDefinition( + m_repository->definitionForName(QStringLiteral("GNU Assembler"))); +#endif + ResultsUtil::hideEmptyColumns(m_callerCalleeResults.selfCosts, ui->assemblyView, DisassemblyModel::COLUMN_COUNT); ResultsUtil::hideEmptyColumns(m_callerCalleeResults.selfCosts, ui->sourceCodeView, SourceCodeModel::COLUMN_COUNT);