dolphin/Source/Core/DolphinQt/Debugger/GekkoSyntaxHighlight.cpp
mitaclaw e4fb837f4b Modernize std::find_if with ranges
In BTEmu.cpp, `std::mem_fn` was not necessary for the predicate to compile.
2024-10-10 15:28:11 -07:00

253 lines
7.5 KiB
C++

// 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::FPR);
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::ranges::find_if(info->parens, [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:
case HighlightFormat::FPR:
case HighlightFormat::SPR:
case HighlightFormat::CRField:
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);
}