diff --git a/rpcs3/rpcs3qt/log_frame.cpp b/rpcs3/rpcs3qt/log_frame.cpp
index 0c831f6125..d32de0f26c 100644
--- a/rpcs3/rpcs3qt/log_frame.cpp
+++ b/rpcs3/rpcs3qt/log_frame.cpp
@@ -679,7 +679,7 @@ void log_frame::UpdateUI()
const auto font_start_tag = [](const QColor& color) -> const QString { return QStringLiteral(""); };
const QString font_start_tag_stack = "";
- const QString font_end_tag = QStringLiteral("");
+ static const QString font_end_tag = QStringLiteral("");
static constexpr auto escaped = [](const QString& text)
{
diff --git a/rpcs3/rpcs3qt/patch_creator_dialog.cpp b/rpcs3/rpcs3qt/patch_creator_dialog.cpp
index de71ac5115..c873125350 100644
--- a/rpcs3/rpcs3qt/patch_creator_dialog.cpp
+++ b/rpcs3/rpcs3qt/patch_creator_dialog.cpp
@@ -10,6 +10,9 @@
#include
#include
#include
+#include
+
+#include
LOG_CHANNEL(patch_log, "PAT");
@@ -35,6 +38,7 @@ patch_creator_dialog::patch_creator_dialog(QWidget* parent)
{
ui->setupUi(this);
ui->patchEdit->setFont(mMonoFont);
+ ui->patchEdit->setAcceptRichText(true);
ui->addPatchOffsetEdit->setFont(mMonoFont);
ui->addPatchOffsetEdit->setClearButtonEnabled(true);
ui->addPatchValueEdit->setFont(mMonoFont);
@@ -374,11 +378,12 @@ bool patch_creator_dialog::can_move_instructions(QModelIndexList& selection, mov
return selection.last().row() < ui->instructionTable->rowCount() - 1;
}
-void patch_creator_dialog::validate()
+void patch_creator_dialog::validate(const QString& patch)
{
patch_engine::patch_map patches;
- const std::string content = ui->patchEdit->toPlainText().toStdString();
- const bool is_valid = patch_engine::load(patches, "From Patch Creator", content, true);
+ const std::string content = patch.toStdString();
+ std::stringstream messages;
+ const bool is_valid = patch_engine::load(patches, "From Patch Creator", content, true, &messages);
if (is_valid != m_valid)
{
@@ -400,6 +405,50 @@ void patch_creator_dialog::validate()
ui->validLabel->setPalette(palette);
m_valid = is_valid;
}
+
+ if (is_valid)
+ {
+ ui->patchEdit->setText(patch);
+ return;
+ }
+
+ // Search for erronous yml node locations in log message
+ static const std::regex r("(line )(\\d+)(, column )(\\d+)");
+ std::smatch sm;
+ std::set faulty_lines;
+
+ for (std::string err = messages.str(); !err.empty() && std::regex_search(err, sm, r) && sm.size() == 5; err = sm.suffix())
+ {
+ if (s64 row{}; try_to_int64(&row, sm[2].str(), 0, u32{umax}))
+ {
+ faulty_lines.insert(row);
+ }
+ }
+
+ // Create html and colorize offending lines
+ const QString font_start_tag = QStringLiteral("");;
+ static const QString font_end_tag = QStringLiteral("");
+ static const QString line_break_tag = QStringLiteral("
");
+
+ QStringList lines = patch.split("\n");
+ QString new_text;
+
+ for (int i = 0; i < lines.size(); i++)
+ {
+ // Escape each line and replace raw whitespace
+ const QString line = lines[i].toHtmlEscaped().replace(" ", " ");
+
+ if (faulty_lines.empty() || faulty_lines.contains(i))
+ {
+ new_text += font_start_tag + line + font_end_tag + line_break_tag;
+ }
+ else
+ {
+ new_text += line + line_break_tag;
+ }
+ }
+
+ ui->patchEdit->setHtml(new_text);
}
void patch_creator_dialog::export_patch()
@@ -465,8 +514,7 @@ void patch_creator_dialog::generate_yml(const QString& /*text*/)
patch.append(QString(" - [ %0, %1, %2 ]%3\n").arg(type).arg(offset).arg(value).arg(comment.isEmpty() ? QStringLiteral("") : QString(" # %0").arg(comment)));
}
- ui->patchEdit->setText(patch);
- validate();
+ validate(patch);
}
bool patch_creator_dialog::eventFilter(QObject* object, QEvent* event)
diff --git a/rpcs3/rpcs3qt/patch_creator_dialog.h b/rpcs3/rpcs3qt/patch_creator_dialog.h
index d8ddf120cb..a59063e31d 100644
--- a/rpcs3/rpcs3qt/patch_creator_dialog.h
+++ b/rpcs3/rpcs3qt/patch_creator_dialog.h
@@ -45,7 +45,7 @@ private:
private Q_SLOTS:
void show_table_menu(const QPoint& pos);
- void validate();
+ void validate(const QString& patch);
void generate_yml(const QString& text = {});
void export_patch();