diff --git a/plugins/builtin/include/content/helpers/provider_extra_data.hpp b/plugins/builtin/include/content/helpers/provider_extra_data.hpp index ddbce3e57..28df90c99 100644 --- a/plugins/builtin/include/content/helpers/provider_extra_data.hpp +++ b/plugins/builtin/include/content/helpers/provider_extra_data.hpp @@ -15,16 +15,51 @@ namespace hex::plugin::builtin { struct Data { bool dataDirty = false; - struct { + struct PatternLanguage { + struct PatternVariable { + bool inVariable; + bool outVariable; + + pl::core::Token::ValueType type; + pl::core::Token::Literal value; + }; + + enum class EnvVarType + { + Integer, + Float, + String, + Bool + }; + + struct EnvVar { + u64 id; + std::string name; + pl::core::Token::Literal value; + EnvVarType type; + + bool operator==(const EnvVar &other) const { + return this->id == other.id; + } + }; + std::string sourceCode; std::mutex runtimeMutex; std::unique_ptr runtime; + std::vector> console; bool executionDone = true; + + std::optional lastEvaluationError; + std::vector> lastEvaluationLog; + std::map lastEvaluationOutVars; + std::map patternVariables; + + std::list envVarEntries; } patternLanguage; std::list bookmarks; - struct { + struct DataProcessor { std::list endNodes; std::list> nodes; std::list links; @@ -33,7 +68,7 @@ namespace hex::plugin::builtin { std::optional currNodeError; } dataProcessor; - struct { + struct HexEditor { std::optional selectionStart, selectionEnd; float scrollPosition = 0.0F; } editor; diff --git a/plugins/builtin/include/content/views/view_pattern_editor.hpp b/plugins/builtin/include/content/views/view_pattern_editor.hpp index 3fadb2558..42756812f 100644 --- a/plugins/builtin/include/content/views/view_pattern_editor.hpp +++ b/plugins/builtin/include/content/views/view_pattern_editor.hpp @@ -4,6 +4,7 @@ #include #include #include +#include #include #include @@ -26,33 +27,6 @@ namespace hex::plugin::builtin { void drawContent() override; private: - struct PatternVariable { - bool inVariable; - bool outVariable; - - pl::core::Token::ValueType type; - pl::core::Token::Literal value; - }; - - enum class EnvVarType - { - Integer, - Float, - String, - Bool - }; - - struct EnvVar { - u64 id; - std::string name; - pl::core::Token::Literal value; - EnvVarType type; - - bool operator==(const EnvVar &other) const { - return this->id == other.id; - } - }; - enum class DangerousFunctionPerms : u8 { Ask, Allow, @@ -60,6 +34,8 @@ namespace hex::plugin::builtin { }; private: + using PlData = ProviderExtraData::Data::PatternLanguage; + std::unique_ptr m_parserRuntime; std::vector m_possiblePatternFiles; @@ -68,9 +44,6 @@ namespace hex::plugin::builtin { bool m_lastEvaluationProcessed = true; bool m_lastEvaluationResult = false; - std::optional m_lastEvaluationError; - std::vector> m_lastEvaluationLog; - std::map m_lastEvaluationOutVars; std::atomic m_runningEvaluators = 0; std::atomic m_runningParsers = 0; @@ -80,12 +53,6 @@ namespace hex::plugin::builtin { bool m_acceptPatternWindowOpen = false; TextEditor m_textEditor; - std::vector> m_console; - - std::map m_patternVariables; - - u64 m_envVarIdCounter; - std::list m_envVarEntries; std::atomic m_dangerousFunctionCalled = false; std::atomic m_dangerousFunctionsAllowed = DangerousFunctionPerms::Ask; @@ -94,16 +61,16 @@ namespace hex::plugin::builtin { bool m_autoLoadPatterns = true; private: - void drawConsole(ImVec2 size); - void drawEnvVars(ImVec2 size); - void drawVariableSettings(ImVec2 size); + void drawConsole(ImVec2 size, const std::vector> &console); + void drawEnvVars(ImVec2 size, std::list &envVars); + void drawVariableSettings(ImVec2 size, std::map &patternVariables); void drawPatternTooltip(pl::ptrn::Pattern *pattern); - void loadPatternFile(const std::fs::path &path); + void loadPatternFile(const std::fs::path &path, prv::Provider *provider); - void parsePattern(const std::string &code); - void evaluatePattern(const std::string &code); + void parsePattern(const std::string &code, prv::Provider *provider); + void evaluatePattern(const std::string &code, prv::Provider *provider); void registerEvents(); void registerMenuItems(); diff --git a/plugins/builtin/source/content/views/view_pattern_editor.cpp b/plugins/builtin/source/content/views/view_pattern_editor.cpp index 8b018ad2c..c433c905c 100644 --- a/plugins/builtin/source/content/views/view_pattern_editor.cpp +++ b/plugins/builtin/source/content/views/view_pattern_editor.cpp @@ -88,9 +88,6 @@ namespace hex::plugin::builtin { this->m_textEditor.SetLanguageDefinition(PatternLanguage()); this->m_textEditor.SetShowWhitespaces(false); - this->m_envVarEntries.push_back({ 0, "", 0, EnvVarType::Integer }); - this->m_envVarIdCounter = 1; - this->registerEvents(); this->registerMenuItems(); this->registerHandlers(); @@ -109,6 +106,8 @@ namespace hex::plugin::builtin { auto provider = ImHexApi::Provider::get(); if (ImHexApi::Provider::isValid() && provider->isAvailable()) { + auto &extraData = ProviderExtraData::get(provider).patternLanguage; + auto textEditorSize = ImGui::GetContentRegionAvail(); textEditorSize.y *= 3.75 / 5.0; textEditorSize.y -= ImGui::GetTextLineHeightWithSpacing(); @@ -119,15 +118,15 @@ namespace hex::plugin::builtin { if (ImGui::BeginTabBar("##settings")) { if (ImGui::BeginTabItem("hex.builtin.view.pattern_editor.console"_lang)) { - this->drawConsole(settingsSize); + this->drawConsole(settingsSize, extraData.console); ImGui::EndTabItem(); } if (ImGui::BeginTabItem("hex.builtin.view.pattern_editor.env_vars"_lang)) { - this->drawEnvVars(settingsSize); + this->drawEnvVars(settingsSize, extraData.envVarEntries); ImGui::EndTabItem(); } if (ImGui::BeginTabItem("hex.builtin.view.pattern_editor.settings"_lang)) { - this->drawVariableSettings(settingsSize); + this->drawVariableSettings(settingsSize, extraData.patternVariables); ImGui::EndTabItem(); } @@ -142,7 +141,7 @@ namespace hex::plugin::builtin { runtime->abort(); } else { if (ImGui::IconButton(ICON_VS_DEBUG_START, ImGui::GetCustomColorVec4(ImGuiCustomCol_ToolbarGreen))) { - this->evaluatePattern(this->m_textEditor.GetText()); + this->evaluatePattern(this->m_textEditor.GetText(), provider); } } @@ -176,13 +175,36 @@ namespace hex::plugin::builtin { this->m_hasUnevaluatedChanges = false; - TaskManager::createBackgroundTask("Pattern Parsing", [this, code = this->m_textEditor.GetText()](auto &){ - this->parsePattern(code); + TaskManager::createBackgroundTask("Pattern Parsing", [this, code = this->m_textEditor.GetText(), provider](auto &){ + this->parsePattern(code, provider); if (this->m_runAutomatically) - this->evaluatePattern(code); + this->evaluatePattern(code, provider); }); } + + if (!this->m_lastEvaluationProcessed) { + extraData.console = extraData.lastEvaluationLog; + + if (!this->m_lastEvaluationResult) { + if (extraData.lastEvaluationError) { + TextEditor::ErrorMarkers errorMarkers = { + { extraData.lastEvaluationError->line, extraData.lastEvaluationError->message } + }; + this->m_textEditor.SetErrorMarkers(errorMarkers); + } + } else { + for (auto &[name, variable] : extraData.patternVariables) { + if (variable.outVariable && extraData.lastEvaluationOutVars.contains(name)) + variable.value = extraData.lastEvaluationOutVars.at(name); + } + + EventManager::post(); + } + + this->m_lastEvaluationProcessed = true; + extraData.executionDone = true; + } } if (this->m_dangerousFunctionCalled && !ImGui::IsPopupOpen(View::toWindowName("hex.builtin.view.pattern_editor.dangerous_function.name").c_str())) { @@ -209,43 +231,20 @@ namespace hex::plugin::builtin { } View::discardNavigationRequests(); - - if (!this->m_lastEvaluationProcessed) { - this->m_console = this->m_lastEvaluationLog; - - if (!this->m_lastEvaluationResult) { - if (this->m_lastEvaluationError) { - TextEditor::ErrorMarkers errorMarkers = { - { this->m_lastEvaluationError->line, this->m_lastEvaluationError->message } - }; - this->m_textEditor.SetErrorMarkers(errorMarkers); - } - } else { - for (auto &[name, variable] : this->m_patternVariables) { - if (variable.outVariable && this->m_lastEvaluationOutVars.contains(name)) - variable.value = this->m_lastEvaluationOutVars.at(name); - } - - EventManager::post(); - } - - this->m_lastEvaluationProcessed = true; - ProviderExtraData::get(provider).patternLanguage.executionDone = true; - } } ImGui::End(); } - void ViewPatternEditor::drawConsole(ImVec2 size) { + void ViewPatternEditor::drawConsole(ImVec2 size, const std::vector> &console) { ImGui::PushStyleColor(ImGuiCol_ChildBg, this->m_textEditor.GetPalette()[u32(TextEditor::PaletteIndex::Background)]); if (ImGui::BeginChild("##console", size, true, ImGuiWindowFlags_AlwaysVerticalScrollbar | ImGuiWindowFlags_HorizontalScrollbar)) { ImGuiListClipper clipper; - clipper.Begin(this->m_console.size()); + clipper.Begin(console.size()); while (clipper.Step()) for (int i = clipper.DisplayStart; i < clipper.DisplayEnd; i++) { - const auto &[level, message] = this->m_console[i]; + const auto &[level, message] = console[i]; switch (level) { using enum pl::core::LogConsole::Level; @@ -276,7 +275,9 @@ namespace hex::plugin::builtin { ImGui::PopStyleColor(1); } - void ViewPatternEditor::drawEnvVars(ImVec2 size) { + void ViewPatternEditor::drawEnvVars(ImVec2 size, std::list &envVars) { + static u32 envVarCounter = 1; + if (ImGui::BeginChild("##env_vars", size, true, ImGuiWindowFlags_AlwaysVerticalScrollbar)) { int index = 0; if (ImGui::BeginTable("##env_vars_table", 4, ImGuiTableFlags_SizingStretchProp | ImGuiTableFlags_BordersInnerH)) { @@ -285,7 +286,7 @@ namespace hex::plugin::builtin { ImGui::TableSetupColumn("Value", ImGuiTableColumnFlags_WidthStretch, 0.38F); ImGui::TableSetupColumn("Remove", ImGuiTableColumnFlags_WidthStretch, 0.12F); - for (auto iter = this->m_envVarEntries.begin(); iter != this->m_envVarEntries.end(); iter++) { + for (auto iter = envVars.begin(); iter != envVars.end(); iter++) { ImGui::TableNextRow(); ImGui::TableNextColumn(); @@ -299,7 +300,7 @@ namespace hex::plugin::builtin { if (ImGui::BeginCombo("", Types[static_cast(type)])) { for (auto i = 0; i < IM_ARRAYSIZE(Types); i++) { if (ImGui::Selectable(Types[i])) - type = static_cast(i); + type = static_cast(i); } ImGui::EndCombo(); @@ -316,28 +317,29 @@ namespace hex::plugin::builtin { ImGui::PushItemWidth(ImGui::GetContentRegionAvail().x); switch (type) { - case EnvVarType::Integer: + using enum PlData::EnvVarType; + case Integer: { i64 displayValue = hex::get_or(value, 0); ImGui::InputScalar("###value", ImGuiDataType_S64, &displayValue); value = i128(displayValue); break; } - case EnvVarType::Float: + case Float: { auto displayValue = hex::get_or(value, 0.0); ImGui::InputDouble("###value", &displayValue); value = displayValue; break; } - case EnvVarType::Bool: + case Bool: { auto displayValue = hex::get_or(value, false); ImGui::Checkbox("###value", &displayValue); value = displayValue; break; } - case EnvVarType::String: + case String: { auto displayValue = hex::get_or(value, ""); ImGui::InputText("###value", displayValue); @@ -351,20 +353,20 @@ namespace hex::plugin::builtin { if (ImGui::IconButton(ICON_VS_ADD, ImGui::GetStyleColorVec4(ImGuiCol_Text))) { iter++; - this->m_envVarEntries.insert(iter, { this->m_envVarIdCounter++, "", i128(0), EnvVarType::Integer }); + envVars.insert(iter, { envVarCounter++, "", i128(0), PlData::EnvVarType::Integer }); iter--; } ImGui::SameLine(); - ImGui::BeginDisabled(this->m_envVarEntries.size() <= 1); + ImGui::BeginDisabled(envVars.size() <= 1); { if (ImGui::IconButton(ICON_VS_REMOVE, ImGui::GetStyleColorVec4(ImGuiCol_Text))) { - bool isFirst = iter == this->m_envVarEntries.begin(); - this->m_envVarEntries.erase(iter); + bool isFirst = iter == envVars.begin(); + envVars.erase(iter); if (isFirst) - iter = this->m_envVarEntries.begin(); + iter = envVars.begin(); } } ImGui::EndDisabled(); @@ -376,16 +378,16 @@ namespace hex::plugin::builtin { ImGui::EndChild(); } - void ViewPatternEditor::drawVariableSettings(ImVec2 size) { + void ViewPatternEditor::drawVariableSettings(ImVec2 size, std::map &patternVariables) { if (ImGui::BeginChild("##settings", size, true, ImGuiWindowFlags_AlwaysVerticalScrollbar)) { - if (this->m_patternVariables.empty()) { + if (patternVariables.empty()) { ImGui::TextFormattedCentered("hex.builtin.view.pattern_editor.no_in_out_vars"_lang); } else { if (ImGui::BeginTable("##in_out_vars_table", 2, ImGuiTableFlags_SizingStretchProp | ImGuiTableFlags_BordersInnerH)) { ImGui::TableSetupColumn("Name", ImGuiTableColumnFlags_WidthStretch, 0.4F); ImGui::TableSetupColumn("Value", ImGuiTableColumnFlags_WidthStretch, 0.6F); - for (auto &[name, variable] : this->m_patternVariables) { + for (auto &[name, variable] : patternVariables) { ImGui::TableNextRow(); ImGui::TableNextColumn(); @@ -430,6 +432,7 @@ namespace hex::plugin::builtin { } void ViewPatternEditor::drawAlwaysVisible() { + auto provider = ImHexApi::Provider::get(); ImGui::SetNextWindowPos(ImGui::GetMainViewport()->GetCenter(), ImGuiCond_Appearing, ImVec2(0.5F, 0.5F)); if (ImGui::BeginPopupModal("hex.builtin.view.pattern_editor.accept_pattern"_lang, &this->m_acceptPatternWindowOpen, ImGuiWindowFlags_AlwaysAutoResize)) { @@ -458,8 +461,8 @@ namespace hex::plugin::builtin { ImGui::TextUnformatted("hex.builtin.view.pattern_editor.accept_pattern.question"_lang); confirmButtons( - "hex.builtin.common.yes"_lang, "hex.builtin.common.no"_lang, [this] { - this->loadPatternFile(this->m_possiblePatternFiles[this->m_selectedPatternFile]); + "hex.builtin.common.yes"_lang, "hex.builtin.common.no"_lang, [this, provider] { + this->loadPatternFile(this->m_possiblePatternFiles[this->m_selectedPatternFile], provider); ImGui::CloseCurrentPopup(); }, [] { ImGui::CloseCurrentPopup(); }); if (ImGui::IsKeyDown(ImGui::GetKeyIndex(ImGuiKey_Escape))) @@ -532,25 +535,26 @@ namespace hex::plugin::builtin { } - void ViewPatternEditor::loadPatternFile(const std::fs::path &path) { + void ViewPatternEditor::loadPatternFile(const std::fs::path &path, prv::Provider *provider) { fs::File file(path, fs::File::Mode::Read); if (file.isValid()) { auto code = file.readString(); - this->evaluatePattern(code); + this->evaluatePattern(code, provider); this->m_textEditor.SetText(code); - TaskManager::createBackgroundTask("Parse pattern", [this, code](auto&) { this->parsePattern(code); }); + TaskManager::createBackgroundTask("Parse pattern", [this, code, provider](auto&) { this->parsePattern(code, provider); }); } } - void ViewPatternEditor::parsePattern(const std::string &code) { + void ViewPatternEditor::parsePattern(const std::string &code, prv::Provider *provider) { this->m_runningParsers++; ContentRegistry::PatternLanguage::configureRuntime(*this->m_parserRuntime, nullptr); auto ast = this->m_parserRuntime->parseString(code); + auto &patternLanguage = ProviderExtraData::get(provider).patternLanguage; - this->m_patternVariables.clear(); + patternLanguage.patternVariables.clear(); if (ast) { for (auto &node : *ast) { @@ -561,7 +565,7 @@ namespace hex::plugin::builtin { auto builtinType = dynamic_cast(type->getType().get()); if (builtinType == nullptr) continue; - PatternVariable variable = { + PlData::PatternVariable variable = { .inVariable = variableDecl->isInVariable(), .outVariable = variableDecl->isOutVariable(), .type = builtinType->getType(), @@ -569,8 +573,8 @@ namespace hex::plugin::builtin { }; if (variable.inVariable || variable.outVariable) { - if (!this->m_patternVariables.contains(variableDecl->getName())) - this->m_patternVariables[variableDecl->getName()] = variable; + if (!patternLanguage.patternVariables.contains(variableDecl->getName())) + patternLanguage.patternVariables[variableDecl->getName()] = variable; } } } @@ -579,15 +583,14 @@ namespace hex::plugin::builtin { this->m_runningParsers--; } - void ViewPatternEditor::evaluatePattern(const std::string &code) { - auto provider = ImHexApi::Provider::get(); + void ViewPatternEditor::evaluatePattern(const std::string &code, prv::Provider *provider) { auto &patternLanguage = ProviderExtraData::get(provider).patternLanguage; this->m_runningEvaluators++; patternLanguage.executionDone = false; this->m_textEditor.SetErrorMarkers({}); - this->m_console.clear(); + patternLanguage.console.clear(); ContentRegistry::PatternLanguage::configureRuntime(*patternLanguage.runtime, provider); @@ -601,11 +604,11 @@ namespace hex::plugin::builtin { task.setInterruptCallback([&runtime] { runtime->abort(); }); std::map envVars; - for (const auto &[id, name, value, type] : this->m_envVarEntries) + for (const auto &[id, name, value, type] : patternLanguage.envVarEntries) envVars.insert({ name, value }); std::map inVariables; - for (auto &[name, variable] : this->m_patternVariables) { + for (auto &[name, variable] : patternLanguage.patternVariables) { if (variable.inVariable) inVariables[name] = variable.value; } @@ -621,13 +624,13 @@ namespace hex::plugin::builtin { }); ON_SCOPE_EXIT { - this->m_lastEvaluationLog = runtime->getConsoleLog(); - this->m_lastEvaluationOutVars = runtime->getOutVariables(); + patternLanguage.lastEvaluationLog = runtime->getConsoleLog(); + patternLanguage.lastEvaluationOutVars = runtime->getOutVariables(); this->m_runningEvaluators--; this->m_lastEvaluationProcessed = false; - this->m_lastEvaluationLog.emplace_back( + patternLanguage.lastEvaluationLog.emplace_back( pl::core::LogConsole::Level::Info, hex::format("Evaluation took {}", runtime->getLastRunningTime()) ); @@ -636,7 +639,7 @@ namespace hex::plugin::builtin { this->m_lastEvaluationResult = runtime->executeString(code, envVars, inVariables); if (!this->m_lastEvaluationResult) { - this->m_lastEvaluationError = runtime->getError(); + patternLanguage.lastEvaluationError = runtime->getError(); } }); } @@ -722,6 +725,8 @@ namespace hex::plugin::builtin { this->m_acceptPatternWindowOpen = true; } }); + + patternLanguageData.envVarEntries.push_back({ 0, "", 0, PlData::EnvVarType::Integer }); }); EventManager::subscribe(this, [this](prv::Provider *oldProvider, prv::Provider *newProvider) { @@ -773,6 +778,7 @@ namespace hex::plugin::builtin { void ViewPatternEditor::registerMenuItems() { ContentRegistry::Interface::addMenuItem("hex.builtin.menu.file", 2000, [&, this] { bool providerValid = ImHexApi::Provider::isValid(); + auto provider = ImHexApi::Provider::get(); if (ImGui::MenuItem("hex.builtin.view.pattern_editor.menu.file.load_pattern"_lang, nullptr, false, providerValid)) { @@ -790,8 +796,8 @@ namespace hex::plugin::builtin { } View::showFileChooserPopup(paths, { {"Pattern File", "hexpat"} }, - [this](const std::fs::path &path) { - this->loadPatternFile(path); + [this, provider](const std::fs::path &path) { + this->loadPatternFile(path, provider); }); }