summaryrefslogtreecommitdiff
path: root/Source/Core/DolphinQt/Debugger/GekkoSyntaxHighlight.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'Source/Core/DolphinQt/Debugger/GekkoSyntaxHighlight.cpp')
-rw-r--r--Source/Core/DolphinQt/Debugger/GekkoSyntaxHighlight.cpp261
1 files changed, 261 insertions, 0 deletions
diff --git a/Source/Core/DolphinQt/Debugger/GekkoSyntaxHighlight.cpp b/Source/Core/DolphinQt/Debugger/GekkoSyntaxHighlight.cpp
new file mode 100644
index 0000000000..cdbbcf550d
--- /dev/null
+++ b/Source/Core/DolphinQt/Debugger/GekkoSyntaxHighlight.cpp
@@ -0,0 +1,261 @@
+// Copyright 2023 Dolphin Emulator Project
+// SPDX-License-Identifier: GPL-2.0-or-later
+
+#include "DolphinQt/Debugger/GekkoSyntaxHighlight.h"
+
+#include "Common/Assembler/GekkoParser.h"
+
+#include <QLabel>
+#include <QPalette>
+
+namespace
+{
+using namespace Common::GekkoAssembler;
+using namespace Common::GekkoAssembler::detail;
+
+class HighlightParsePlugin : public ParsePlugin
+{
+public:
+ virtual ~HighlightParsePlugin() = default;
+
+ std::vector<std::pair<int, int>>&& MoveParens() { return std::move(m_matched_parens); }
+ std::vector<std::tuple<int, int, HighlightFormat>>&& MoveFormatting()
+ {
+ return std::move(m_formatting);
+ }
+
+ void OnDirectivePre(GekkoDirective) override { HighlightCurToken(HighlightFormat::Directive); }
+
+ void OnInstructionPre(const ParseInfo&, bool) override
+ {
+ HighlightCurToken(HighlightFormat::Mnemonic);
+ }
+
+ void OnTerminal(Terminal type, const AssemblerToken& val) override
+ {
+ switch (type)
+ {
+ case Terminal::Id:
+ HighlightCurToken(HighlightFormat::Symbol);
+ break;
+
+ case Terminal::Hex:
+ case Terminal::Dec:
+ case Terminal::Oct:
+ case Terminal::Bin:
+ case Terminal::Flt:
+ HighlightCurToken(HighlightFormat::Immediate);
+ break;
+
+ case Terminal::GPR:
+ HighlightCurToken(HighlightFormat::GPR);
+ break;
+
+ case Terminal::FPR:
+ HighlightCurToken(HighlightFormat::GPR);
+ break;
+
+ case Terminal::SPR:
+ HighlightCurToken(HighlightFormat::SPR);
+ break;
+
+ case Terminal::CRField:
+ HighlightCurToken(HighlightFormat::CRField);
+ break;
+
+ case Terminal::Lt:
+ case Terminal::Gt:
+ case Terminal::Eq:
+ case Terminal::So:
+ HighlightCurToken(HighlightFormat::CRFlag);
+ break;
+
+ case Terminal::Str:
+ HighlightCurToken(HighlightFormat::Str);
+ break;
+
+ default:
+ break;
+ }
+ }
+
+ void OnHiaddr(std::string_view) override
+ {
+ HighlightCurToken(HighlightFormat::Symbol);
+ auto&& [ha_pos, ha_tok] = m_owner->lexer.LookaheadTagRef(2);
+ m_formatting.emplace_back(static_cast<int>(ha_pos.col),
+ static_cast<int>(ha_tok.token_val.length()), HighlightFormat::HaLa);
+ }
+
+ void OnLoaddr(std::string_view id) override { OnHiaddr(id); }
+
+ void OnOpenParen(ParenType type) override
+ {
+ m_paren_stack.push_back(static_cast<int>(m_owner->lexer.ColNumber()));
+ }
+
+ void OnCloseParen(ParenType type) override
+ {
+ if (m_paren_stack.empty())
+ {
+ return;
+ }
+
+ m_matched_parens.emplace_back(m_paren_stack.back(),
+ static_cast<int>(m_owner->lexer.ColNumber()));
+ m_paren_stack.pop_back();
+ }
+
+ void OnError() override
+ {
+ m_formatting.emplace_back(static_cast<int>(m_owner->error->col),
+ static_cast<int>(m_owner->error->len), HighlightFormat::Error);
+ }
+
+ void OnLabelDecl(std::string_view name) override
+ {
+ const int len = static_cast<int>(m_owner->lexer.LookaheadRef().token_val.length());
+ const int off = static_cast<int>(m_owner->lexer.ColNumber());
+ m_formatting.emplace_back(len, off, HighlightFormat::Symbol);
+ }
+
+ void OnVarDecl(std::string_view name) override { OnLabelDecl(name); }
+
+private:
+ std::vector<int> m_paren_stack;
+ std::vector<std::pair<int, int>> m_matched_parens;
+ std::vector<std::tuple<int, int, HighlightFormat>> m_formatting;
+
+ void HighlightCurToken(HighlightFormat format)
+ {
+ const int len = static_cast<int>(m_owner->lexer.LookaheadRef().token_val.length());
+ const int off = static_cast<int>(m_owner->lexer.ColNumber());
+ m_formatting.emplace_back(off, len, format);
+ }
+};
+} // namespace
+
+void GekkoSyntaxHighlight::highlightBlock(const QString& text)
+{
+ BlockInfo* info = static_cast<BlockInfo*>(currentBlockUserData());
+ if (info == nullptr)
+ {
+ info = new BlockInfo;
+ setCurrentBlockUserData(info);
+ }
+
+ qsizetype comment_idx = text.indexOf(QLatin1Char('#'));
+ if (comment_idx != -1)
+ {
+ HighlightSubstr(comment_idx, text.length() - comment_idx, HighlightFormat::Comment);
+ }
+
+ if (m_mode == 0)
+ {
+ HighlightParsePlugin plugin;
+ ParseWithPlugin(&plugin, text.toStdString());
+
+ info->block_format = plugin.MoveFormatting();
+ info->parens = plugin.MoveParens();
+ info->error = std::move(plugin.Error());
+ info->error_at_eol = info->error && info->error->len == 0;
+ }
+ else if (m_mode == 1)
+ {
+ auto paren_it = std::find_if(info->parens.begin(), info->parens.end(),
+ [this](const std::pair<int, int>& p) {
+ return p.first == m_cursor_loc || p.second == m_cursor_loc;
+ });
+ if (paren_it != info->parens.end())
+ {
+ HighlightSubstr(paren_it->first, 1, HighlightFormat::Paren);
+ HighlightSubstr(paren_it->second, 1, HighlightFormat::Paren);
+ }
+ }
+
+ for (auto&& [off, len, format] : info->block_format)
+ {
+ HighlightSubstr(off, len, format);
+ }
+}
+
+GekkoSyntaxHighlight::GekkoSyntaxHighlight(QTextDocument* document, QTextCharFormat base_format,
+ bool dark_scheme)
+ : QSyntaxHighlighter(document), m_base_format(base_format)
+{
+ QPalette base_scheme;
+ m_theme_idx = dark_scheme ? 1 : 0;
+}
+
+void GekkoSyntaxHighlight::HighlightSubstr(int start, int len, HighlightFormat format)
+{
+ QTextCharFormat hl_format = m_base_format;
+ const QColor DIRECTIVE_COLOR[2] = {QColor(0x9d, 0x00, 0x06),
+ QColor(0xfb, 0x49, 0x34)}; // Gruvbox darkred
+ const QColor MNEMONIC_COLOR[2] = {QColor(0x79, 0x74, 0x0e),
+ QColor(0xb8, 0xbb, 0x26)}; // Gruvbox darkgreen
+ const QColor IMM_COLOR[2] = {QColor(0xb5, 0x76, 0x14),
+ QColor(0xfa, 0xbd, 0x2f)}; // Gruvbox darkyellow
+ const QColor BUILTIN_COLOR[2] = {QColor(0x07, 0x66, 0x78),
+ QColor(0x83, 0xa5, 0x98)}; // Gruvbox darkblue
+ const QColor HA_LA_COLOR[2] = {QColor(0xaf, 0x3a, 0x03),
+ QColor(0xfe, 0x80, 0x19)}; // Gruvbox darkorange
+ const QColor HOVER_BG_COLOR[2] = {QColor(0xd5, 0xc4, 0xa1),
+ QColor(0x50, 0x49, 0x45)}; // Gruvbox bg2
+ const QColor STRING_COLOR[2] = {QColor(0x98, 0x97, 0x1a),
+ QColor(0x98, 0x97, 0x1a)}; // Gruvbox green
+ const QColor COMMENT_COLOR[2] = {QColor(0x68, 0x9d, 0x6a),
+ QColor(0x68, 0x9d, 0x6a)}; // Gruvbox aqua
+
+ switch (format)
+ {
+ case HighlightFormat::Directive:
+ hl_format.setForeground(DIRECTIVE_COLOR[m_theme_idx]);
+ break;
+ case HighlightFormat::Mnemonic:
+ hl_format.setForeground(MNEMONIC_COLOR[m_theme_idx]);
+ break;
+ case HighlightFormat::Symbol:
+ break;
+ case HighlightFormat::Immediate:
+ hl_format.setForeground(IMM_COLOR[m_theme_idx]);
+ break;
+ case HighlightFormat::GPR:
+ hl_format.setForeground(BUILTIN_COLOR[m_theme_idx]);
+ break;
+ case HighlightFormat::FPR:
+ hl_format.setForeground(BUILTIN_COLOR[m_theme_idx]);
+ break;
+ case HighlightFormat::SPR:
+ hl_format.setForeground(BUILTIN_COLOR[m_theme_idx]);
+ break;
+ case HighlightFormat::CRField:
+ hl_format.setForeground(BUILTIN_COLOR[m_theme_idx]);
+ break;
+ case HighlightFormat::CRFlag:
+ hl_format.setForeground(BUILTIN_COLOR[m_theme_idx]);
+ break;
+ case HighlightFormat::Str:
+ hl_format.setForeground(STRING_COLOR[m_theme_idx]);
+ break;
+ case HighlightFormat::HaLa:
+ hl_format.setForeground(HA_LA_COLOR[m_theme_idx]);
+ break;
+ case HighlightFormat::Paren:
+ hl_format.setBackground(HOVER_BG_COLOR[m_theme_idx]);
+ break;
+ case HighlightFormat::Default:
+ hl_format.clearForeground();
+ hl_format.clearBackground();
+ break;
+ case HighlightFormat::Comment:
+ hl_format.setForeground(COMMENT_COLOR[m_theme_idx]);
+ break;
+ case HighlightFormat::Error:
+ hl_format.setUnderlineColor(Qt::red);
+ hl_format.setUnderlineStyle(QTextCharFormat::WaveUnderline);
+ break;
+ }
+
+ setFormat(start, len, hl_format);
+}