diff --git a/lib/external/pattern_language b/lib/external/pattern_language index d70f027c0..ecef9505a 160000 --- a/lib/external/pattern_language +++ b/lib/external/pattern_language @@ -1 +1 @@ -Subproject commit d70f027c015b784140b3e8be60370df3e58c4fa6 +Subproject commit ecef9505afe9833f14e1ef80c2de64dd1e3d40f0 diff --git a/plugins/builtin/include/ui/pattern_drawer.hpp b/plugins/builtin/include/ui/pattern_drawer.hpp index f6ede7290..c3e8685dc 100644 --- a/plugins/builtin/include/ui/pattern_drawer.hpp +++ b/plugins/builtin/include/ui/pattern_drawer.hpp @@ -3,6 +3,7 @@ #include #include +#include #include #include @@ -81,6 +82,13 @@ namespace hex::plugin::builtin::ui { void traversePatternTree(pl::ptrn::Pattern &pattern, std::vector &patternPath, const std::function &callback); std::string getDisplayName(const pl::ptrn::Pattern& pattern) const; + struct Filter { + std::vector path; + std::optional value; + }; + + std::optional parseRValueFilter(const std::string &filter) const; + private: std::map m_displayEnd; std::vector m_sortedPatterns; @@ -95,7 +103,7 @@ namespace hex::plugin::builtin::ui { std::string m_lastVisualizerError; std::string m_filterText; - std::vector m_filter; + Filter m_filter; std::vector m_currPatternPath; std::map, std::unique_ptr> m_favorites; std::map>> m_groups; diff --git a/plugins/builtin/source/ui/pattern_drawer.cpp b/plugins/builtin/source/ui/pattern_drawer.cpp index f6da0062b..b206cac83 100644 --- a/plugins/builtin/source/ui/pattern_drawer.cpp +++ b/plugins/builtin/source/ui/pattern_drawer.cpp @@ -154,28 +154,52 @@ namespace hex::plugin::builtin::ui { } } - std::vector parseRValueFilter(const std::string &filter) { - std::vector result; + } - if (filter.empty()) { - return result; - } - - result.emplace_back(); - for (char c : filter) { - if (c == '.') - result.emplace_back(); - else if (c == '[') { - result.emplace_back(); - result.back() += c; - } else { - result.back() += c; - } - } + std::optional PatternDrawer::parseRValueFilter(const std::string &filter) const { + Filter result; + if (filter.empty()) { return result; } + result.path.emplace_back(); + for (size_t i = 0; i < filter.size(); i += 1) { + char c = filter[i]; + + if (i < filter.size() - 1 && c == '=' && filter[i + 1] == '=') { + try { + pl::core::Lexer lexer; + + auto source = filter.substr(i + 2); + auto tokens = lexer.lex(filter.substr(i + 2), filter.substr(i + 2)); + + if (!tokens.has_value() || tokens->size() != 2) + return std::nullopt; + + auto literal = std::get_if(&tokens->front().value); + if (literal == nullptr) + return std::nullopt; + + result.value = *literal; + } catch (pl::core::err::LexerError &error) { + return std::nullopt; + } + + break; + } else if (c == '.') + result.path.emplace_back(); + else if (c == '[') { + result.path.emplace_back(); + result.path.back() += c; + } else if (c == ' ') { + continue; + } else { + result.path.back() += c; + } + } + + return result; } bool PatternDrawer::isEditingPattern(const pl::ptrn::Pattern& pattern) const { @@ -813,8 +837,21 @@ namespace hex::plugin::builtin::ui { this->m_currPatternPath.push_back(pattern.getVariableName()); ON_SCOPE_EXIT { this->m_currPatternPath.pop_back(); }; - if (matchesFilter(this->m_filter, this->m_currPatternPath, false)) - pattern.accept(*this); + if (matchesFilter(this->m_filter.path, this->m_currPatternPath, false)) { + if (this->m_filter.value.has_value()) { + auto patternValue = pattern.getValue(); + if (patternValue == this->m_filter.value) + pattern.accept(*this); + else if (!matchesFilter(this->m_filter.path, this->m_currPatternPath, true)) + pattern.accept(*this); + else if (patternValue.isPattern() && this->m_filter.value->isString()) { + if (patternValue.toString(true) == this->m_filter.value->toString(false)) + pattern.accept(*this); + } + } else { + pattern.accept(*this); + } + } } void PatternDrawer::drawArray(pl::ptrn::Pattern& pattern, pl::ptrn::IIterable &iterable, bool isInlined) { @@ -1062,7 +1099,8 @@ namespace hex::plugin::builtin::ui { ImGui::PushItemWidth(ImGui::GetContentRegionAvail().x - ImGui::GetTextLineHeightWithSpacing() * 9.5); if (ImGui::InputTextIcon("##Search", ICON_VS_FILTER, this->m_filterText)) { - this->m_filter = parseRValueFilter(this->m_filterText); + if (auto result = parseRValueFilter(this->m_filterText); result.has_value()) + this->m_filter = *result; } ImGui::PopItemWidth();