mirror of
https://github.com/rizinorg/cutter.git
synced 2025-01-31 16:47:26 +00:00
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:
parent
f59e5bbc01
commit
4330b7ddaa
@ -78,6 +78,7 @@ SOURCES += \
|
|||||||
dialogs/SaveProjectDialog.cpp \
|
dialogs/SaveProjectDialog.cpp \
|
||||||
utils/TempConfig.cpp \
|
utils/TempConfig.cpp \
|
||||||
utils/SvgIconEngine.cpp \
|
utils/SvgIconEngine.cpp \
|
||||||
|
utils/SyntaxHighlighter.cpp \
|
||||||
widgets/PseudocodeWidget.cpp \
|
widgets/PseudocodeWidget.cpp \
|
||||||
widgets/VisualNavbar.cpp \
|
widgets/VisualNavbar.cpp \
|
||||||
widgets/GraphView.cpp \
|
widgets/GraphView.cpp \
|
||||||
@ -131,6 +132,7 @@ HEADERS += \
|
|||||||
dialogs/SaveProjectDialog.h \
|
dialogs/SaveProjectDialog.h \
|
||||||
utils/TempConfig.h \
|
utils/TempConfig.h \
|
||||||
utils/SvgIconEngine.h \
|
utils/SvgIconEngine.h \
|
||||||
|
utils/SyntaxHighlighter.h \
|
||||||
widgets/PseudocodeWidget.h \
|
widgets/PseudocodeWidget.h \
|
||||||
widgets/VisualNavbar.h \
|
widgets/VisualNavbar.h \
|
||||||
widgets/GraphView.h \
|
widgets/GraphView.h \
|
||||||
@ -165,7 +167,6 @@ FORMS += \
|
|||||||
widgets/SidebarWidget.ui \
|
widgets/SidebarWidget.ui \
|
||||||
widgets/HexdumpWidget.ui \
|
widgets/HexdumpWidget.ui \
|
||||||
dialogs/SaveProjectDialog.ui \
|
dialogs/SaveProjectDialog.ui \
|
||||||
widgets/PseudocodeWidget.ui \
|
|
||||||
dialogs/preferences/PreferencesDialog.ui \
|
dialogs/preferences/PreferencesDialog.ui \
|
||||||
dialogs/preferences/GeneralOptionsWidget.ui
|
dialogs/preferences/GeneralOptionsWidget.ui
|
||||||
|
|
||||||
|
102
src/utils/SyntaxHighlighter.cpp
Normal file
102
src/utils/SyntaxHighlighter.cpp
Normal 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);
|
||||||
|
}
|
||||||
|
}
|
34
src/utils/SyntaxHighlighter.h
Normal file
34
src/utils/SyntaxHighlighter.h
Normal 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;
|
||||||
|
};
|
@ -1,18 +1,23 @@
|
|||||||
#include "PseudocodeWidget.h"
|
#include "PseudocodeWidget.h"
|
||||||
#include "ui_PseudocodeWidget.h"
|
|
||||||
|
#include <QTextEdit>
|
||||||
|
|
||||||
#include "utils/Configuration.h"
|
#include "utils/Configuration.h"
|
||||||
#include "utils/Helpers.h"
|
#include "utils/Helpers.h"
|
||||||
|
#include "utils/SyntaxHighlighter.h"
|
||||||
#include "utils/TempConfig.h"
|
#include "utils/TempConfig.h"
|
||||||
|
|
||||||
PseudocodeWidget::PseudocodeWidget(QWidget *parent, Qt::WindowFlags flags) :
|
PseudocodeWidget::PseudocodeWidget(QWidget *parent, Qt::WindowFlags flags)
|
||||||
QDockWidget(parent, flags),
|
: QDockWidget(parent, flags)
|
||||||
ui(new Ui::PseudocodeWidget)
|
, textEditWidget(new QTextEdit(this))
|
||||||
|
, syntaxHighLighter( new SyntaxHighlighter(textEditWidget->document()))
|
||||||
{
|
{
|
||||||
ui->setupUi(this);
|
textEditWidget->setParent(this);
|
||||||
|
setWidget(textEditWidget);
|
||||||
setupFonts();
|
setupFonts();
|
||||||
colorsUpdatedSlot();
|
colorsUpdatedSlot();
|
||||||
|
textEditWidget->setReadOnly(true);
|
||||||
|
textEditWidget->setLineWrapMode(QTextEdit::NoWrap);
|
||||||
|
|
||||||
connect(Config(), SIGNAL(fontsUpdated()), this, SLOT(fontsUpdated()));
|
connect(Config(), SIGNAL(fontsUpdated()), this, SLOT(fontsUpdated()));
|
||||||
connect(Config(), SIGNAL(colorsUpdated()), this, SLOT(colorsUpdatedSlot()));
|
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(seekChanged(RVA)), this, SLOT(on_seekChanged(RVA)));
|
||||||
connect(Core(), SIGNAL(raisePrioritizedMemoryWidget(CutterCore::MemoryWidgetType)), this, SLOT(raisePrioritizedMemoryWidget(CutterCore::MemoryWidgetType)));
|
connect(Core(), SIGNAL(raisePrioritizedMemoryWidget(CutterCore::MemoryWidgetType)), this, SLOT(raisePrioritizedMemoryWidget(CutterCore::MemoryWidgetType)));
|
||||||
connect(this, &QDockWidget::visibilityChanged, this, [](bool visibility) {
|
connect(this, &QDockWidget::visibilityChanged, this, [](bool visibility) {
|
||||||
@ -62,12 +65,13 @@ void PseudocodeWidget::on_seekChanged(RVA addr)
|
|||||||
|
|
||||||
void PseudocodeWidget::refresh(RVA addr)
|
void PseudocodeWidget::refresh(RVA addr)
|
||||||
{
|
{
|
||||||
QString decompiledCode = Core()->getDecompiledCode(addr);
|
const QString& decompiledCode = Core()->getDecompiledCode(addr);
|
||||||
if (decompiledCode.length() == 0)
|
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()
|
void PseudocodeWidget::refreshPseudocode()
|
||||||
@ -86,7 +90,7 @@ void PseudocodeWidget::raisePrioritizedMemoryWidget(CutterCore::MemoryWidgetType
|
|||||||
void PseudocodeWidget::setupFonts()
|
void PseudocodeWidget::setupFonts()
|
||||||
{
|
{
|
||||||
QFont font = Config()->getFont();
|
QFont font = Config()->getFont();
|
||||||
ui->pseudocodeTextBrowser->setFont(font);
|
textEditWidget->setFont(font);
|
||||||
}
|
}
|
||||||
|
|
||||||
void PseudocodeWidget::fontsUpdated()
|
void PseudocodeWidget::fontsUpdated()
|
||||||
@ -96,8 +100,9 @@ void PseudocodeWidget::fontsUpdated()
|
|||||||
|
|
||||||
void PseudocodeWidget::colorsUpdatedSlot()
|
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("gui.background").name())
|
||||||
.arg(ConfigColor("btext").name());
|
.arg(ConfigColor("btext").name());
|
||||||
ui->pseudocodeTextBrowser->setStyleSheet(styleSheet);
|
textEditWidget->setStyleSheet(styleSheet);
|
||||||
}
|
}
|
||||||
|
@ -4,13 +4,11 @@
|
|||||||
#include <QDockWidget>
|
#include <QDockWidget>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
#include "ui_PseudocodeWidget.h"
|
|
||||||
#include "cutter.h"
|
#include "cutter.h"
|
||||||
|
|
||||||
namespace Ui
|
|
||||||
{
|
class QTextEdit;
|
||||||
class PseudocodeWidget;
|
class SyntaxHighlighter;
|
||||||
}
|
|
||||||
|
|
||||||
class PseudocodeWidget : public QDockWidget
|
class PseudocodeWidget : public QDockWidget
|
||||||
{
|
{
|
||||||
@ -21,20 +19,20 @@ public:
|
|||||||
explicit PseudocodeWidget(QWidget *parent = nullptr, Qt::WindowFlags flags = 0);
|
explicit PseudocodeWidget(QWidget *parent = nullptr, Qt::WindowFlags flags = 0);
|
||||||
~PseudocodeWidget();
|
~PseudocodeWidget();
|
||||||
|
|
||||||
private:
|
|
||||||
std::unique_ptr<Ui::PseudocodeWidget> ui;
|
|
||||||
void refresh(RVA addr);
|
|
||||||
void setupFonts();
|
|
||||||
|
|
||||||
signals:
|
|
||||||
|
|
||||||
public slots:
|
|
||||||
private slots:
|
private slots:
|
||||||
void on_seekChanged(RVA addr);
|
void on_seekChanged(RVA addr);
|
||||||
void raisePrioritizedMemoryWidget(CutterCore::MemoryWidgetType type);
|
void raisePrioritizedMemoryWidget(CutterCore::MemoryWidgetType type);
|
||||||
void fontsUpdated();
|
void fontsUpdated();
|
||||||
void colorsUpdatedSlot();
|
void colorsUpdatedSlot();
|
||||||
void refreshPseudocode();
|
void refreshPseudocode();
|
||||||
|
|
||||||
|
private:
|
||||||
|
void refresh(RVA addr);
|
||||||
|
void setupFonts();
|
||||||
|
|
||||||
|
private:
|
||||||
|
QTextEdit* textEditWidget;
|
||||||
|
SyntaxHighlighter* syntaxHighLighter;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif // PSEUDOCODEWIDGET_H
|
#endif // PSEUDOCODEWIDGET_H
|
||||||
|
@ -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>
|
|
Loading…
Reference in New Issue
Block a user