Commit f304e018 authored by Aleix Pol Gonzalez's avatar Aleix Pol Gonzalez 🐧

Use SyntaxHighlighter for highlighting

Summary:
The code is especially fiddly and complex. Using this we can on the
other hand leverage other parts of our system.

Test Plan: Used, will upload screenshot

Reviewers: #plasma, sitter

Reviewed By: sitter

Subscribers: plasma-devel

Tags: #plasma

Differential Revision: https://phabricator.kde.org/D28234
parent 32b11e57
......@@ -27,7 +27,7 @@ find_package(Qt5 ${QT_MIN_VERSION} CONFIG REQUIRED COMPONENTS Core Widgets Test
find_package(KF5 ${KF5_MIN_VERSION} REQUIRED COMPONENTS I18n CoreAddons Service
ConfigWidgets JobWidgets KIO Crash Completion WidgetsAddons Wallet
Notifications IdleTime WindowSystem)
Notifications IdleTime WindowSystem SyntaxHighlighting)
find_package(Qt5X11Extras ${QT_MIN_VERSION} CONFIG)
set_package_properties(Qt5X11Extras PROPERTIES TYPE RECOMMENDED PURPOSE "Recommended for better integration on X11.")
......
......@@ -37,7 +37,6 @@ set(drkonqi_SRCS
ptracer.cpp
debuggermanager.cpp
applicationdetailsexamples.cpp
gdbhighlighter.cpp
statusnotifier.cpp
)
......@@ -104,6 +103,8 @@ target_link_libraries(DrKonqiInternal
KF5::Notifications # for status notifier
KF5::IdleTime # hide status notifier only if user saw it
KF5::SyntaxHighlighting # Backtrace Highlighting
drkonqi_backtrace_parser
qbugzilla
)
......
......@@ -21,9 +21,14 @@
#include <QLabel>
#include <QScrollBar>
#include <QDebug>
#include <KMessageBox>
#include <KLocalizedString>
#include <KSyntaxHighlighting/SyntaxHighlighter>
#include <KSyntaxHighlighting/Repository>
#include <KSyntaxHighlighting/Theme>
#include <KSyntaxHighlighting/Definition>
#include <qdesktopservices.h>
#include "drkonqi.h"
......@@ -33,7 +38,6 @@
#include "parser/backtraceparser.h"
#include "drkonqi_globals.h"
#include "debuggermanager.h"
#include "gdbhighlighter.h"
static const char extraDetailsLabelMargin[] = " margin: 5px; ";
......@@ -221,8 +225,14 @@ void BacktraceWidget::loadData()
// highlight if possible
if (m_btGenerator->debugger().codeName() == QLatin1String("gdb")) {
m_highlighter = new GdbHighlighter(ui.m_backtraceEdit->document(),
m_btGenerator->parser()->parsedBacktraceLines());
KSyntaxHighlighting::Repository repository;
m_highlighter = new KSyntaxHighlighting::SyntaxHighlighter(ui.m_backtraceEdit->document());
m_highlighter->setTheme((palette().color(QPalette::Base).lightness() < 128)
? repository.defaultTheme(KSyntaxHighlighting::Repository::DarkTheme)
: repository.defaultTheme(KSyntaxHighlighting::Repository::LightTheme));
const auto def = repository.definitionForName(QStringLiteral("GDB Backtrace"));
m_highlighter->setDefinition(def);
}
BacktraceParser * btParser = m_btGenerator->parser();
......@@ -322,11 +332,6 @@ void BacktraceWidget::loadData()
void BacktraceWidget::backtraceNewLine(const QString & line)
{
// We absolutely must not have a highlighter attached. The highlighter has
// a static list of lines to highlight from. When we are loading lines
// this static list does not match reality breaking text length expectations
// and resulting in segfaults.
Q_ASSERT(!m_highlighter);
//While loading the backtrace (unparsed) a new line was sent from the debugger, append it
ui.m_backtraceEdit->append(line.trimmed());
}
......
......@@ -25,7 +25,9 @@
#include "debugpackageinstaller.h"
#include "ui_backtracewidget.h"
class QSyntaxHighlighter;
namespace KSyntaxHighlighting {
class SyntaxHighlighter;
}
class BacktraceRatingWidget;
class BacktraceGenerator;
......@@ -54,7 +56,7 @@ private:
BacktraceGenerator * m_btGenerator = nullptr;
Ui::Form ui;
BacktraceRatingWidget * m_backtraceRatingWidget = nullptr;
QSyntaxHighlighter *m_highlighter = nullptr;
KSyntaxHighlighting::SyntaxHighlighter *m_highlighter = nullptr;
DebugPackageInstaller * m_debugPackageInstaller = nullptr;
void setAsLoading();
......
/*
Copyright (C) 2010 Milian Wolff <mail@milianw.de>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#include "gdbhighlighter.h"
#include <QRegularExpression>
#include <QTextDocument>
#include <KColorScheme>
GdbHighlighter::GdbHighlighter(QTextDocument* parent, const QList<BacktraceLine> & gdbLines)
: QSyntaxHighlighter(parent)
{
// setup line lookup
int l = 0;
foreach(const BacktraceLine& line, gdbLines) {
lines.insert(l, line);
l += line.toString().count(QLatin1Char('\n'));
}
// setup formats
KColorScheme scheme(QPalette::Active);
crashFormat.setForeground(scheme.foreground(KColorScheme::NegativeText));
nullptrFormat.setForeground(scheme.foreground(KColorScheme::NegativeText));
nullptrFormat.setFontWeight(QFont::Bold);
assertFormat = nullptrFormat;
threadFormat.setForeground(scheme.foreground(KColorScheme::NeutralText));
urlFormat.setForeground(scheme.foreground(KColorScheme::LinkText));
funcFormat.setForeground(scheme.foreground(KColorScheme::VisitedText));
funcFormat.setFontWeight(QFont::Bold);
otheridFormat.setForeground(scheme.foreground(KColorScheme::PositiveText));
crapFormat.setForeground(scheme.foreground(KColorScheme::InactiveText));
}
void GdbHighlighter::highlightBlock(const QString& text)
{
int cur = 0;
int next;
int diff;
const static QRegularExpression hexptrPattern(QStringLiteral("0x[0-9a-f]+"));
int lineNr = currentBlock().firstLineNumber();
while ( cur < text.length() ) {
next = text.indexOf(QLatin1Char('\n'), cur);
if (next == -1) {
next = text.length();
}
if (lineNr == 0) {
// line that contains 'Application: ...'
++lineNr;
cur = next;
continue;
}
diff = next - cur;
const QString lineStr = text.mid(cur, diff).append(QLatin1Char('\n'));
// -1 since we skip the first line
QMap< int, BacktraceLine >::iterator it = lines.lowerBound(lineNr - 1);
Q_ASSERT(it != lines.end());
// lowerbound would return the next higher item, even though we want the former one
if (it.key() > lineNr - 1) {
--it;
}
const BacktraceLine& line = it.value();
if (line.type() == BacktraceLine::KCrash) {
setFormat(cur, diff, crashFormat);
} else if (line.type() == BacktraceLine::ThreadStart || line.type() == BacktraceLine::ThreadIndicator) {
setFormat(cur, diff, threadFormat);
} else if (line.type() == BacktraceLine::Crap) {
setFormat(cur, diff, crapFormat);
} else if (line.type() == BacktraceLine::StackFrame) {
if (!line.fileName().isEmpty()) {
int colonPos = line.fileName().lastIndexOf(QLatin1Char(':'));
setFormat(lineStr.indexOf(line.fileName()), colonPos == -1 ? line.fileName().length() : colonPos, urlFormat);
}
if (!line.libraryName().isEmpty()) {
setFormat(lineStr.indexOf(line.libraryName()), line.libraryName().length(), urlFormat);
}
if (!line.functionName().isEmpty()) {
int idx = lineStr.indexOf(line.functionName());
if (idx != -1) {
// highlight Id::Id::Id::Func
// Id should have otheridFormat, :: no format and Func funcFormat
int i = idx;
int from = idx;
while (i < idx + line.functionName().length()) {
if (lineStr.at(i) == QLatin1Char(':')) {
setFormat(from, i - from, otheridFormat);
// skip ::
i += 2;
from = i;
continue;
} else if (lineStr.at(i) == QLatin1Char('<') || lineStr.at(i) == QLatin1Char('>')) {
setFormat(from, i - from, otheridFormat);
++i;
from = i;
continue;
}
++i;
}
if (line.functionName() == QLatin1String("qFatal") || line.functionName() == QLatin1String("abort") || line.functionName() == QLatin1String("__assert_fail")
|| line.functionName() == QLatin1String("*__GI___assert_fail") || line.functionName() == QLatin1String("*__GI_abort")) {
setFormat(from, i - from, assertFormat);
} else {
setFormat(from, i - from, funcFormat);
}
}
}
// highlight hexadecimal ptrs
QRegularExpressionMatchIterator iter = hexptrPattern.globalMatch(lineStr);
while (iter.hasNext()) {
const QRegularExpressionMatch match = iter.next();
if (match.captured(0) == QLatin1String("0x0")) {
setFormat(match.capturedStart(0), match.capturedLength(0), nullptrFormat);
}
}
}
cur = next;
++lineNr;
}
}
/*
Copyright (C) 2010 Milian Wolff <mail@milianw.de>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
*/
#ifndef GDBHIGHLIGHTER_H
#define GDBHIGHLIGHTER_H
#include <QSyntaxHighlighter>
#include "parser/backtraceline.h"
class GdbHighlighter : public QSyntaxHighlighter
{
public:
GdbHighlighter(QTextDocument* parent, const QList<BacktraceLine> & gdbLines);
protected:
void highlightBlock(const QString& text) override;
private:
QMap<int, BacktraceLine> lines;
QTextCharFormat crashFormat;
QTextCharFormat nullptrFormat;
QTextCharFormat assertFormat;
QTextCharFormat threadFormat;
QTextCharFormat urlFormat;
QTextCharFormat funcFormat;
QTextCharFormat otheridFormat;
QTextCharFormat crapFormat;
};
#endif // GDBHIGHLIGHTER_H
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment