1
0
mirror of synced 2025-01-18 17:14:13 +01:00

fix: Make syncing pattern code not erase pattern code as often

This commit is contained in:
WerWolv 2024-01-11 21:56:54 +01:00
parent e5c7e52d72
commit 0d0dd7d57c
3 changed files with 84 additions and 81 deletions

View File

@ -7,15 +7,10 @@
#include <pl/pattern_language.hpp>
#include <pl/core/errors/error.hpp>
#include <content/providers/memory_file_provider.hpp>
#include <ui/hex_editor.hpp>
#include <ui/pattern_drawer.hpp>
#include <cstring>
#include <filesystem>
#include <string_view>
#include <functional>
#include <TextEditor.h>
@ -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<std::string> m_perProviderSource;
std::string m_sharedSource;
};
class ViewPatternEditor : public View::Window {
public:
ViewPatternEditor();
@ -166,14 +191,13 @@ namespace hex::plugin::builtin {
std::atomic<bool> m_dangerousFunctionCalled = false;
std::atomic<DangerousFunctionPerms> m_dangerousFunctionsAllowed = DangerousFunctionPerms::Ask;
bool m_syncPatternSourceCode = false;
bool m_autoLoadPatterns = true;
std::map<prv::Provider*, std::function<void()>> m_sectionWindowDrawer;
ui::HexEditor m_sectionHexEditor;
PerProvider<std::string> m_sourceCode;
PatternSourceCode m_sourceCode;
PerProvider<std::vector<std::string>> m_console;
PerProvider<bool> m_executionDone = true;

View File

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

View File

@ -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<u32>::max()) {
if (const auto max = runtime.getMaximumPatternCount(); max >= std::numeric_limits<u32>::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<std::shared_ptr<pl::ptrn::Pattern>> empty;
constexpr static std::vector<std::shared_ptr<pl::ptrn::Pattern>> 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<pl::core::ast::ASTNodeVariableDecl *>(node.get())) {
auto type = variableDecl->getType().get();
if (const auto variableDecl = dynamic_cast<pl::core::ast::ASTNodeVariableDecl *>(node.get())) {
const auto type = variableDecl->getType().get();
if (type == nullptr) continue;
auto builtinType = dynamic_cast<pl::core::ast::ASTNodeBuiltinType *>(type->getType().get());
const auto builtinType = dynamic_cast<pl::core::ast::ASTNodeBuiltinType *>(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<ui::PatternDrawer>();
});
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<char>(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<ImColor> 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 "";