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();