mirror of https://github.com/WerWolv/ImHex
fix: Crashes and usability issues with the pattern tree filter
This commit is contained in:
parent
8f57dd86af
commit
980438008c
|
|
@ -1 +1 @@
|
||||||
Subproject commit 7b2a0523ee8bb235cb1a8591eef969095e6c4fe2
|
Subproject commit 32394f789a81a5401d905689a5ea52a6634005f5
|
||||||
|
|
@ -85,7 +85,7 @@ namespace hex::ui {
|
||||||
void drawColorColumn(const pl::ptrn::Pattern& pattern);
|
void drawColorColumn(const pl::ptrn::Pattern& pattern);
|
||||||
void drawCommentColumn(const pl::ptrn::Pattern& pattern);
|
void drawCommentColumn(const pl::ptrn::Pattern& pattern);
|
||||||
|
|
||||||
bool beginPatternTable(const std::vector<std::shared_ptr<pl::ptrn::Pattern>> &patterns, std::vector<pl::ptrn::Pattern*> &sortedPatterns, float height) const;
|
bool beginPatternTable(const std::vector<std::shared_ptr<pl::ptrn::Pattern>> &patterns, std::vector<std::shared_ptr<pl::ptrn::Pattern>> &sortedPatterns, float height) const;
|
||||||
bool createTreeNode(const pl::ptrn::Pattern& pattern, bool leaf = false);
|
bool createTreeNode(const pl::ptrn::Pattern& pattern, bool leaf = false);
|
||||||
void createDefaultEntry(const pl::ptrn::Pattern &pattern);
|
void createDefaultEntry(const pl::ptrn::Pattern &pattern);
|
||||||
void closeTreeNode(bool inlined) const;
|
void closeTreeNode(bool inlined) const;
|
||||||
|
|
@ -93,23 +93,28 @@ namespace hex::ui {
|
||||||
bool sortPatterns(const ImGuiTableSortSpecs* sortSpecs, const pl::ptrn::Pattern * left, const pl::ptrn::Pattern * right) const;
|
bool sortPatterns(const ImGuiTableSortSpecs* sortSpecs, const pl::ptrn::Pattern * left, const pl::ptrn::Pattern * right) const;
|
||||||
[[nodiscard]] bool isEditingPattern(const pl::ptrn::Pattern& pattern) const;
|
[[nodiscard]] bool isEditingPattern(const pl::ptrn::Pattern& pattern) const;
|
||||||
void resetEditing();
|
void resetEditing();
|
||||||
void traversePatternTree(pl::ptrn::Pattern &pattern, std::vector<std::string> &patternPath, const std::function<void(pl::ptrn::Pattern&)> &callback);
|
void traversePatternTree(const std::shared_ptr<pl::ptrn::Pattern> &pattern, std::vector<std::string> &patternPath, const std::function<void(const std::shared_ptr<pl::ptrn::Pattern>&)> &callback);
|
||||||
[[nodiscard]] std::string getDisplayName(const pl::ptrn::Pattern& pattern) const;
|
[[nodiscard]] std::string getDisplayName(const pl::ptrn::Pattern& pattern) const;
|
||||||
|
|
||||||
[[nodiscard]] std::vector<std::string> getPatternPath(const pl::ptrn::Pattern *pattern) const;
|
[[nodiscard]] std::vector<std::string> getPatternPath(const pl::ptrn::Pattern *pattern) const;
|
||||||
|
|
||||||
struct Filter {
|
struct Filter {
|
||||||
std::vector<std::string> path;
|
std::vector<std::string> path;
|
||||||
|
|
||||||
|
bool inverted = false;
|
||||||
|
bool typeMatch = false;
|
||||||
|
std::strong_ordering operation = std::strong_ordering::equal;
|
||||||
std::optional<pl::core::Token::Literal> value;
|
std::optional<pl::core::Token::Literal> value;
|
||||||
};
|
};
|
||||||
|
|
||||||
[[nodiscard]] static bool matchesFilter(const std::vector<std::string> &filterPath, const std::vector<std::string> &patternPath, bool fullMatch);
|
[[nodiscard]] static bool matchesFilter(const std::vector<std::string> &filterPath, const std::vector<std::string> &patternPath, bool fullMatch);
|
||||||
[[nodiscard]] static std::optional<Filter> parseRValueFilter(const std::string &filter);
|
[[nodiscard]] static std::optional<Filter> parseRValueFilter(const std::string &filter);
|
||||||
|
[[nodiscard]] static std::optional<Filter> parseComparison(const Filter &currFilter, std::string filterString);
|
||||||
void updateFilter();
|
void updateFilter();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::map<const pl::ptrn::Pattern*, u64> m_displayEnd;
|
std::map<const pl::ptrn::Pattern*, u64> m_displayEnd;
|
||||||
std::vector<pl::ptrn::Pattern*> m_sortedPatterns;
|
std::vector<std::shared_ptr<pl::ptrn::Pattern>> m_sortedPatterns;
|
||||||
|
|
||||||
const pl::ptrn::Pattern *m_editingPattern = nullptr;
|
const pl::ptrn::Pattern *m_editingPattern = nullptr;
|
||||||
u64 m_editingPatternOffset = 0;
|
u64 m_editingPatternOffset = 0;
|
||||||
|
|
@ -125,8 +130,8 @@ namespace hex::ui {
|
||||||
std::set<pl::ptrn::Pattern*> m_visualizedPatterns;
|
std::set<pl::ptrn::Pattern*> m_visualizedPatterns;
|
||||||
|
|
||||||
std::string m_filterText;
|
std::string m_filterText;
|
||||||
Filter m_filter;
|
std::optional<Filter> m_filter;
|
||||||
std::vector<pl::ptrn::Pattern*> m_filteredPatterns;
|
std::vector<std::shared_ptr<pl::ptrn::Pattern>> m_filteredPatterns;
|
||||||
|
|
||||||
std::vector<std::string> m_currPatternPath;
|
std::vector<std::string> m_currPatternPath;
|
||||||
std::map<std::vector<std::string>, std::shared_ptr<pl::ptrn::Pattern>> m_favorites;
|
std::map<std::vector<std::string>, std::shared_ptr<pl::ptrn::Pattern>> m_favorites;
|
||||||
|
|
|
||||||
|
|
@ -32,6 +32,8 @@
|
||||||
#include <imgui.h>
|
#include <imgui.h>
|
||||||
#include <hex/ui/imgui_imhex_extensions.h>
|
#include <hex/ui/imgui_imhex_extensions.h>
|
||||||
#include <fonts/vscode_icons.hpp>
|
#include <fonts/vscode_icons.hpp>
|
||||||
|
#include <hex/api/tutorial_manager.hpp>
|
||||||
|
#include <pl/core/ast/ast_node_mathematical_expression.hpp>
|
||||||
|
|
||||||
#include <wolv/io/file.hpp>
|
#include <wolv/io/file.hpp>
|
||||||
|
|
||||||
|
|
@ -197,6 +199,61 @@ namespace hex::ui {
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
std::optional<PatternDrawer::Filter> PatternDrawer::parseComparison(const Filter &currFilter, std::string filterString) {
|
||||||
|
auto result = currFilter;
|
||||||
|
|
||||||
|
pl::core::Lexer lexer;
|
||||||
|
|
||||||
|
filterString = wolv::util::trim(filterString);
|
||||||
|
if (filterString.empty())
|
||||||
|
return std::nullopt;
|
||||||
|
else if (filterString.starts_with("===")) {
|
||||||
|
result.operation = std::strong_ordering::equal;
|
||||||
|
result.inverted = false;
|
||||||
|
result.typeMatch = true;
|
||||||
|
filterString = filterString.substr(3);
|
||||||
|
} else if (filterString.starts_with("==")) {
|
||||||
|
result.operation = std::strong_ordering::equal;
|
||||||
|
result.inverted = false;
|
||||||
|
filterString = filterString.substr(2);
|
||||||
|
} else if (filterString.starts_with("!=")) {
|
||||||
|
result.operation = std::strong_ordering::equal;
|
||||||
|
result.inverted = true;
|
||||||
|
filterString = filterString.substr(2);
|
||||||
|
} else if (filterString.starts_with(">=")) {
|
||||||
|
result.operation = std::strong_ordering::less;
|
||||||
|
result.inverted = true;
|
||||||
|
filterString = filterString.substr(2);
|
||||||
|
} else if (filterString.starts_with("<=")) {
|
||||||
|
result.operation = std::strong_ordering::greater;
|
||||||
|
result.inverted = true;
|
||||||
|
filterString = filterString.substr(2);
|
||||||
|
} else if (filterString.starts_with(">")) {
|
||||||
|
result.operation = std::strong_ordering::greater;
|
||||||
|
result.inverted = false;
|
||||||
|
filterString = filterString.substr(1);
|
||||||
|
} else if (filterString.starts_with("<")) {
|
||||||
|
result.operation = std::strong_ordering::less;
|
||||||
|
result.inverted = false;
|
||||||
|
filterString = filterString.substr(1);
|
||||||
|
} else {
|
||||||
|
return std::nullopt;
|
||||||
|
}
|
||||||
|
|
||||||
|
pl::api::Source source(filterString);
|
||||||
|
auto tokens = lexer.lex(&source);
|
||||||
|
|
||||||
|
if (!tokens.isOk() || tokens.unwrap().size() != 2)
|
||||||
|
return std::nullopt;
|
||||||
|
|
||||||
|
auto literal = std::get_if<pl::core::Token::Literal>(&tokens.unwrap().front().value);
|
||||||
|
if (literal == nullptr)
|
||||||
|
return std::nullopt;
|
||||||
|
result.value = *literal;
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
std::optional<PatternDrawer::Filter> PatternDrawer::parseRValueFilter(const std::string &filter) {
|
std::optional<PatternDrawer::Filter> PatternDrawer::parseRValueFilter(const std::string &filter) {
|
||||||
Filter result;
|
Filter result;
|
||||||
|
|
||||||
|
|
@ -208,30 +265,30 @@ namespace hex::ui {
|
||||||
for (size_t i = 0; i < filter.size(); i += 1) {
|
for (size_t i = 0; i < filter.size(); i += 1) {
|
||||||
char c = filter[i];
|
char c = filter[i];
|
||||||
|
|
||||||
if (i < filter.size() - 1 && c == '=' && filter[i + 1] == '=') {
|
if (c == '.') {
|
||||||
pl::core::Lexer lexer;
|
if (result.path.back().empty())
|
||||||
|
|
||||||
pl::api::Source source(filter.substr(i + 2));
|
|
||||||
auto tokens = lexer.lex(&source);
|
|
||||||
|
|
||||||
if (!tokens.isOk() || tokens.unwrap().size() != 2)
|
|
||||||
return std::nullopt;
|
return std::nullopt;
|
||||||
|
|
||||||
auto literal = std::get_if<pl::core::Token::Literal>(&tokens.unwrap().front().value);
|
|
||||||
if (literal == nullptr)
|
|
||||||
return std::nullopt;
|
|
||||||
result.value = *literal;
|
|
||||||
|
|
||||||
break;
|
|
||||||
} else if (c == '.') {
|
|
||||||
result.path.emplace_back();
|
result.path.emplace_back();
|
||||||
|
} else if (c == '*') {
|
||||||
|
if (!result.path.back().empty())
|
||||||
|
return std::nullopt;
|
||||||
|
|
||||||
|
result.path.back() = "*";
|
||||||
} else if (c == '[') {
|
} else if (c == '[') {
|
||||||
result.path.emplace_back();
|
result.path.emplace_back();
|
||||||
result.path.back() += c;
|
result.path.back() += c;
|
||||||
|
} else if (c == ']') {
|
||||||
|
result.path.back() += c;
|
||||||
} else if (c == ' ') {
|
} else if (c == ' ') {
|
||||||
// Skip whitespace
|
// Skip whitespace
|
||||||
} else {
|
} else if (std::isalnum(c) || c == '_') {
|
||||||
|
if (result.path.back() == "*")
|
||||||
|
return std::nullopt;
|
||||||
|
|
||||||
result.path.back() += c;
|
result.path.back() += c;
|
||||||
|
} else {
|
||||||
|
return parseComparison(result, filter.substr(i));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -241,7 +298,10 @@ namespace hex::ui {
|
||||||
void PatternDrawer::updateFilter() {
|
void PatternDrawer::updateFilter() {
|
||||||
m_filteredPatterns.clear();
|
m_filteredPatterns.clear();
|
||||||
|
|
||||||
if (m_filter.path.empty()) {
|
if (!m_filter.has_value())
|
||||||
|
return;
|
||||||
|
|
||||||
|
if (m_filter->path.empty()) {
|
||||||
m_filteredPatterns = m_sortedPatterns;
|
m_filteredPatterns = m_sortedPatterns;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
@ -251,13 +311,23 @@ namespace hex::ui {
|
||||||
if (m_filteredPatterns.size() > m_maxFilterDisplayItems)
|
if (m_filteredPatterns.size() > m_maxFilterDisplayItems)
|
||||||
break;
|
break;
|
||||||
|
|
||||||
traversePatternTree(*pattern, treePath, [this, &treePath](auto &pattern) {
|
traversePatternTree(pattern, treePath, [this, &treePath](auto &pattern) {
|
||||||
if (m_filteredPatterns.size() > m_maxFilterDisplayItems)
|
if (m_filteredPatterns.size() > m_maxFilterDisplayItems)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
if (matchesFilter(m_filter.path, treePath, false)) {
|
if (matchesFilter(m_filter->path, treePath, false)) {
|
||||||
if (!m_filter.value.has_value() || pattern.getValue() == m_filter.value)
|
if (!m_filter->value.has_value()) {
|
||||||
m_filteredPatterns.push_back(&pattern);
|
m_filteredPatterns.push_back(pattern);
|
||||||
|
} else {
|
||||||
|
auto patternValue = pattern->getValue();
|
||||||
|
if (!m_filter->inverted && (patternValue <=> m_filter->value) == m_filter->operation) {
|
||||||
|
if (!m_filter->typeMatch || (m_filter->value->index() == patternValue.index()))
|
||||||
|
m_filteredPatterns.push_back(pattern);
|
||||||
|
} else if (m_filter->inverted && (patternValue <=> m_filter->value) != m_filter->operation) {
|
||||||
|
if (!m_filter->typeMatch || (m_filter->value->index() == patternValue.index()))
|
||||||
|
m_filteredPatterns.push_back(pattern);
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
@ -608,7 +678,7 @@ namespace hex::ui {
|
||||||
}
|
}
|
||||||
|
|
||||||
int id = 1;
|
int id = 1;
|
||||||
pattern.forEachEntry(0, pattern.getEntryCount(), [&] (u64, auto *field) {
|
pattern.forEachEntry(0, pattern.getEntryCount(), [&] (u64, const auto &field) {
|
||||||
ImGui::PushID(id);
|
ImGui::PushID(id);
|
||||||
this->draw(*field);
|
this->draw(*field);
|
||||||
ImGui::PopID();
|
ImGui::PopID();
|
||||||
|
|
@ -804,7 +874,7 @@ namespace hex::ui {
|
||||||
}
|
}
|
||||||
|
|
||||||
int id = 1;
|
int id = 1;
|
||||||
pattern.forEachEntry(0, pattern.getEntryCount(), [&](u64, auto *member){
|
pattern.forEachEntry(0, pattern.getEntryCount(), [&](u64, const auto &member){
|
||||||
ImGui::PushID(id);
|
ImGui::PushID(id);
|
||||||
this->draw(*member);
|
this->draw(*member);
|
||||||
ImGui::PopID();
|
ImGui::PopID();
|
||||||
|
|
@ -849,7 +919,7 @@ namespace hex::ui {
|
||||||
}
|
}
|
||||||
|
|
||||||
int id = 1;
|
int id = 1;
|
||||||
pattern.forEachEntry(0, pattern.getEntryCount(), [&](u64, auto *member) {
|
pattern.forEachEntry(0, pattern.getEntryCount(), [&](u64, const auto &member) {
|
||||||
ImGui::PushID(id);
|
ImGui::PushID(id);
|
||||||
this->draw(*member);
|
this->draw(*member);
|
||||||
ImGui::PopID();
|
ImGui::PopID();
|
||||||
|
|
@ -1051,7 +1121,7 @@ namespace hex::ui {
|
||||||
}
|
}
|
||||||
|
|
||||||
int id = 1;
|
int id = 1;
|
||||||
iterable.forEachEntry(i, endIndex, [&](u64, auto *entry){
|
iterable.forEachEntry(i, endIndex, [&](u64, const auto &entry){
|
||||||
ImGui::PushID(id);
|
ImGui::PushID(id);
|
||||||
this->draw(*entry);
|
this->draw(*entry);
|
||||||
ImGui::PopID();
|
ImGui::PopID();
|
||||||
|
|
@ -1100,7 +1170,7 @@ namespace hex::ui {
|
||||||
return sortSpecs->Specs->SortDirection == ImGuiSortDirection_Ascending ? result == std::strong_ordering::less : result == std::strong_ordering::greater;
|
return sortSpecs->Specs->SortDirection == ImGuiSortDirection_Ascending ? result == std::strong_ordering::less : result == std::strong_ordering::greater;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool PatternDrawer::beginPatternTable(const std::vector<std::shared_ptr<pl::ptrn::Pattern>> &patterns, std::vector<pl::ptrn::Pattern*> &sortedPatterns, float height) const {
|
bool PatternDrawer::beginPatternTable(const std::vector<std::shared_ptr<pl::ptrn::Pattern>> &patterns, std::vector<std::shared_ptr<pl::ptrn::Pattern>> &sortedPatterns, float height) const {
|
||||||
if (!ImGui::BeginTable("##Patterntable", 9, ImGuiTableFlags_Borders | ImGuiTableFlags_Resizable | ImGuiTableFlags_Sortable | ImGuiTableFlags_Hideable | ImGuiTableFlags_Reorderable | ImGuiTableFlags_RowBg | ImGuiTableFlags_ScrollY, ImVec2(0, height))) {
|
if (!ImGui::BeginTable("##Patterntable", 9, ImGuiTableFlags_Borders | ImGuiTableFlags_Resizable | ImGuiTableFlags_Sortable | ImGuiTableFlags_Hideable | ImGuiTableFlags_Reorderable | ImGuiTableFlags_RowBg | ImGuiTableFlags_ScrollY, ImVec2(0, height))) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
@ -1128,13 +1198,10 @@ namespace hex::ui {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!m_favoritesUpdateTask.isRunning()) {
|
if (!m_favoritesUpdateTask.isRunning()) {
|
||||||
sortedPatterns.clear();
|
sortedPatterns = patterns;
|
||||||
std::transform(patterns.begin(), patterns.end(), std::back_inserter(sortedPatterns), [](const std::shared_ptr<pl::ptrn::Pattern> &pattern) {
|
|
||||||
return pattern.get();
|
|
||||||
});
|
|
||||||
|
|
||||||
std::stable_sort(sortedPatterns.begin(), sortedPatterns.end(), [this, &sortSpecs](const pl::ptrn::Pattern *left, const pl::ptrn::Pattern *right) -> bool {
|
std::stable_sort(sortedPatterns.begin(), sortedPatterns.end(), [this, &sortSpecs](const std::shared_ptr<pl::ptrn::Pattern> &left, const std::shared_ptr<pl::ptrn::Pattern> &right) -> bool {
|
||||||
return this->sortPatterns(sortSpecs, left, right);
|
return this->sortPatterns(sortSpecs, left.get(), right.get());
|
||||||
});
|
});
|
||||||
|
|
||||||
for (auto &pattern : sortedPatterns) {
|
for (auto &pattern : sortedPatterns) {
|
||||||
|
|
@ -1149,14 +1216,18 @@ namespace hex::ui {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void PatternDrawer::traversePatternTree(pl::ptrn::Pattern &pattern, std::vector<std::string> &patternPath, const std::function<void(pl::ptrn::Pattern&)> &callback) {
|
void PatternDrawer::traversePatternTree(const std::shared_ptr<pl::ptrn::Pattern> &pattern, std::vector<std::string> &patternPath, const std::function<void(const std::shared_ptr<pl::ptrn::Pattern>&)> &callback) {
|
||||||
patternPath.push_back(pattern.getVariableName());
|
patternPath.push_back(pattern->getVariableName());
|
||||||
ON_SCOPE_EXIT { patternPath.pop_back(); };
|
ON_SCOPE_EXIT { patternPath.pop_back(); };
|
||||||
|
|
||||||
callback(pattern);
|
callback(pattern);
|
||||||
if (auto iterable = dynamic_cast<pl::ptrn::IIterable*>(&pattern); iterable != nullptr) {
|
if (auto iterable = dynamic_cast<pl::ptrn::IIterable*>(pattern.get()); iterable != nullptr) {
|
||||||
iterable->forEachEntry(0, iterable->getEntryCount(), [&](u64, pl::ptrn::Pattern *entry) {
|
// Don't index individual characters of strings
|
||||||
traversePatternTree(*entry, patternPath, callback);
|
if (dynamic_cast<pl::ptrn::PatternString*>(pattern.get()) || dynamic_cast<pl::ptrn::PatternWideString*>(pattern.get()))
|
||||||
|
return;
|
||||||
|
|
||||||
|
iterable->forEachEntry(0, iterable->getEntryCount(), [&](u64, const auto &entry) {
|
||||||
|
traversePatternTree(entry, patternPath, callback);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -1199,10 +1270,48 @@ namespace hex::ui {
|
||||||
|
|
||||||
auto &style = ImGui::GetStyle();
|
auto &style = ImGui::GetStyle();
|
||||||
ImGui::PushItemWidth(-(style.ItemSpacing.x * 2 + style.WindowPadding.x * 2 + ImGui::GetTextLineHeightWithSpacing() * 5 + 15_scaled));
|
ImGui::PushItemWidth(-(style.ItemSpacing.x * 2 + style.WindowPadding.x * 2 + ImGui::GetTextLineHeightWithSpacing() * 5 + 15_scaled));
|
||||||
if (ImGuiExt::InputTextIcon("##Search", ICON_VS_FILTER, m_filterText)) {
|
|
||||||
m_filter = parseRValueFilter(m_filterText).value_or(Filter{ });
|
const bool filterError = !m_filterText.empty() && !m_filter.has_value();
|
||||||
updateFilter();
|
|
||||||
|
if (filterError) {
|
||||||
|
ImGui::PushStyleColor(ImGuiCol_Border, ImGuiExt::GetCustomColorU32(ImGuiCustomCol_LoggerError));
|
||||||
|
ImGui::PushStyleVar(ImGuiStyleVar_FrameBorderSize, 1_scaled);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (ImGuiExt::InputTextIcon("##Search", ICON_VS_FILTER, m_filterText)) {
|
||||||
|
auto newFilter = parseRValueFilter(m_filterText);
|
||||||
|
|
||||||
|
if (m_filterText.empty()) {
|
||||||
|
m_filter.reset();
|
||||||
|
updateFilter();
|
||||||
|
} else if (!newFilter.has_value()) {
|
||||||
|
m_filter.reset();
|
||||||
|
m_filteredPatterns.clear();
|
||||||
|
} else {
|
||||||
|
m_filter = newFilter;
|
||||||
|
updateFilter();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TutorialManager::setLastItemInteractiveHelpPopup([] {
|
||||||
|
ImGuiExt::TextFormattedWrapped("{}",
|
||||||
|
"Allows filtering of the pattern tree using the following syntax:\n\n"
|
||||||
|
"- variable_name: Shows all patterns with this name\n"
|
||||||
|
"- container.var: Shows all patterns named var that are inside a pattern called container\n"
|
||||||
|
"- a.*.b: Searches all children of pattern a for a pattern named b\n"
|
||||||
|
"- a[10].b: Shows patterns named b inside the 10th array entry of a pattern named a\n"
|
||||||
|
"- x > 10: Shows all patterns named x that have a value greater than 10\n"
|
||||||
|
"- a.b == 100: Shows all patterns named b with a value of 100 that are inside a pattern named a\n"
|
||||||
|
"- a == \"Hello\": Shows all patterns named a whose value is the string \"Hello\"\n\n"
|
||||||
|
"If nothing was found, the tree will be empty. If there was a parsing error, the filter text field will be highlighted in red."
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
if (filterError) {
|
||||||
|
ImGui::PopStyleColor();
|
||||||
|
ImGui::PopStyleVar();
|
||||||
|
}
|
||||||
|
|
||||||
ImGui::PopItemWidth();
|
ImGui::PopItemWidth();
|
||||||
|
|
||||||
ImGui::SameLine();
|
ImGui::SameLine();
|
||||||
|
|
@ -1322,7 +1431,7 @@ namespace hex::ui {
|
||||||
|
|
||||||
m_showFavoriteStars = true;
|
m_showFavoriteStars = true;
|
||||||
|
|
||||||
for (auto &pattern : m_filter.path.empty() ? m_sortedPatterns : m_filteredPatterns) {
|
for (auto &pattern : m_filterText.empty() ? m_sortedPatterns : m_filteredPatterns) {
|
||||||
ImGui::PushID(id);
|
ImGui::PushID(id);
|
||||||
this->draw(*pattern);
|
this->draw(*pattern);
|
||||||
ImGui::PopID();
|
ImGui::PopID();
|
||||||
|
|
@ -1372,14 +1481,14 @@ namespace hex::ui {
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
patternPath.clear();
|
patternPath.clear();
|
||||||
traversePatternTree(*pattern, patternPath, [&, this](const pl::ptrn::Pattern &currPattern) {
|
traversePatternTree(pattern, patternPath, [&, this](const std::shared_ptr<pl::ptrn::Pattern> &currPattern) {
|
||||||
for (auto &[path, favoritePattern] : m_favorites) {
|
for (auto &[path, favoritePattern] : m_favorites) {
|
||||||
if (updatedFavorites == m_favorites.size())
|
if (updatedFavorites == m_favorites.size())
|
||||||
task.interrupt();
|
task.interrupt();
|
||||||
task.update();
|
task.update();
|
||||||
|
|
||||||
if (matchesFilter(patternPath, path, true)) {
|
if (matchesFilter(patternPath, path, true)) {
|
||||||
favoritePattern = currPattern.clone();
|
favoritePattern = currPattern->clone();
|
||||||
updatedFavorites += 1;
|
updatedFavorites += 1;
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
|
||||||
|
|
@ -29,9 +29,9 @@ namespace hex::plugin::visualizers {
|
||||||
dataPoints.clear();
|
dataPoints.clear();
|
||||||
lastPoint = { 0, 0 };
|
lastPoint = { 0, 0 };
|
||||||
|
|
||||||
bitfield->forEachEntry(0, bitfield->getEntryCount(), [&](u64, pl::ptrn::Pattern *entry) {
|
bitfield->forEachEntry(0, bitfield->getEntryCount(), [&](u64, const auto &entry) {
|
||||||
size_t bitSize;
|
size_t bitSize;
|
||||||
if (const auto *bitfieldField = dynamic_cast<pl::ptrn::PatternBitfieldField*>(entry); bitfieldField != nullptr)
|
if (const auto *bitfieldField = dynamic_cast<pl::ptrn::PatternBitfieldField*>(entry.get()); bitfieldField != nullptr)
|
||||||
bitSize = bitfieldField->getBitSize();
|
bitSize = bitfieldField->getBitSize();
|
||||||
else
|
else
|
||||||
bitSize = entry->getSize() * 8;
|
bitSize = entry->getSize() * 8;
|
||||||
|
|
|
||||||
|
|
@ -33,7 +33,7 @@ namespace hex::plugin::visualizers {
|
||||||
height = u64(arguments[2].toUnsigned());
|
height = u64(arguments[2].toUnsigned());
|
||||||
|
|
||||||
auto iterable = dynamic_cast<pl::ptrn::IIterable*>(pattern.get());
|
auto iterable = dynamic_cast<pl::ptrn::IIterable*>(pattern.get());
|
||||||
iterable->forEachEntry(0, iterable->getEntryCount(), [&](u64, pl::ptrn::Pattern *entry) {
|
iterable->forEachEntry(0, iterable->getEntryCount(), [&](u64, const auto &entry) {
|
||||||
tableContent.push_back(entry->toString());
|
tableContent.push_back(entry->toString());
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue