diff --git a/rpcs3/rpcs3qt/log_frame.cpp b/rpcs3/rpcs3qt/log_frame.cpp index 7689aa8f9c..e77a847c78 100644 --- a/rpcs3/rpcs3qt/log_frame.cpp +++ b/rpcs3/rpcs3qt/log_frame.cpp @@ -132,8 +132,6 @@ log_frame::log_frame(std::shared_ptr _gui_settings, QWidget* paren m_tty->setContextMenuPolicy(Qt::CustomContextMenu); m_tty->document()->setMaximumBlockCount(max_block_count_tty); m_tty->installEventFilter(this); - - m_tty_ansi_highlighter = new AnsiHighlighter(m_tty->document()); m_tty_input = new QLineEdit(); if (m_tty_channel >= 0) @@ -164,6 +162,11 @@ log_frame::log_frame(std::shared_ptr _gui_settings, QWidget* paren CreateAndConnectActions(); LoadSettings(); + if (m_ansi_tty) + { + m_tty_ansi_highlighter = new AnsiHighlighter(m_tty->document()); + } + m_timer = new QTimer(this); connect(m_timer, &QTimer::timeout, this, &log_frame::UpdateUI); } @@ -291,6 +294,16 @@ void log_frame::CreateAndConnectActions() { m_gui_settings->SetValue(gui::l_ansi_code, checked); m_ansi_tty = checked; + + if (!m_tty_ansi_highlighter) + { + m_tty_ansi_highlighter = new AnsiHighlighter(m_tty->document()); + } + else + { + delete m_tty_ansi_highlighter; + m_tty_ansi_highlighter = nullptr; + } }); m_tty_channel_acts = new QActionGroup(this); @@ -602,13 +615,15 @@ void log_frame::UpdateUI() buf_line.assign(std::string_view(m_tty_buf).substr(str_index, m_tty_buf.find_first_of('\n', str_index) - str_index)); str_index += buf_line.size() + 1; - // Ignore control characters and greater/equal to 0x80, but preserve ESC (0x1B) if ANSI mode is enabled - buf_line.erase(std::remove_if(buf_line.begin(), buf_line.end(), [this](s8 c) { + buf_line.erase(std::remove_if(buf_line.begin(), buf_line.end(), [this](s8 c) + { + // If ANSI TTY is enabled, preserve ESC (0x1B) for ANSI sequences if (m_ansi_tty) { - // Keep ESC (0x1B) so ANSI sequences remain intact return c <= 0x8 || c == 0x7F || (c >= 0xE && c <= 0x1F && c != 0x1B); } + + // Remove all control characters so output is clean return c <= 0x8 || c == 0x7F || (c >= 0xE && c <= 0x1F); }), buf_line.end()); diff --git a/rpcs3/rpcs3qt/log_frame.h b/rpcs3/rpcs3qt/log_frame.h index f8dd57605f..35ee672ffc 100644 --- a/rpcs3/rpcs3qt/log_frame.h +++ b/rpcs3/rpcs3qt/log_frame.h @@ -1,11 +1,11 @@ #pragma once #include "Utilities/File.h" +#include "rpcs3qt/syntax_highlighter.h" #include "util/logs.hpp" #include "custom_dock_widget.h" #include "find_dialog.h" -#include "syntax_highlighter.h" #include @@ -13,6 +13,8 @@ #include #include +class AnsiHighlighter; + class gui_settings; class log_frame : public custom_dock_widget diff --git a/rpcs3/rpcs3qt/log_viewer.h b/rpcs3/rpcs3qt/log_viewer.h index 8f9e14f833..a2e8242f89 100644 --- a/rpcs3/rpcs3qt/log_viewer.h +++ b/rpcs3/rpcs3qt/log_viewer.h @@ -34,7 +34,6 @@ private: QString m_full_log; QPlainTextEdit* m_log_text; LogHighlighter* m_log_highlighter; - AnsiHighlighter* m_ansi_highlighter; std::unique_ptr m_find_dialog; std::bitset<32> m_log_levels = std::bitset<32>(0b11111111u); bool m_show_timestamps = true; diff --git a/rpcs3/rpcs3qt/syntax_highlighter.cpp b/rpcs3/rpcs3qt/syntax_highlighter.cpp index 0cc16bc30e..4cc44b6d8b 100644 --- a/rpcs3/rpcs3qt/syntax_highlighter.cpp +++ b/rpcs3/rpcs3qt/syntax_highlighter.cpp @@ -186,48 +186,49 @@ GlslHighlighter::GlslHighlighter(QTextDocument* parent) : Highlighter(parent) AnsiHighlighter::AnsiHighlighter(QTextDocument* parent) : Highlighter(parent) { + m_foreground_color = gui::utils::get_foreground_color(); } -void AnsiHighlighter::highlightBlock(const QString &text) +void AnsiHighlighter::highlightBlock(const QString& text) { // Match ANSI SGR sequences, e.g. "\x1b[31m" or "\x1b[1;32m" - const QRegularExpression ansi_re("\x1b\\[[0-9;]*m"); - const QRegularExpression param_re("\x1b\\[([0-9;]*)m"); + static const QRegularExpression ansi_re("\x1b\\[[0-9;]*m"); + static const QRegularExpression param_re("\x1b\\[([0-9;]*)m"); - QTextCharFormat escapeFormat; - escapeFormat.setForeground(Qt::darkGray); - escapeFormat.setFontItalic(true); + static QTextCharFormat escape_format; + escape_format.setForeground(Qt::darkGray); + escape_format.setFontItalic(true); - QTextCharFormat currentFormat; - currentFormat.setForeground(gui::utils::get_foreground_color()); + static QTextCharFormat current_format; + current_format.setForeground(m_foreground_color); int pos = 0; auto it = ansi_re.globalMatch(text); while (it.hasNext()) { - auto match = it.next(); - int start = match.capturedStart(); - int length = match.capturedLength(); + const auto match = it.next(); + const int start = match.capturedStart(); + const int length = match.capturedLength(); // Apply current format to the chunk before this escape sequence if (start > pos) { - setFormat(pos, start - pos, currentFormat); + setFormat(pos, start - pos, current_format); } // Highlight the escape sequence itself - setFormat(start, length, escapeFormat); + setFormat(start, length, escape_format); // Parse SGR parameters and update currentFormat - QRegularExpressionMatch pm = param_re.match(match.captured()); + const QRegularExpressionMatch pm = param_re.match(match.captured()); if (pm.hasMatch()) { - QString params = pm.captured(1); + const QString params = pm.captured(1); if (params.isEmpty()) { // empty or just \x1b[m = reset - currentFormat = QTextCharFormat(); - currentFormat.setForeground(gui::utils::get_foreground_color()); + current_format = QTextCharFormat(); + current_format.setForeground(m_foreground_color); } else { @@ -240,35 +241,35 @@ void AnsiHighlighter::highlightBlock(const QString &text) switch (code) { case 0: - currentFormat = QTextCharFormat(); - currentFormat.setForeground(gui::utils::get_foreground_color()); + current_format = QTextCharFormat(); + current_format.setForeground(m_foreground_color); break; case 1: - currentFormat.setFontWeight(QFont::Bold); + current_format.setFontWeight(QFont::Bold); break; case 3: - currentFormat.setFontItalic(true); + current_format.setFontItalic(true); break; case 4: - currentFormat.setFontUnderline(true); + current_format.setFontUnderline(true); break; - case 30: currentFormat.setForeground(Qt::black); break; - case 31: currentFormat.setForeground(Qt::red); break; - case 32: currentFormat.setForeground(Qt::darkGreen); break; - case 33: currentFormat.setForeground(Qt::darkYellow); break; - case 34: currentFormat.setForeground(Qt::darkBlue); break; - case 35: currentFormat.setForeground(Qt::darkMagenta); break; - case 36: currentFormat.setForeground(Qt::darkCyan); break; - case 37: currentFormat.setForeground(Qt::lightGray); break; - case 39: currentFormat.setForeground(gui::utils::get_foreground_color()); break; - case 90: currentFormat.setForeground(Qt::darkGray); break; - case 91: currentFormat.setForeground(Qt::red); break; - case 92: currentFormat.setForeground(Qt::green); break; - case 93: currentFormat.setForeground(Qt::yellow); break; - case 94: currentFormat.setForeground(Qt::blue); break; - case 95: currentFormat.setForeground(Qt::magenta); break; - case 96: currentFormat.setForeground(Qt::cyan); break; - case 97: currentFormat.setForeground(Qt::white); break; + case 30: current_format.setForeground(Qt::black); break; + case 31: current_format.setForeground(Qt::red); break; + case 32: current_format.setForeground(Qt::darkGreen); break; + case 33: current_format.setForeground(Qt::darkYellow); break; + case 34: current_format.setForeground(Qt::darkBlue); break; + case 35: current_format.setForeground(Qt::darkMagenta); break; + case 36: current_format.setForeground(Qt::darkCyan); break; + case 37: current_format.setForeground(Qt::lightGray); break; + case 39: current_format.setForeground(m_foreground_color); break; + case 90: current_format.setForeground(Qt::darkGray); break; + case 91: current_format.setForeground(Qt::red); break; + case 92: current_format.setForeground(Qt::green); break; + case 93: current_format.setForeground(Qt::yellow); break; + case 94: current_format.setForeground(Qt::blue); break; + case 95: current_format.setForeground(Qt::magenta); break; + case 96: current_format.setForeground(Qt::cyan); break; + case 97: current_format.setForeground(Qt::white); break; // Background and extended colors not yet handled default: break; @@ -282,5 +283,5 @@ void AnsiHighlighter::highlightBlock(const QString &text) // Apply remaining format if (pos < text.length()) - setFormat(pos, text.length() - pos, currentFormat); + setFormat(pos, text.length() - pos, current_format); } diff --git a/rpcs3/rpcs3qt/syntax_highlighter.h b/rpcs3/rpcs3qt/syntax_highlighter.h index d5ba800e3b..f8577333dd 100644 --- a/rpcs3/rpcs3qt/syntax_highlighter.h +++ b/rpcs3/rpcs3qt/syntax_highlighter.h @@ -2,6 +2,7 @@ #include #include +#include // Inspired by https://doc.qt.io/qt-5/qtwidgets-richtext-syntaxhighlighter-example.html @@ -61,5 +62,7 @@ public: explicit AnsiHighlighter(QTextDocument* parent = nullptr); protected: - void highlightBlock(const QString &text) override; + QColor m_foreground_color; + + void highlightBlock(const QString& text) override; };