Implemented syntax highlighter (#220)

* Implemented syntaxHighLighter
* removed PseudoWidget.ui
* buildfix
* reverted r2-submodule
* Added nowrap to the pseudocodeWidget
* changed color of functions in the pseudocode highlighter
This commit is contained in:
Properrr 2017-12-15 02:52:47 -08:00 committed by xarkes
parent f59e5bbc01
commit 4330b7ddaa
6 changed files with 168 additions and 55 deletions

View File

@ -78,6 +78,7 @@ SOURCES += \
dialogs/SaveProjectDialog.cpp \
utils/TempConfig.cpp \
utils/SvgIconEngine.cpp \
utils/SyntaxHighlighter.cpp \
widgets/PseudocodeWidget.cpp \
widgets/VisualNavbar.cpp \
widgets/GraphView.cpp \
@ -131,6 +132,7 @@ HEADERS += \
dialogs/SaveProjectDialog.h \
utils/TempConfig.h \
utils/SvgIconEngine.h \
utils/SyntaxHighlighter.h \
widgets/PseudocodeWidget.h \
widgets/VisualNavbar.h \
widgets/GraphView.h \
@ -165,7 +167,6 @@ FORMS += \
widgets/SidebarWidget.ui \
widgets/HexdumpWidget.ui \
dialogs/SaveProjectDialog.ui \
widgets/PseudocodeWidget.ui \
dialogs/preferences/PreferencesDialog.ui \
dialogs/preferences/GeneralOptionsWidget.ui

View File

@ -0,0 +1,102 @@
#include "SyntaxHighlighter.h"
SyntaxHighlighter::SyntaxHighlighter(QTextDocument *parent)
: QSyntaxHighlighter(parent)
, commentStartExpression("/\\*")
, commentEndExpression("\\*/")
{
HighlightingRule rule;
QStringList keywordPatterns;
//C language keywords
keywordPatterns << "\\bauto\\b" << "\\bdouble\\b" << "\\bint\\b"
<< "\\bstruct\\b" << "\\bbreak\\b" << "\\belse\\b"
<< "\\blong\\b" << "\\switch\\b" << "\\bcase\\b"
<< "\\benum\\b" << "\\bregister\\b" << "\\btypedef\\b"
<< "\\bchar\\b" << "\\bextern\\b" << "\\breturn\\b"
<< "\\bunion\\b" << "\\bconst\\b" << "\\bfloat\\b"
<< "\\bshort\\b" << "\\bunsigned\\b" << "\\bcontinue\\b"
<< "\\bfor\\b" << "\\bsigned\\b" << "\\bvoid\\b"
<< "\\bdefault\\b" << "\\bgoto\\b" << "\\bsizeof\\b"
<< "\\bvolatile\\b" << "\\bdo\\b" << "\\bif\\b"
<< "\\static\\b" << "\\while\\b";
//Special words
keywordPatterns << "\\bloc_*\\b" << "\\bsym.*\\b";
QTextCharFormat keywordFormat;
keywordFormat.setForeground(Qt::red);
keywordFormat.setFontWeight(QFont::Bold);
for( const auto& pattern : keywordPatterns )
{
rule.pattern.setPattern(pattern);
rule.format = keywordFormat;
highlightingRules.append(rule);
}
//Functions
rule.pattern.setPattern("\\b[A-Za-z0-9_]+(?=\\()");
rule.format.clearBackground();
rule.format.clearForeground();
rule.format.setFontItalic(true);
rule.format.setForeground(Qt::darkCyan);
highlightingRules.append(rule);
//single-line comment
rule.pattern.setPattern("//[^\n]*");
rule.format.clearBackground();
rule.format.clearForeground();
rule.format.setForeground(Qt::gray);
highlightingRules.append(rule);
//quotation
rule.pattern.setPattern("\".*\"");
rule.format.clearBackground();
rule.format.clearForeground();
rule.format.setForeground(Qt::darkGreen);
highlightingRules.append(rule);
multiLineCommentFormat.setForeground(Qt::gray);
}
void SyntaxHighlighter::highlightBlock(const QString&text)
{
for( const auto& it : highlightingRules )
{
auto matchIterator = it.pattern.globalMatch(text);
while (matchIterator.hasNext())
{
const auto match = matchIterator.next();
setFormat(match.capturedStart(), match.capturedLength(), it.format);
}
}
setCurrentBlockState(0);
int startIndex = 0;
if (previousBlockState() != 1)
{
startIndex = text.indexOf(commentStartExpression);
}
while (startIndex >= 0)
{
const auto match = commentEndExpression.match(text, startIndex);
const int endIndex = match.capturedStart();
int commentLength = 0;
if (endIndex == -1)
{
setCurrentBlockState(1);
commentLength = text.length() - startIndex;
}
else
{
commentLength = endIndex - startIndex
+ match.capturedLength();
}
setFormat(startIndex, commentLength, multiLineCommentFormat);
startIndex = text.indexOf(commentStartExpression, startIndex + commentLength);
}
}

View File

@ -0,0 +1,34 @@
#pragma once
#include <QSyntaxHighlighter>
#include <QVector>
#include <QTextDocument>
#include <QRegularExpression>
#include <QTextCharFormat>
class SyntaxHighlighter : public QSyntaxHighlighter
{
Q_OBJECT
public:
SyntaxHighlighter(QTextDocument *parent = nullptr);
virtual ~SyntaxHighlighter() = default;
protected:
void highlightBlock(const QString &text) override;
private:
struct HighlightingRule
{
QRegularExpression pattern;
QTextCharFormat format;
};
QVector<HighlightingRule> highlightingRules;
QRegularExpression commentStartExpression;
QRegularExpression commentEndExpression;
QTextCharFormat multiLineCommentFormat;
};

View File

@ -1,18 +1,23 @@
#include "PseudocodeWidget.h"
#include "ui_PseudocodeWidget.h"
#include <QTextEdit>
#include "utils/Configuration.h"
#include "utils/Helpers.h"
#include "utils/SyntaxHighlighter.h"
#include "utils/TempConfig.h"
PseudocodeWidget::PseudocodeWidget(QWidget *parent, Qt::WindowFlags flags) :
QDockWidget(parent, flags),
ui(new Ui::PseudocodeWidget)
PseudocodeWidget::PseudocodeWidget(QWidget *parent, Qt::WindowFlags flags)
: QDockWidget(parent, flags)
, textEditWidget(new QTextEdit(this))
, syntaxHighLighter( new SyntaxHighlighter(textEditWidget->document()))
{
ui->setupUi(this);
textEditWidget->setParent(this);
setWidget(textEditWidget);
setupFonts();
colorsUpdatedSlot();
textEditWidget->setReadOnly(true);
textEditWidget->setLineWrapMode(QTextEdit::NoWrap);
connect(Config(), SIGNAL(fontsUpdated()), this, SLOT(fontsUpdated()));
connect(Config(), SIGNAL(colorsUpdated()), this, SLOT(colorsUpdatedSlot()));
@ -27,8 +32,6 @@ PseudocodeWidget::PseudocodeWidget(QWidget *parent, Qt::WindowFlags flags) :
});
connect(Core(), SIGNAL(seekChanged(RVA)), this, SLOT(on_seekChanged(RVA)));
connect(Core(), SIGNAL(raisePrioritizedMemoryWidget(CutterCore::MemoryWidgetType)), this, SLOT(raisePrioritizedMemoryWidget(CutterCore::MemoryWidgetType)));
connect(this, &QDockWidget::visibilityChanged, this, [](bool visibility) {
@ -62,12 +65,13 @@ void PseudocodeWidget::on_seekChanged(RVA addr)
void PseudocodeWidget::refresh(RVA addr)
{
QString decompiledCode = Core()->getDecompiledCode(addr);
const QString& decompiledCode = Core()->getDecompiledCode(addr);
if (decompiledCode.length() == 0)
{
decompiledCode = tr("Cannot decompile at") + " " + RAddressString(addr) + " " + tr("(Not a function?)");
textEditWidget->setText(tr("Cannot decompile at") + " " + RAddressString(addr) + " " + tr("(Not a function?)"));
return;
}
ui->pseudocodeTextBrowser->setText(decompiledCode);
textEditWidget->setText(decompiledCode);
}
void PseudocodeWidget::refreshPseudocode()
@ -86,7 +90,7 @@ void PseudocodeWidget::raisePrioritizedMemoryWidget(CutterCore::MemoryWidgetType
void PseudocodeWidget::setupFonts()
{
QFont font = Config()->getFont();
ui->pseudocodeTextBrowser->setFont(font);
textEditWidget->setFont(font);
}
void PseudocodeWidget::fontsUpdated()
@ -96,8 +100,9 @@ void PseudocodeWidget::fontsUpdated()
void PseudocodeWidget::colorsUpdatedSlot()
{
QString styleSheet = QString("QTextBrowser { background-color: %1; color: %2; }")
const QString textEditClassName(textEditWidget->metaObject()->className());
QString styleSheet = QString(textEditClassName + " { background-color: %1; color: %2; }")
.arg(ConfigColor("gui.background").name())
.arg(ConfigColor("btext").name());
ui->pseudocodeTextBrowser->setStyleSheet(styleSheet);
textEditWidget->setStyleSheet(styleSheet);
}

View File

@ -4,13 +4,11 @@
#include <QDockWidget>
#include <memory>
#include "ui_PseudocodeWidget.h"
#include "cutter.h"
namespace Ui
{
class PseudocodeWidget;
}
class QTextEdit;
class SyntaxHighlighter;
class PseudocodeWidget : public QDockWidget
{
@ -21,20 +19,20 @@ public:
explicit PseudocodeWidget(QWidget *parent = nullptr, Qt::WindowFlags flags = 0);
~PseudocodeWidget();
private:
std::unique_ptr<Ui::PseudocodeWidget> ui;
void refresh(RVA addr);
void setupFonts();
signals:
public slots:
private slots:
void on_seekChanged(RVA addr);
void raisePrioritizedMemoryWidget(CutterCore::MemoryWidgetType type);
void fontsUpdated();
void colorsUpdatedSlot();
void refreshPseudocode();
private:
void refresh(RVA addr);
void setupFonts();
private:
QTextEdit* textEditWidget;
SyntaxHighlighter* syntaxHighLighter;
};
#endif // PSEUDOCODEWIDGET_H

View File

@ -1,27 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<ui version="4.0">
<class>PseudocodeWidget</class>
<widget class="QDockWidget" name="PseudocodeWidget">
<property name="geometry">
<rect>
<x>0</x>
<y>0</y>
<width>686</width>
<height>646</height>
</rect>
</property>
<property name="toolTipDuration">
<number>0</number>
</property>
<property name="windowTitle">
<string>Form</string>
</property>
<widget class="QTextBrowser" name="pseudocodeTextBrowser">
<property name="lineWrapMode">
<enum>QTextEdit::NoWrap</enum>
</property>
</widget>
</widget>
<resources/>
<connections/>
</ui>