From 0d0dd7d57cefa39d2a19293d1e5d1420809e4b3b Mon Sep 17 00:00:00 2001 From: WerWolv Date: Thu, 11 Jan 2024 21:56:54 +0100 Subject: [PATCH] fix: Make syncing pattern code not erase pattern code as often --- .../content/views/view_pattern_editor.hpp | 38 +++++- plugins/builtin/source/content/events.cpp | 1 - .../content/views/view_pattern_editor.cpp | 126 ++++++++---------- 3 files changed, 84 insertions(+), 81 deletions(-) diff --git a/plugins/builtin/include/content/views/view_pattern_editor.hpp b/plugins/builtin/include/content/views/view_pattern_editor.hpp index 3fd51761c..d34525508 100644 --- a/plugins/builtin/include/content/views/view_pattern_editor.hpp +++ b/plugins/builtin/include/content/views/view_pattern_editor.hpp @@ -7,15 +7,10 @@ #include #include -#include - #include #include - -#include #include -#include #include #include @@ -24,6 +19,36 @@ namespace pl::ptrn { class Pattern; } namespace hex::plugin::builtin { + class PatternSourceCode { + public: + const std::string& get(prv::Provider *provider) { + if (m_synced) + return m_sharedSource; + + return m_perProviderSource.get(provider); + } + + void set(prv::Provider *provider, std::string source) { + source = wolv::util::trim(source); + + m_perProviderSource.set(source, provider); + m_sharedSource = std::move(source); + } + + bool isSynced() const { + return m_synced; + } + + void enableSync(bool enabled) { + m_synced = enabled; + } + + private: + bool m_synced = false; + PerProvider m_perProviderSource; + std::string m_sharedSource; + }; + class ViewPatternEditor : public View::Window { public: ViewPatternEditor(); @@ -166,14 +191,13 @@ namespace hex::plugin::builtin { std::atomic m_dangerousFunctionCalled = false; std::atomic m_dangerousFunctionsAllowed = DangerousFunctionPerms::Ask; - bool m_syncPatternSourceCode = false; bool m_autoLoadPatterns = true; std::map> m_sectionWindowDrawer; ui::HexEditor m_sectionHexEditor; - PerProvider m_sourceCode; + PatternSourceCode m_sourceCode; PerProvider> m_console; PerProvider m_executionDone = true; diff --git a/plugins/builtin/source/content/events.cpp b/plugins/builtin/source/content/events.cpp index bc147c4d6..f5f0fb4db 100644 --- a/plugins/builtin/source/content/events.cpp +++ b/plugins/builtin/source/content/events.cpp @@ -90,7 +90,6 @@ namespace hex::plugin::builtin { EventProviderOpened::subscribe([](hex::prv::Provider *provider) { if (provider != nullptr && ImHexApi::Provider::get() == provider) RequestUpdateWindowTitle::post(); - EventProviderChanged::post(nullptr, provider); }); RequestOpenFile::subscribe(openFile); diff --git a/plugins/builtin/source/content/views/view_pattern_editor.cpp b/plugins/builtin/source/content/views/view_pattern_editor.cpp index 3dea5e956..5a42f98ea 100644 --- a/plugins/builtin/source/content/views/view_pattern_editor.cpp +++ b/plugins/builtin/source/content/views/view_pattern_editor.cpp @@ -206,7 +206,7 @@ namespace hex::plugin::builtin { static float height = 0; static bool dragging = false; - auto availableSize = ImGui::GetContentRegionAvail(); + const auto availableSize = ImGui::GetContentRegionAvail(); auto textEditorSize = availableSize; textEditorSize.y *= 3.5 / 5.0; textEditorSize.y -= ImGui::GetTextLineHeightWithSpacing(); @@ -222,7 +222,7 @@ namespace hex::plugin::builtin { } if (ImGui::BeginPopup("##pattern_editor_context_menu")) { - bool hasSelection = m_textEditor.HasSelection(); + const bool hasSelection = m_textEditor.HasSelection(); if (ImGui::MenuItem("hex.builtin.view.hex_editor.menu.edit.cut"_lang, Shortcut(CTRLCMD + Keys::X).toString().c_str(), false, hasSelection)) { m_textEditor.Cut(); } @@ -354,7 +354,7 @@ namespace hex::plugin::builtin { insertPos(runtime.getLastWriteAddress(), ImGuiExt::GetCustomColorU32(ImGuiCustomCol_ToolbarRed)); insertPos(runtime.getLastPatternPlaceAddress(), ImGuiExt::GetCustomColorU32(ImGuiCustomCol_ToolbarGreen)); - auto drawList = ImGui::GetWindowDrawList(); + const auto drawList = ImGui::GetWindowDrawList(); for (const auto &[progress, color] : m_accessHistory) { if (progress <= 0) continue; @@ -376,7 +376,7 @@ namespace hex::plugin::builtin { ImGui::SeparatorEx(ImGuiSeparatorFlags_Vertical); ImGui::SameLine(); - if (auto max = runtime.getMaximumPatternCount(); max >= std::numeric_limits::max()) { + if (const auto max = runtime.getMaximumPatternCount(); max >= std::numeric_limits::max()) { ImGuiExt::TextFormatted("{}", runtime.getCreatedPatternCount()); } else { ImGuiExt::TextFormatted("{} / {}", @@ -389,7 +389,6 @@ namespace hex::plugin::builtin { if (m_textEditor.IsTextChanged()) { m_hasUnevaluatedChanges = true; ImHexApi::Provider::markDirty(); - m_sourceCode = m_textEditor.GetText(); } if (m_hasUnevaluatedChanges && m_runningEvaluators == 0 && m_runningParsers == 0) { @@ -438,7 +437,7 @@ namespace hex::plugin::builtin { m_consoleEditor.SetCursorPosition({ int(lineCount + 1), 0 }); - auto linesToAdd = m_console->size() - lineCount; + const auto linesToAdd = m_console->size() - lineCount; for (size_t i = 0; i < linesToAdd; i += 1) { m_consoleEditor.InsertText(m_console->at(lineCount + i)); m_consoleEditor.InsertText("\n"); @@ -536,8 +535,8 @@ namespace hex::plugin::builtin { ImGui::BeginDisabled(envVars.size() <= 1); { if (ImGuiExt::IconButton(ICON_VS_REMOVE, ImGui::GetStyleColorVec4(ImGuiCol_Text))) { - bool isFirst = iter == envVars.begin(); - bool isLast = std::next(iter) == envVars.end(); + const bool isFirst = iter == envVars.begin(); + const bool isLast = std::next(iter) == envVars.end(); envVars.erase(iter); if (isFirst) @@ -677,7 +676,7 @@ namespace hex::plugin::builtin { if (patternProvider->isReadable() && *m_executionDone) { return runtime.getPatterns(id); } else { - static const std::vector> empty; + constexpr static std::vector> empty; return empty; } }(); @@ -724,12 +723,12 @@ namespace hex::plugin::builtin { void ViewPatternEditor::drawDebugger(ImVec2 size) { - auto &runtime = ContentRegistry::PatternLanguage::getRuntime(); + const auto &runtime = ContentRegistry::PatternLanguage::getRuntime(); auto &evaluator = runtime.getInternals().evaluator; if (ImGui::BeginChild("##debugger", size, true)) { const auto &breakpoints = evaluator->getBreakpoints(); - auto line = m_textEditor.GetCursorPosition().mLine + 1; + const auto line = m_textEditor.GetCursorPosition().mLine + 1; if (!breakpoints.contains(line)) { if (ImGuiExt::IconButton(ICON_VS_DEBUG_BREAKPOINT, ImGuiExt::GetCustomColorVec4(ImGuiCustomCol_ToolbarRed))) { @@ -760,7 +759,7 @@ namespace hex::plugin::builtin { if (evaluator->getScopeCount() > 0) { ImGui::SetNextItemWidth(-1); - auto &currScope = evaluator->getScope(-m_debuggerScopeIndex); + const auto &currScope = evaluator->getScope(-m_debuggerScopeIndex); if (ImGui::BeginCombo("##scope", displayValue(currScope.parent, m_debuggerScopeIndex).c_str())) { for (size_t i = 0; i < evaluator->getScopeCount(); i++) { auto &scope = evaluator->getScope(-i); @@ -776,7 +775,7 @@ namespace hex::plugin::builtin { } if (m_resetDebuggerVariables) { - auto pauseLine = evaluator->getPauseLine(); + const auto pauseLine = evaluator->getPauseLine(); (*m_debuggerDrawer)->reset(); m_resetDebuggerVariables = false; @@ -786,7 +785,7 @@ namespace hex::plugin::builtin { m_textEditor.SetCursorPosition({ int(pauseLine.value() - 1), 0 }); } - auto &currScope = evaluator->getScope(-m_debuggerScopeIndex); + const auto &currScope = evaluator->getScope(-m_debuggerScopeIndex); (*m_debuggerDrawer)->draw(*currScope.scope, &runtime, size.y - ImGui::GetTextLineHeightWithSpacing() * 4); } } @@ -814,7 +813,7 @@ namespace hex::plugin::builtin { if (!m_lastEvaluationResult) { if (m_lastEvaluationError->has_value()) { const auto message = [this]{ - auto message = (*m_lastEvaluationError)->message; + const auto &message = (*m_lastEvaluationError)->message; auto lines = wolv::util::splitString(message, "\n"); std::ranges::transform(lines, lines.begin(), [](auto line) { @@ -827,7 +826,7 @@ namespace hex::plugin::builtin { return wolv::util::combineStrings(lines, "\n"); }(); - TextEditor::ErrorMarkers errorMarkers = { + const TextEditor::ErrorMarkers errorMarkers = { { (*m_lastEvaluationError)->line, message } }; m_textEditor.SetErrorMarkers(errorMarkers); @@ -852,11 +851,6 @@ namespace hex::plugin::builtin { if (!m_autoLoadPatterns) return; - // Copy over current pattern source code to the new provider - if (!m_syncPatternSourceCode) { - *m_sourceCode = m_textEditor.GetText(); - } - pl::PatternLanguage runtime; ContentRegistry::PatternLanguage::configureRuntime(runtime, provider); @@ -873,7 +867,7 @@ namespace hex::plugin::builtin { foundCorrectType = true; return true; } - return !std::all_of(value.begin(), value.end(), isspace) && !value.ends_with('\n') && !value.ends_with('\r'); + return !std::ranges::all_of(value, isspace) && !value.ends_with('\n') && !value.ends_with('\r'); }); // Format: [ AA BB CC DD ] @ 0x12345678 @@ -889,7 +883,7 @@ namespace hex::plugin::builtin { value = value.substr(1); - auto end = value.find(']'); + const auto end = value.find(']'); if (end == std::string::npos) return std::nullopt; @@ -905,7 +899,7 @@ namespace hex::plugin::builtin { if (value.empty()) return std::nullopt; - auto start = value.find('@'); + const auto start = value.find('@'); if (start == std::string::npos) return std::nullopt; @@ -1040,7 +1034,7 @@ namespace hex::plugin::builtin { this->evaluatePattern(code, provider); m_textEditor.SetText(code); - m_sourceCode = code; + m_sourceCode.set(provider, code); TaskManager::createBackgroundTask("Parse pattern", [this, code, provider](auto&) { this->parsePattern(code, provider); }); } @@ -1050,23 +1044,23 @@ namespace hex::plugin::builtin { m_runningParsers += 1; ContentRegistry::PatternLanguage::configureRuntime(*m_parserRuntime, nullptr); - auto ast = m_parserRuntime->parseString(code); + const auto &ast = m_parserRuntime->parseString(code); auto &patternVariables = m_patternVariables.get(provider); patternVariables.clear(); - if (ast) { + if (ast.has_value()) { for (auto &node : *ast) { - if (auto variableDecl = dynamic_cast(node.get())) { - auto type = variableDecl->getType().get(); + if (const auto variableDecl = dynamic_cast(node.get())) { + const auto type = variableDecl->getType().get(); if (type == nullptr) continue; - auto builtinType = dynamic_cast(type->getType().get()); + const auto builtinType = dynamic_cast(type->getType().get()); if (builtinType == nullptr) continue; - PatternVariable variable = { + const PatternVariable variable = { .inVariable = variableDecl->isInVariable(), .outVariable = variableDecl->isOutVariable(), .type = builtinType->getType(), @@ -1155,6 +1149,7 @@ namespace hex::plugin::builtin { case Info: line = hex::format("I: {}", line); break; case Warning: line = hex::format("W: {}", line); break; case Error: line = hex::format("E: {}", line); break; + default: break; } m_console->emplace_back(line); @@ -1205,42 +1200,33 @@ namespace hex::plugin::builtin { RequestSetPatternLanguageCode::subscribe(this, [this](const std::string &code) { m_textEditor.SetText(code); - m_sourceCode = code; + m_sourceCode.set(ImHexApi::Provider::get(), code); m_hasUnevaluatedChanges = true; }); EventSettingsChanged::subscribe(this, [this] { - m_syncPatternSourceCode = ContentRegistry::Settings::read("hex.builtin.setting.general", "hex.builtin.setting.general.sync_pattern_source", false); - m_autoLoadPatterns = ContentRegistry::Settings::read("hex.builtin.setting.general", "hex.builtin.setting.general.auto_load_patterns", true); + m_sourceCode.enableSync(ContentRegistry::Settings::read("hex.builtin.setting.general", "hex.builtin.setting.general.sync_pattern_source", false)); + m_autoLoadPatterns = ContentRegistry::Settings::read("hex.builtin.setting.general", "hex.builtin.setting.general.auto_load_patterns", true); }); EventProviderOpened::subscribe(this, [this](prv::Provider *provider) { m_shouldAnalyze.get(provider) = true; - m_envVarEntries->push_back({ 0, "", 0, EnvVarType::Integer }); + m_envVarEntries->emplace_back(0, "", i128(0), EnvVarType::Integer); m_debuggerDrawer.get(provider) = std::make_unique(); }); EventProviderChanged::subscribe(this, [this](prv::Provider *oldProvider, prv::Provider *newProvider) { - if (!m_syncPatternSourceCode) { - if (oldProvider != nullptr) - m_sourceCode.get(oldProvider) = m_textEditor.GetText(); + if (oldProvider != nullptr) + m_sourceCode.set(oldProvider, m_textEditor.GetText()); - if (newProvider != nullptr) { - m_consoleEditor.SetTextLines(m_console.get(newProvider)); - m_textEditor.SetText(wolv::util::trim(m_sourceCode.get(newProvider))); - } else { - m_textEditor.SetText(""); - } - } else { - m_hasUnevaluatedChanges = true; - } + if (newProvider != nullptr) + m_textEditor.SetText(m_sourceCode.get(newProvider)); }); EventProviderClosed::subscribe(this, [this](prv::Provider *) { - if (m_syncPatternSourceCode && ImHexApi::Provider::getProviders().empty()) { + if (ImHexApi::Provider::getProviders().empty()) { m_textEditor.SetText(""); - m_sourceCode = ""; } }); @@ -1271,14 +1257,14 @@ namespace hex::plugin::builtin { } void ViewPatternEditor::appendVariable(const std::string &type) { - auto selection = ImHexApi::HexEditor::getSelection(); + const auto &selection = ImHexApi::HexEditor::getSelection(); appendEditorText(hex::format("{0} {0}_at_0x{1:02X} @ 0x{1:02X};", type, selection->getStartAddress())); AchievementManager::unlockAchievement("hex.builtin.achievement.patterns", "hex.builtin.achievement.patterns.place_menu.name"); } void ViewPatternEditor::appendArray(const std::string &type, size_t size) { - auto selection = ImHexApi::HexEditor::getSelection(); + const auto &selection = ImHexApi::HexEditor::getSelection(); appendEditorText(hex::format("{0} {0}_array_at_0x{1:02X}[0x{2:02X}] @ 0x{1:02X};", type, selection->getStartAddress(), (selection->getSize() + (size - 1)) / size)); } @@ -1354,10 +1340,10 @@ namespace hex::plugin::builtin { } const auto &types = m_parserRuntime->getInternals().parser->getTypes(); - bool hasPlaceableTypes = std::any_of(types.begin(), types.end(), [](const auto &type) { return !type.second->isTemplateType(); }); + const bool hasPlaceableTypes = std::ranges::any_of(types, [](const auto &type) { return !type.second->isTemplateType(); }); if (ImGui::BeginMenu("hex.builtin.view.pattern_editor.menu.edit.place_pattern.custom"_lang, hasPlaceableTypes)) { - auto selection = ImHexApi::HexEditor::getSelection(); + const auto &selection = ImHexApi::HexEditor::getSelection(); for (const auto &[typeName, type] : types) { if (type->isTemplateType()) @@ -1365,7 +1351,7 @@ namespace hex::plugin::builtin { createNestedMenu(hex::splitString(typeName, "::"), [&, this] { std::string variableName; - for (char &c : hex::replaceStrings(typeName, "::", "_")) + for (const char c : hex::replaceStrings(typeName, "::", "_")) variableName += static_cast(std::tolower(c)); variableName += hex::format("_at_0x{:02X}", selection->getStartAddress()); @@ -1398,7 +1384,7 @@ namespace hex::plugin::builtin { if (m_runningEvaluators != 0) return std::nullopt; - auto &runtime = ContentRegistry::PatternLanguage::getRuntime(); + const auto &runtime = ContentRegistry::PatternLanguage::getRuntime(); std::optional color; @@ -1418,17 +1404,17 @@ namespace hex::plugin::builtin { hex::unused(data, size); if (TRY_LOCK(ContentRegistry::PatternLanguage::getRuntimeLock())) { - auto &runtime = ContentRegistry::PatternLanguage::getRuntime(); + const auto &runtime = ContentRegistry::PatternLanguage::getRuntime(); auto patterns = runtime.getPatternsAtAddress(address); - if (!patterns.empty() && !std::all_of(patterns.begin(), patterns.end(), [](const auto &pattern) { return pattern->getVisibility() == pl::ptrn::Visibility::Hidden; })) { + if (!patterns.empty() && !std::ranges::all_of(patterns, [](const auto &pattern) { return pattern->getVisibility() == pl::ptrn::Visibility::Hidden; })) { ImGui::BeginTooltip(); for (const auto &pattern : patterns) { if (pattern->getVisibility() != pl::ptrn::Visibility::Visible) continue; - auto tooltipColor = (pattern->getColor() & 0x00FF'FFFF) | 0x7000'0000; + const auto tooltipColor = (pattern->getColor() & 0x00FF'FFFF) | 0x7000'0000; ImGui::PushID(pattern); if (ImGui::BeginTable("##tooltips", 1, ImGuiTableFlags_RowBg | ImGuiTableFlags_NoClip)) { ImGui::TableNextRow(); @@ -1452,10 +1438,9 @@ namespace hex::plugin::builtin { .basePath = "pattern_source_code.hexpat", .required = false, .load = [this](prv::Provider *provider, const std::fs::path &basePath, const Tar &tar) { - std::string sourceCode = tar.readString(basePath); + const auto sourceCode = tar.readString(basePath); - if (!m_syncPatternSourceCode) - m_sourceCode.get(provider) = sourceCode; + m_sourceCode.set(provider, sourceCode); if (provider == ImHexApi::Provider::get()) m_textEditor.SetText(sourceCode); @@ -1463,15 +1448,10 @@ namespace hex::plugin::builtin { return true; }, .store = [this](prv::Provider *provider, const std::fs::path &basePath, const Tar &tar) { - std::string sourceCode; - if (provider == ImHexApi::Provider::get()) - m_sourceCode.get(provider) = m_textEditor.GetText(); + m_sourceCode.set(provider, m_textEditor.GetText()); - if (m_syncPatternSourceCode) - sourceCode = m_textEditor.GetText(); - else - sourceCode = m_sourceCode.get(provider); + const auto &sourceCode = m_sourceCode.get(provider); tar.writeString(basePath, wolv::util::trim(sourceCode)); return true; @@ -1479,8 +1459,8 @@ namespace hex::plugin::builtin { }); ShortcutManager::addShortcut(this, Keys::F8 + AllowWhileTyping, "hex.builtin.view.pattern_editor.shortcut.add_breakpoint", [this] { - auto line = m_textEditor.GetCursorPosition().mLine + 1; - auto &runtime = ContentRegistry::PatternLanguage::getRuntime(); + const auto line = m_textEditor.GetCursorPosition().mLine + 1; + const auto &runtime = ContentRegistry::PatternLanguage::getRuntime(); auto &evaluator = runtime.getInternals().evaluator; auto &breakpoints = evaluator->getBreakpoints(); @@ -1501,14 +1481,14 @@ namespace hex::plugin::builtin { /* Continue debugger */ ShortcutManager::addGlobalShortcut(SHIFT + Keys::F9 + AllowWhileTyping, "hex.builtin.view.pattern_editor.shortcut.continue_debugger", [this] { - auto &runtime = ContentRegistry::PatternLanguage::getRuntime(); + const auto &runtime = ContentRegistry::PatternLanguage::getRuntime(); if (runtime.isRunning()) m_breakpointHit = false; }); /* Step debugger */ ShortcutManager::addGlobalShortcut(SHIFT + Keys::F7 + AllowWhileTyping, "hex.builtin.view.pattern_editor.shortcut.step_debugger", [this] { - auto &runtime = ContentRegistry::PatternLanguage::getRuntime(); + const auto &runtime = ContentRegistry::PatternLanguage::getRuntime(); if (runtime.isRunning()) { runtime.getInternals().evaluator->pauseNextLine(); m_breakpointHit = false; @@ -1517,7 +1497,7 @@ namespace hex::plugin::builtin { // Generate pattern code report ContentRegistry::Reports::addReportProvider([this](prv::Provider *provider) -> std::string { - auto patternCode = m_sourceCode.get(provider); + const auto &patternCode = m_sourceCode.get(provider); if (wolv::util::trim(patternCode).empty()) return "";