From 80953a2286c5b9959e06b935896b63403cd430a1 Mon Sep 17 00:00:00 2001 From: WerWolv Date: Wed, 31 Jan 2024 11:26:22 +0100 Subject: [PATCH] feat: Allow jumping from hex editor to patterns and from patterns to source line --- lib/external/pattern_language | 2 +- .../include/hex/api/event_manager.hpp | 5 +++- lib/libimhex/source/api/imhex_api.cpp | 2 +- plugins/builtin/romfs/lang/en_US.json | 1 + .../source/content/views/view_hex_editor.cpp | 11 ++++++-- .../content/views/view_pattern_data.cpp | 10 +++++++- .../content/views/view_pattern_editor.cpp | 10 ++++++-- plugins/ui/include/ui/pattern_drawer.hpp | 7 ++++-- plugins/ui/source/ui/hex_editor.cpp | 2 +- plugins/ui/source/ui/pattern_drawer.cpp | 25 ++++++++++++++++++- 10 files changed, 63 insertions(+), 12 deletions(-) diff --git a/lib/external/pattern_language b/lib/external/pattern_language index 76c73d3a3..31c32e965 160000 --- a/lib/external/pattern_language +++ b/lib/external/pattern_language @@ -1 +1 @@ -Subproject commit 76c73d3a3ba90bb356907861c74deb2cafdd69ae +Subproject commit 31c32e965521d97bfcdca325af37e5243b9825f7 diff --git a/lib/libimhex/include/hex/api/event_manager.hpp b/lib/libimhex/include/hex/api/event_manager.hpp index fa90b359f..90f537c66 100644 --- a/lib/libimhex/include/hex/api/event_manager.hpp +++ b/lib/libimhex/include/hex/api/event_manager.hpp @@ -36,6 +36,7 @@ namespace hex { class View; } +namespace pl::ptrn { class Pattern; } namespace hex { @@ -274,7 +275,9 @@ namespace hex { EVENT_DEF(RequestAddInitTask, std::string, bool, std::function); EVENT_DEF(RequestAddExitTask, std::string, std::function); EVENT_DEF(RequestOpenWindow, std::string); - EVENT_DEF(RequestSelectionChange, Region); + EVENT_DEF(RequestHexEditorSelectionChange, Region); + EVENT_DEF(RequestPatternEditorSelectionChange, u32, u32); + EVENT_DEF(RequestJumpToPattern, const pl::ptrn::Pattern*); EVENT_DEF(RequestAddBookmark, Region, std::string, std::string, color_t, u64*); EVENT_DEF(RequestRemoveBookmark, u64); EVENT_DEF(RequestSetPatternLanguageCode, std::string); diff --git a/lib/libimhex/source/api/imhex_api.cpp b/lib/libimhex/source/api/imhex_api.cpp index 6e8d2dcf7..3b50a97d7 100644 --- a/lib/libimhex/source/api/imhex_api.cpp +++ b/lib/libimhex/source/api/imhex_api.cpp @@ -191,7 +191,7 @@ namespace hex { } void setSelection(const ProviderRegion ®ion) { - RequestSelectionChange::post(region); + RequestHexEditorSelectionChange::post(region); } void setSelection(u64 address, size_t size, prv::Provider *provider) { diff --git a/plugins/builtin/romfs/lang/en_US.json b/plugins/builtin/romfs/lang/en_US.json index 1cf6497be..e88a20e98 100644 --- a/plugins/builtin/romfs/lang/en_US.json +++ b/plugins/builtin/romfs/lang/en_US.json @@ -766,6 +766,7 @@ "hex.builtin.view.hex_editor.menu.edit.fill": "Fill...", "hex.builtin.view.hex_editor.menu.edit.insert": "Insert...", "hex.builtin.view.hex_editor.menu.edit.jump_to": "Jump to", + "hex.builtin.view.hex_editor.menu.edit.jump_to.curr_pattern": "Current Pattern", "hex.builtin.view.hex_editor.menu.edit.open_in_new_provider": "Open selection view...", "hex.builtin.view.hex_editor.menu.edit.paste": "Paste", "hex.builtin.view.hex_editor.menu.edit.paste_all": "Paste all", diff --git a/plugins/builtin/source/content/views/view_hex_editor.cpp b/plugins/builtin/source/content/views/view_hex_editor.cpp index a729fb753..d19400f8a 100644 --- a/plugins/builtin/source/content/views/view_hex_editor.cpp +++ b/plugins/builtin/source/content/views/view_hex_editor.cpp @@ -458,7 +458,7 @@ namespace hex::plugin::builtin { } ViewHexEditor::~ViewHexEditor() { - RequestSelectionChange::unsubscribe(this); + RequestHexEditorSelectionChange::unsubscribe(this); EventProviderChanged::unsubscribe(this); EventProviderOpened::unsubscribe(this); EventHighlightingChanged::unsubscribe(this); @@ -800,7 +800,7 @@ namespace hex::plugin::builtin { } void ViewHexEditor::registerEvents() { - RequestSelectionChange::subscribe(this, [this](Region region) { + RequestHexEditorSelectionChange::subscribe(this, [this](Region region) { auto provider = ImHexApi::Provider::get(); if (region == Region::Invalid()) { @@ -1136,6 +1136,13 @@ namespace hex::plugin::builtin { if (ImGui::MenuItem(hex::format("0x{:08X}", bigEndianValue).c_str(), "hex.ui.common.big_endian"_lang, false, canJumpTo(bigEndianValue))) { ImHexApi::HexEditor::setSelection(bigEndianValue, 1); } + + if (ImGui::MenuItem("hex.builtin.view.hex_editor.menu.edit.jump_to.curr_pattern"_lang, "", false, selection.has_value() && ContentRegistry::PatternLanguage::getRuntime().getCreatedPatternCount() > 0)) { + auto patterns = ContentRegistry::PatternLanguage::getRuntime().getPatternsAtAddress(selection->getStartAddress()); + + if (!patterns.empty()) + RequestJumpToPattern::post(patterns.front()); + } }, [] { return ImHexApi::Provider::isValid() && ImHexApi::HexEditor::isSelectionValid() && ImHexApi::HexEditor::getSelection()->getSize() <= sizeof(u64); }); diff --git a/plugins/builtin/source/content/views/view_pattern_data.cpp b/plugins/builtin/source/content/views/view_pattern_data.cpp index 4d9010d57..1c926e3d6 100644 --- a/plugins/builtin/source/content/views/view_pattern_data.cpp +++ b/plugins/builtin/source/content/views/view_pattern_data.cpp @@ -30,10 +30,18 @@ namespace hex::plugin::builtin { (*m_patternDrawer)->reset(); }); + RequestJumpToPattern::subscribe(this, [this](const pl::ptrn::Pattern *pattern) { + (*m_patternDrawer)->jumpToPattern(pattern); + }); + m_patternDrawer.setOnCreateCallback([this](prv::Provider *, auto &drawer) { drawer = std::make_unique(); - drawer->setSelectionCallback([](Region region){ ImHexApi::HexEditor::setSelection(region); }); + drawer->setSelectionCallback([](const pl::ptrn::Pattern *pattern) { + ImHexApi::HexEditor::setSelection(Region { pattern->getOffset(), pattern->getSize() }); + RequestPatternEditorSelectionChange::post(pattern->getLine(), 0); + }); + drawer->setTreeStyle(m_treeStyle); drawer->enableRowColoring(m_rowColoring); }); diff --git a/plugins/builtin/source/content/views/view_pattern_editor.cpp b/plugins/builtin/source/content/views/view_pattern_editor.cpp index 4557f723d..db7f4b0c9 100644 --- a/plugins/builtin/source/content/views/view_pattern_editor.cpp +++ b/plugins/builtin/source/content/views/view_pattern_editor.cpp @@ -192,6 +192,7 @@ namespace hex::plugin::builtin { } ViewPatternEditor::~ViewPatternEditor() { + RequestPatternEditorSelectionChange::unsubscribe(this); RequestSetPatternLanguageCode::unsubscribe(this); RequestRunPatternCode::unsubscribe(this); EventFileLoaded::unsubscribe(this); @@ -1111,8 +1112,8 @@ namespace hex::plugin::builtin { m_sectionWindowDrawer[patternProvider] = [this, id, patternProvider, dataProvider, hexEditor, patternDrawer = std::make_shared(), &runtime] mutable { hexEditor.setProvider(dataProvider.get()); hexEditor.draw(480_scaled); - patternDrawer->setSelectionCallback([&](const auto ®ion) { - hexEditor.setSelection(region); + patternDrawer->setSelectionCallback([&](const pl::ptrn::Pattern *pattern) { + hexEditor.setSelection(Region { pattern->getOffset(), pattern->getSize() }); }); const auto &patterns = [&, this] -> const auto& { @@ -1627,6 +1628,11 @@ namespace hex::plugin::builtin { } void ViewPatternEditor::registerEvents() { + RequestPatternEditorSelectionChange::subscribe(this, [this](u32 line, u32 column) { + const TextEditor::Coordinates coords = { int(line) - 1, int(column) }; + m_textEditor.SetCursorPosition(coords); + }); + RequestLoadPatternLanguageFile::subscribe(this, [this](const std::fs::path &path) { this->loadPatternFile(path, ImHexApi::Provider::get()); }); diff --git a/plugins/ui/include/ui/pattern_drawer.hpp b/plugins/ui/include/ui/pattern_drawer.hpp index 5447b85e8..4652cd85c 100644 --- a/plugins/ui/include/ui/pattern_drawer.hpp +++ b/plugins/ui/include/ui/pattern_drawer.hpp @@ -31,10 +31,12 @@ namespace hex::ui { }; void setTreeStyle(TreeStyle style) { m_treeStyle = style; } - void setSelectionCallback(std::function callback) { m_selectionCallback = std::move(callback); } + void setSelectionCallback(std::function callback) { m_selectionCallback = std::move(callback); } void enableRowColoring(bool enabled) { m_rowColoring = enabled; } void reset(); + void jumpToPattern(const pl::ptrn::Pattern *pattern) { m_jumpToPattern = pattern; } + private: void draw(pl::ptrn::Pattern& pattern); @@ -100,6 +102,7 @@ namespace hex::ui { TreeStyle m_treeStyle = TreeStyle::Default; bool m_rowColoring = false; pl::ptrn::Pattern *m_currVisualizedPattern = nullptr; + const pl::ptrn::Pattern *m_jumpToPattern = nullptr; std::set m_visualizedPatterns; std::string m_lastVisualizerError; @@ -115,7 +118,7 @@ namespace hex::ui { TaskHolder m_favoritesUpdateTask; - std::function m_selectionCallback = [](Region) { }; + std::function m_selectionCallback = [](const pl::ptrn::Pattern *) { }; pl::gen::fmt::FormatterArray m_formatters; }; diff --git a/plugins/ui/source/ui/hex_editor.cpp b/plugins/ui/source/ui/hex_editor.cpp index 48a4d577e..05ad75ad6 100644 --- a/plugins/ui/source/ui/hex_editor.cpp +++ b/plugins/ui/source/ui/hex_editor.cpp @@ -1032,7 +1032,7 @@ namespace hex::ui { this->setSelection(selectionStart.value_or(address), endAddress); this->scrollToSelection(); } - else if (ImGui::IsMouseClicked(ImGuiMouseButton_Left)) { + else if (ImGui::IsMouseDown(ImGuiMouseButton_Left) || (ImGui::IsMouseDown(ImGuiMouseButton_Right) && (address < m_selectionStart || address > m_selectionEnd))) { if (ImGui::GetIO().KeyShift) this->setSelection(selectionStart.value_or(address), endAddress); else diff --git a/plugins/ui/source/ui/pattern_drawer.cpp b/plugins/ui/source/ui/pattern_drawer.cpp index b5bf975d3..31d824ffd 100644 --- a/plugins/ui/source/ui/pattern_drawer.cpp +++ b/plugins/ui/source/ui/pattern_drawer.cpp @@ -342,6 +342,26 @@ namespace hex::ui { bool PatternDrawer::createTreeNode(const pl::ptrn::Pattern& pattern, bool leaf) { drawFavoriteColumn(pattern); + bool shouldOpen = false; + if (m_jumpToPattern != nullptr) { + if (m_jumpToPattern == &pattern) { + ImGui::SetScrollHereY(); + m_jumpToPattern = nullptr; + } + else { + auto parent = m_jumpToPattern->getParent(); + while (parent != nullptr) { + if (&pattern == parent) { + ImGui::SetScrollHereY(); + shouldOpen = true; + break; + } + + parent = parent->getParent(); + } + } + } + if (pattern.isSealed() || leaf) { ImGui::Indent(); highlightWhenSelected(pattern, [&]{ ImGui::TextUnformatted(this->getDisplayName(pattern).c_str()); }); @@ -350,6 +370,9 @@ namespace hex::ui { } return highlightWhenSelected(pattern, [&]{ + if (shouldOpen) + ImGui::SetNextItemOpen(true, ImGuiCond_Always); + switch (m_treeStyle) { using enum TreeStyle; default: @@ -368,7 +391,7 @@ namespace hex::ui { ImGui::PushID(pattern.getVariableName().c_str()); if (ImGui::Selectable("##PatternLine", false, ImGuiSelectableFlags_SpanAllColumns | ImGuiSelectableFlags_AllowOverlap)) { - m_selectionCallback(Region { pattern.getOffset(), pattern.getSize() }); + m_selectionCallback(&pattern); if (m_editingPattern != &pattern) { this->resetEditing();