impr: Move items from pattern editor console area to more appropriate places

This commit is contained in:
WerWolv
2025-09-09 22:30:29 +02:00
parent be66e3fe79
commit 32e3a4e74f
17 changed files with 298 additions and 210 deletions

View File

@@ -6,6 +6,8 @@
#include <hex/api/events/events_interaction.hpp>
#include <fonts/vscode_icons.hpp>
#include <fonts/tabler_icons.hpp>
#include <imgui_internal.h>
#include <pl/patterns/pattern.hpp>
@@ -40,6 +42,7 @@ namespace hex::plugin::builtin {
});
EventPatternEvaluating::subscribe(this, [this]{
m_virtualFiles->clear();
for (auto &drawers : m_patternDrawer.all())
for (auto &[id, drawer] : drawers)
drawer->reset();
@@ -83,6 +86,10 @@ namespace hex::plugin::builtin {
(*m_patternDrawer)[0]->jumpToPattern(pattern);
});
RequestAddVirtualFile::subscribe(this, [this](const std::fs::path &path, const std::vector<u8> &data, Region region) {
m_virtualFiles->emplace_back(path, data, region);
});
ImHexApi::HexEditor::addHoverHighlightProvider([this](const prv::Provider *, u64, size_t) -> std::set<Region> {
return { m_hoveredPatternRegion };
});
@@ -93,6 +100,105 @@ namespace hex::plugin::builtin {
EventPatternExecuted::unsubscribe(this);
}
static void loadPatternAsMemoryProvider(const VirtualFile *file) {
ImHexApi::Provider::add<prv::MemoryProvider>(file->data, wolv::util::toUTF8String(file->path.filename()));
}
static void drawVirtualFileTree(const std::vector<const VirtualFile*> &virtualFiles, u32 level = 0) {
static int levelId = 0;
if (level == 0)
levelId = 1;
ImGui::PushID(level + 1);
ON_SCOPE_EXIT { ImGui::PopID(); };
std::map<std::string, std::vector<const VirtualFile*>> currFolderEntries;
for (const auto &file : virtualFiles) {
const auto &path = file->path;
auto currSegment = wolv::io::fs::toNormalizedPathString(*std::next(path.begin(), level));
if (std::distance(path.begin(), path.end()) == ptrdiff_t(level + 1)) {
ImGui::TableNextRow();
ImGui::TableNextColumn();
ImGui::TextUnformatted(ICON_VS_FILE);
ImGui::PushID(levelId);
ImGui::SameLine();
ImGui::TreeNodeEx(currSegment.c_str(), ImGuiTreeNodeFlags_DrawLinesToNodes | ImGuiTreeNodeFlags_SpanFullWidth | ImGuiTreeNodeFlags_Leaf | ImGuiTreeNodeFlags_NoTreePushOnOpen);
if (ImGui::IsMouseDown(ImGuiMouseButton_Right) && ImGui::IsItemHovered() && !ImGui::IsMouseDragging(ImGuiMouseButton_Right)) {
ImGui::OpenPopup("##virtual_files_context_menu");
}
if (ImGui::BeginPopup("##virtual_files_context_menu")) {
if (ImGui::MenuItem("hex.builtin.view.hex_editor.menu.edit.open_in_new_provider"_lang, nullptr, false)) {
loadPatternAsMemoryProvider(file);
}
ImGui::EndPopup();
}
if (ImGui::IsMouseDoubleClicked(ImGuiMouseButton_Left) && ImGui::IsItemHovered()) {
loadPatternAsMemoryProvider(file);
}
ImGui::PopID();
levelId += 1;
continue;
}
currFolderEntries[currSegment].emplace_back(file);
}
int id = 1;
for (const auto &[segment, entries] : currFolderEntries) {
ImGui::TableNextRow();
ImGui::TableNextColumn();
ImGui::PushStyleVarX(ImGuiStyleVar_FramePadding, 0.0F);
if (level == 0) {
ImGui::TextUnformatted(ICON_VS_DATABASE);
} else {
ImGui::TextUnformatted(ICON_VS_FOLDER);
}
ImGui::PushID(id);
ImGui::SameLine(0, 20_scaled);
const auto open = ImGui::TreeNodeEx("##Segment", ImGuiTreeNodeFlags_DrawLinesToNodes | ImGuiTreeNodeFlags_SpanLabelWidth | ImGuiTreeNodeFlags_OpenOnArrow);
ImGui::SameLine();
ImGui::TextUnformatted(segment.c_str());
ImGui::PopStyleVar();
if (open) {
drawVirtualFileTree(entries, level + 1);
ImGui::TreePop();
}
ImGui::PopID();
id += 1;
}
}
static void setItemInfoTooltip(const char *title, const char *description) {
if (ImGui::IsItemHovered(ImGuiHoveredFlags_ForTooltip)) {
ImGui::SetNextWindowSize(scaled(300, 0), ImGuiCond_Always);
if (ImGui::BeginTooltipEx(ImGuiTooltipFlags_OverridePrevious, ImGuiWindowFlags_None)) {
if (ImGuiExt::BeginSubWindow(title)) {
ImGuiExt::TextFormattedWrapped("{}", description);
}
ImGuiExt::EndSubWindow();
ImGui::EndTooltip();
}
}
}
static void selectFirstTabItem() {
auto tabBar = ImGui::GetCurrentTabBar();
if (tabBar != nullptr && tabBar->Tabs.Size > 0) {
tabBar->SelectedTabId = tabBar->Tabs.front().ID;
}
}
void ViewPatternData::drawContent() {
// Draw the pattern tree if the provider is valid
if (ImHexApi::Provider::isValid()) {
@@ -156,65 +262,106 @@ namespace hex::plugin::builtin {
}
constexpr static auto SimplifiedEditorAttribute = "hex::editor_export";
if (TRY_LOCK(ContentRegistry::PatternLanguage::getRuntimeLock()) && patternsValid) {
const auto &patternSet = runtime.getPatternsWithAttribute(SimplifiedEditorAttribute);
std::vector<pl::ptrn::Pattern*> patterns = { patternSet.begin(), patternSet.end() };
std::ranges::sort(patterns, [](const pl::ptrn::Pattern *a, const pl::ptrn::Pattern *b) {
return a->getOffset() < b->getOffset() || a->getDisplayName() < b->getDisplayName();
});
if (TRY_LOCK(ContentRegistry::PatternLanguage::getRuntimeLock())) {
constexpr static auto SimplifiedEditorTabName = "hex.builtin.view.pattern_data.simplified_editor"_lang;
const auto simplifiedEditorPatterns = [&] {
const auto &patternSet = runtime.getPatternsWithAttribute(SimplifiedEditorAttribute);
if (!patterns.empty()) {
constexpr auto TabName = "hex.builtin.view.pattern_data.simplified_editor"_lang;
std::vector<pl::ptrn::Pattern*> result = { patternSet.begin(), patternSet.end() };
std::ranges::sort(result, [](const pl::ptrn::Pattern *a, const pl::ptrn::Pattern *b) {
return a->getOffset() < b->getOffset() || a->getDisplayName() < b->getDisplayName();
});
ImGui::TabItemSpacing("##spacing", 0, ImGui::GetContentRegionAvail().x - ImGui::TabItemCalcSize(TabName, false).x);
if (ImGui::BeginTabItem(TabName, nullptr, ImGuiTabItemFlags_Trailing)) {
if (ImGui::BeginChild("##editor")) {
for (const auto &pattern : patterns) {
ImGui::PushID(pattern);
try {
const auto attribute = pattern->getAttributeArguments(SimplifiedEditorAttribute);
return result;
}();
const auto name = attribute.size() >= 1 ? attribute[0].toString() : pattern->getDisplayName();
const auto description = attribute.size() >= 2 ? attribute[1].toString() : pattern->getComment();
constexpr static auto VirtualFilesTabName = "hex.builtin.view.pattern_data.virtual_files"_lang;
const auto widgetPos = 200_scaled;
ImGui::TextUnformatted(name.c_str());
ImGui::SameLine(0, 20_scaled);
if (ImGui::GetCursorPosX() < widgetPos)
ImGui::SetCursorPosX(widgetPos);
float spacingWidth = ImGui::GetContentRegionAvail().x;
ImGui::PushStyleVarY(ImGuiStyleVar_FramePadding, 0);
ImGui::PushItemWidth(-50_scaled);
pattern->accept(m_patternValueEditor);
ImGui::PopItemWidth();
ImGui::PopStyleVar();
spacingWidth -= ImGui::TabItemCalcSize(ICON_TA_ACCESSIBLE, false).x;
spacingWidth -= ImGui::TabItemCalcSize(ICON_TA_BINARY_TREE, false).x;
if (!description.empty()) {
ImGui::PushFont(nullptr, ImGui::GetFontSize() * 0.8F);
ImGui::BeginDisabled();
ImGui::Indent();
ImGui::TextWrapped("%s", description.c_str());
ImGui::Unindent();
ImGui::EndDisabled();
ImGui::PopFont();
}
ImGui::TabItemSpacing("##spacing", ImGuiTabItemFlags_None, spacingWidth);
ImGui::Separator();
ImGui::BeginDisabled(simplifiedEditorPatterns.empty());
if (ImGui::BeginTabItem(ICON_TA_ACCESSIBLE, nullptr, ImGuiTabItemFlags_Trailing)) {
if (simplifiedEditorPatterns.empty())
selectFirstTabItem();
} catch (const std::exception &e) {
ImGui::TextUnformatted(pattern->getDisplayName().c_str());
ImGui::TextUnformatted(e.what());
if (ImGui::BeginChild("##editor")) {
for (const auto &pattern : simplifiedEditorPatterns) {
ImGui::PushID(pattern);
try {
const auto attribute = pattern->getAttributeArguments(SimplifiedEditorAttribute);
const auto name = attribute.size() >= 1 ? attribute[0].toString() : pattern->getDisplayName();
const auto description = attribute.size() >= 2 ? attribute[1].toString() : pattern->getComment();
const auto widgetPos = 200_scaled;
ImGui::TextUnformatted(name.c_str());
ImGui::SameLine(0, 20_scaled);
if (ImGui::GetCursorPosX() < widgetPos)
ImGui::SetCursorPosX(widgetPos);
ImGui::PushStyleVarY(ImGuiStyleVar_FramePadding, 0);
ImGui::PushItemWidth(-50_scaled);
pattern->accept(m_patternValueEditor);
ImGui::PopItemWidth();
ImGui::PopStyleVar();
if (!description.empty()) {
ImGui::PushFont(nullptr, ImGui::GetFontSize() * 0.8F);
ImGui::BeginDisabled();
ImGui::Indent();
ImGui::TextWrapped("%s", description.c_str());
ImGui::Unindent();
ImGui::EndDisabled();
ImGui::PopFont();
}
ImGui::PopID();
ImGui::Separator();
} catch (const std::exception &e) {
ImGui::TextUnformatted(pattern->getDisplayName().c_str());
ImGui::TextUnformatted(e.what());
}
ImGui::EndChild();
ImGui::PopID();
}
ImGui::EndTabItem();
ImGui::EndChild();
}
ImGui::EndTabItem();
}
ImGui::EndDisabled();
if (simplifiedEditorPatterns.empty())
setItemInfoTooltip(SimplifiedEditorTabName, "hex.builtin.view.pattern_data.simplified_editor.no_patterns"_lang);
ImGui::BeginDisabled(m_virtualFiles->empty());
if (ImGui::BeginTabItem(ICON_TA_BINARY_TREE, nullptr, ImGuiTabItemFlags_Trailing)) {
if (m_virtualFiles->empty())
selectFirstTabItem();
std::vector<const VirtualFile*> virtualFilePointers;
for (const auto &file : *m_virtualFiles)
virtualFilePointers.emplace_back(&file);
if (ImGui::BeginTable("##virtual_file_tree", 1, ImGuiTableFlags_BordersOuter | ImGuiTableFlags_BordersInnerH | ImGuiTableFlags_RowBg | ImGuiTableFlags_ScrollY, ImGui::GetContentRegionAvail())) {
ImGui::TableSetupColumn("##path", ImGuiTableColumnFlags_WidthStretch);
drawVirtualFileTree(virtualFilePointers);
ImGui::EndTable();
}
ImGui::EndTabItem();
}
ImGui::EndDisabled();
if (m_virtualFiles->empty())
setItemInfoTooltip(VirtualFilesTabName, "hex.builtin.view.pattern_data.virtual_files.no_virtual_files"_lang);
}
ImGui::EndTabBar();

View File

@@ -285,74 +285,6 @@ namespace hex::plugin::builtin {
return langDef;
}
int levelId;
static void loadPatternAsMemoryProvider(const ViewPatternEditor::VirtualFile *file) {
ImHexApi::Provider::add<prv::MemoryProvider>(file->data, wolv::util::toUTF8String(file->path.filename()));
}
static void drawVirtualFileTree(const std::vector<const ViewPatternEditor::VirtualFile*> &virtualFiles, u32 level = 0) {
ImGui::PushID(level + 1);
ON_SCOPE_EXIT { ImGui::PopID(); };
std::map<std::string, std::vector<const ViewPatternEditor::VirtualFile*>> currFolderEntries;
for (const auto &file : virtualFiles) {
const auto &path = file->path;
auto currSegment = wolv::io::fs::toNormalizedPathString(*std::next(path.begin(), level));
if (std::distance(path.begin(), path.end()) == ptrdiff_t(level + 1)) {
ImGui::TableNextRow();
ImGui::TableNextColumn();
ImGui::TextUnformatted(ICON_VS_FILE);
ImGui::PushID(levelId);
ImGui::SameLine();
ImGui::TreeNodeEx(currSegment.c_str(), ImGuiTreeNodeFlags_SpanFullWidth | ImGuiTreeNodeFlags_Leaf | ImGuiTreeNodeFlags_NoTreePushOnOpen);
if (ImGui::IsMouseDown(ImGuiMouseButton_Right) && ImGui::IsItemHovered() && !ImGui::IsMouseDragging(ImGuiMouseButton_Right)) {
ImGui::OpenPopup("##virtual_files_context_menu");
}
if (ImGui::BeginPopup("##virtual_files_context_menu")) {
if (ImGui::MenuItem("hex.builtin.view.hex_editor.menu.edit.open_in_new_provider"_lang, nullptr, false)) {
loadPatternAsMemoryProvider(file);
}
ImGui::EndPopup();
}
if (ImGui::IsMouseDoubleClicked(ImGuiMouseButton_Left) && ImGui::IsItemHovered()) {
loadPatternAsMemoryProvider(file);
}
ImGui::PopID();
levelId +=1;
continue;
}
currFolderEntries[currSegment].emplace_back(file);
}
int id = 1;
for (const auto &[segment, entries] : currFolderEntries) {
ImGui::TableNextRow();
ImGui::TableNextColumn();
if (level == 0) {
ImGui::TextUnformatted(ICON_VS_DATABASE);
} else {
ImGui::TextUnformatted(ICON_VS_FOLDER);
}
ImGui::PushID(id);
ImGui::SameLine();
if (ImGui::TreeNodeEx(segment.c_str(), ImGuiTreeNodeFlags_SpanFullWidth)) {
drawVirtualFileTree(entries, level + 1);
ImGui::TreePop();
}
ImGui::PopID();
id += 1;
}
}
ViewPatternEditor::ViewPatternEditor() : View::Window("hex.builtin.view.pattern_editor.name", ICON_VS_SYMBOL_NAMESPACE) {
m_editorRuntime = std::make_unique<pl::PatternLanguage>();
ContentRegistry::PatternLanguage::configureRuntime(*m_editorRuntime, nullptr);
@@ -452,6 +384,23 @@ namespace hex::plugin::builtin {
drawTextEditorGotoLinePopup(editor);
}
void ViewPatternEditor::drawPatternSettings() {
const auto size = scaled(500, 150);
if (ImGuiExt::BeginSubWindow("hex.builtin.view.pattern_editor.settings"_lang, nullptr, size)) {
this->drawVariableSettings(*m_patternVariables);
}
ImGuiExt::EndSubWindow();
ImGui::NewLine();
if (ImGuiExt::BeginSubWindow("hex.builtin.view.pattern_editor.env_vars"_lang, nullptr, size)) {
this->drawEnvVars(*m_envVarEntries);
}
ImGuiExt::EndSubWindow();
}
void ViewPatternEditor::drawContent() {
auto provider = ImHexApi::Provider::get();
@@ -470,11 +419,27 @@ namespace hex::plugin::builtin {
defaultEditorSize.y *= 0.66F;
fonts::CodeEditor().push();
ImGui::SetNextWindowSizeConstraints(
ImVec2(
defaultEditorSize.x,
ImGui::GetTextLineHeightWithSpacing() * 2
),
ImVec2(
defaultEditorSize.x,
std::min(
ImGui::GetContentRegionAvail().y - ImGui::GetTextLineHeightWithSpacing() * 4,
ImGui::GetContentRegionAvail().y * 0.8F
)
)
);
ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(0.0f, 0.0f));
ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(0.0f, 0.0f));
if (ImGui::BeginChild("##pattern_editor_resizer", defaultEditorSize, ImGuiChildFlags_ResizeY)) {
m_textEditor.get(provider).render("##pattern_editor", ImGui::GetContentRegionAvail(), false);
m_textEditorHoverBox = ImGui::GetCurrentWindow()->Rect();
}
ImGui::EndChild();
ImGui::PopStyleVar(2);
fonts::CodeEditor().pop();
m_consoleHoverBox = ImGui::GetCurrentWindow()->Rect();
@@ -499,35 +464,28 @@ namespace hex::plugin::builtin {
}
auto settingsSize = ImGui::GetContentRegionAvail();
settingsSize.y -= ImGui::GetTextLineHeightWithSpacing() * 2.5F;
if (m_debuggerActive) {
settingsSize.y -= ImGui::GetTextLineHeightWithSpacing() * 2.5F;
if (ImGui::BeginTabBar("##settings")) {
const auto startY = ImGui::GetCursorPosY();
if (ImGui::BeginTabBar("##settings")) {
const auto startY = ImGui::GetCursorPosY();
if (ImGui::BeginTabItem("hex.builtin.view.pattern_editor.console"_lang)) {
this->drawConsole(settingsSize);
ImGui::EndTabItem();
}
if (ImGui::BeginTabItem("hex.builtin.view.pattern_editor.env_vars"_lang)) {
this->drawEnvVars(settingsSize, *m_envVarEntries);
ImGui::EndTabItem();
}
if (ImGui::BeginTabItem("hex.builtin.view.pattern_editor.settings"_lang)) {
this->drawVariableSettings(settingsSize, *m_patternVariables);
ImGui::EndTabItem();
}
if (ImGui::BeginTabItem("hex.builtin.view.pattern_editor.virtual_files"_lang)) {
this->drawVirtualFiles(settingsSize, *m_virtualFiles);
ImGui::EndTabItem();
}
if (ImGui::BeginTabItem("hex.builtin.view.pattern_editor.debugger"_lang)) {
this->drawDebugger(settingsSize);
ImGui::EndTabItem();
}
if (ImGui::BeginTabItem("hex.builtin.view.pattern_editor.console"_lang)) {
this->drawConsole(settingsSize);
ImGui::EndTabItem();
}
if (ImGui::BeginTabItem("hex.builtin.view.pattern_editor.debugger"_lang)) {
this->drawDebugger(settingsSize);
ImGui::EndTabItem();
}
ImGui::SetCursorPosY(startY + settingsSize.y + ImGui::GetStyle().ItemSpacing.y * 2);
ImGui::SetCursorPosY(startY + settingsSize.y + ImGui::GetStyle().ItemSpacing.y * 2);
ImGui::EndTabBar();
ImGui::EndTabBar();
}
} else {
settingsSize.y -= ImGui::GetTextLineHeightWithSpacing() + ImGui::GetStyle().ItemSpacing.y;
this->drawConsole(settingsSize);
}
ImGui::PushStyleVar(ImGuiStyleVar_FrameBorderSize, 1);
@@ -611,7 +569,7 @@ namespace hex::plugin::builtin {
}
ImGui::SetItemTooltip("%s", "hex.builtin.view.pattern_editor.auto"_lang.get());
ImGui::SameLine();
ImGui::SameLine(0, 5_scaled);
bool synced = m_sourceCode.isSynced();
if (ImGuiExt::DimmedIconToggle(ICON_VS_REPO_PINNED, &synced)) {
@@ -619,6 +577,20 @@ namespace hex::plugin::builtin {
}
ImGui::SetItemTooltip("%s", "hex.builtin.setting.general.sync_pattern_source"_lang.get());
ImGui::SameLine(0, 10_scaled);
if (ImGuiExt::DimmedIconButton(ICON_VS_SETTINGS_GEAR, ImGui::GetStyleColorVec4(ImGuiCol_Text))) {
ImGui::OpenPopup("hex.builtin.view.pattern_editor.pattern_settings"_lang);
}
ImGui::SameLine(0, 0);
ImGui::SetNextWindowPos(ImGui::GetCursorScreenPos() + ImVec2(0, ImGui::GetTextLineHeightWithSpacing()), ImGuiCond_Always, ImVec2(0.0F, 1.0F));
if (ImGui::BeginPopup("hex.builtin.view.pattern_editor.pattern_settings"_lang)) {
this->drawPatternSettings();
ImGui::EndPopup();
}
ImGui::SameLine();
ImGui::SeparatorEx(ImGuiSeparatorFlags_Vertical);
ImGui::SameLine();
@@ -1076,10 +1048,10 @@ namespace hex::plugin::builtin {
ImGui::SetCursorPosY(ImGui::GetCursorPosY() + ImGui::GetStyle().FramePadding.y + 1_scaled);
}
void ViewPatternEditor::drawEnvVars(ImVec2 size, std::list<EnvVar> &envVars) {
void ViewPatternEditor::drawEnvVars(std::list<EnvVar> &envVars) {
static u32 envVarCounter = 1;
if (ImGui::BeginChild("##env_vars", size, true, ImGuiWindowFlags_AlwaysVerticalScrollbar)) {
if (ImGui::BeginChild("##env_vars", ImGui::GetContentRegionAvail(), true, ImGuiWindowFlags_AlwaysVerticalScrollbar)) {
if (envVars.size() <= 1) {
ImGuiExt::TextOverlay("hex.builtin.view.pattern_editor.no_env_vars"_lang, ImGui::GetWindowPos() + ImGui::GetWindowSize() / 2, ImGui::GetWindowWidth() * 0.7);
}
@@ -1184,9 +1156,9 @@ namespace hex::plugin::builtin {
ImGui::EndChild();
}
void ViewPatternEditor::drawVariableSettings(ImVec2 size, std::map<std::string, PatternVariable> &patternVariables) {
void ViewPatternEditor::drawVariableSettings(std::map<std::string, PatternVariable> &patternVariables) {
auto provider = ImHexApi::Provider::get();
if (ImGui::BeginChild("##settings", size, true, ImGuiWindowFlags_AlwaysVerticalScrollbar)) {
if (ImGui::BeginChild("##settings", ImGui::GetContentRegionAvail(), true, ImGuiWindowFlags_AlwaysVerticalScrollbar)) {
if (patternVariables.empty()) {
ImGuiExt::TextOverlay("hex.builtin.view.pattern_editor.no_in_out_vars"_lang, ImGui::GetWindowPos() + ImGui::GetWindowSize() / 2, ImGui::GetWindowWidth() * 0.7);
}
@@ -1250,26 +1222,6 @@ namespace hex::plugin::builtin {
ImGui::EndChild();
}
void ViewPatternEditor::drawVirtualFiles(ImVec2 size, const std::vector<VirtualFile> &virtualFiles) const {
std::vector<const VirtualFile*> virtualFilePointers;
for (const auto &file : virtualFiles)
virtualFilePointers.emplace_back(&file);
if (ImGui::BeginTable("##virtual_file_tree", 1, ImGuiTableFlags_BordersOuter | ImGuiTableFlags_BordersInnerH | ImGuiTableFlags_RowBg | ImGuiTableFlags_ScrollY, size)) {
if (virtualFiles.empty()) {
ImGuiExt::TextOverlay("hex.builtin.view.pattern_editor.no_virtual_files"_lang, ImGui::GetWindowPos() + ImGui::GetWindowSize() / 2, ImGui::GetWindowWidth() * 0.7);
}
ImGui::TableSetupColumn("##path", ImGuiTableColumnFlags_WidthStretch);
levelId = 1;
drawVirtualFileTree(virtualFilePointers);
ImGui::EndTable();
}
}
void ViewPatternEditor::drawDebugger(ImVec2 size) {
auto provider = ImHexApi::Provider::get();
const auto &runtime = ContentRegistry::PatternLanguage::getRuntime();
@@ -1278,22 +1230,9 @@ namespace hex::plugin::builtin {
auto &evaluator = runtime.getInternals().evaluator;
m_breakpoints = m_textEditor.get(provider).getBreakpoints();
evaluator->setBreakpoints(m_breakpoints);
const auto line = m_textEditor.get(provider).getCursorPosition().m_line + 1;
if (!m_breakpoints->contains(line)) {
if (ImGuiExt::IconButton(ICON_VS_CIRCLE, ImGuiExt::GetCustomColorVec4(ImGuiCustomCol_ToolbarRed))) {
evaluator->addBreakpoint(line);
}
ImGuiExt::InfoTooltip("hex.builtin.view.pattern_editor.debugger.add_tooltip"_lang);
} else {
if (ImGuiExt::IconButton(ICON_VS_CIRCLE_FILLED, ImGuiExt::GetCustomColorVec4(ImGuiCustomCol_ToolbarRed))) {
evaluator->removeBreakpoint(line);
}
ImGuiExt::InfoTooltip("hex.builtin.view.pattern_editor.debugger.remove_tooltip"_lang);
}
m_breakpoints = evaluator->getBreakpoints();
m_textEditor.get(provider).setBreakpoints(m_breakpoints);
ImGui::SameLine();
if (*m_breakpointHit) {
auto displayValue = [&](const auto &parent, size_t index) {
@@ -1703,7 +1642,6 @@ namespace hex::plugin::builtin {
m_consoleNeedsUpdate = true;
m_consoleEditor.get(provider).setText("");
m_virtualFiles->clear();
m_accessHistory = {};
m_accessHistoryIndex = 0;
@@ -1718,18 +1656,20 @@ namespace hex::plugin::builtin {
ContentRegistry::PatternLanguage::configureRuntime(runtime, provider);
runtime.getInternals().evaluator->setBreakpointHitCallback([this, &runtime, provider] {
m_debuggerScopeIndex = 0;
*m_breakpointHit = true;
m_breakpointHit.get(provider) = true;
m_debuggerActive.get(provider) = true;
m_resetDebuggerVariables = true;
auto optPauseLine = runtime.getInternals().evaluator->getPauseLine();
if (optPauseLine.has_value())
m_textEditor.get(provider).jumpToLine(optPauseLine.value() - 1);
while (*m_breakpointHit) {
while (m_breakpointHit.get(provider)) {
std::this_thread::sleep_for(std::chrono::milliseconds(100LL));
}
});
task.setInterruptCallback([this, &runtime] {
m_breakpointHit = false;
task.setInterruptCallback([this, &runtime, provider] {
m_breakpointHit.get(provider) = false;
m_debuggerActive.get(provider) = false;
runtime.abort();
});
@@ -1791,6 +1731,7 @@ namespace hex::plugin::builtin {
fmt::format("I: Evaluation took {}", std::chrono::duration<double>(runtime.getLastRunningTime()))
);
m_consoleNeedsUpdate = true;
m_debuggerActive.get(provider) = false;
};
@@ -1896,10 +1837,6 @@ namespace hex::plugin::builtin {
});
RequestAddVirtualFile::subscribe(this, [this](const std::fs::path &path, const std::vector<u8> &data, Region region) {
m_virtualFiles->emplace_back(path, data, region);
});
}
static void createNestedMenu(const std::vector<std::string> &menus, const std::function<void()> &function) {