diff options
Diffstat (limited to 'Source/Core/DolphinQt/Debugger/GekkoSyntaxHighlight.cpp')
| -rw-r--r-- | Source/Core/DolphinQt/Debugger/GekkoSyntaxHighlight.cpp | 261 |
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); +} |
