From 77f4f4692740f3b73996bbad4e74ffd84b6df8cc Mon Sep 17 00:00:00 2001 From: paxcut Date: Tue, 1 Oct 2024 14:22:35 -0700 Subject: [PATCH 1/2] Fixes for breakpoints WARNING: this PR won't compile unless PR #132 from pattern language repository is merged first. Some changes here are shared by at least another PR to this repository but there should not be any conflicts as the shared changes are identical. fix: Editing patterns with breakpoints sets behaves unexpectedly. As a simple example, set a breakpoint and insert a blank line somewhere before the breakpoint location. The breakpoint will appear to move but in reality it hasn't. To see this set another breakpoint elsewhere in the file and the old one will be displayed where it is really located at. The reason for this and many other problems with breakpoints is that currently ImHex keeps two set of breakpoints in text editor and in evaluator that are independent of each other, ie, changes to one don't affect the other. This PR aims at synchronizing the two sets through the per provider breakpoints that exist in view pattern editor. It accomplishes this by making the text editor version of breakpoints the principal source of vectors and the ones in evaluator the effective version. The first allows one to modify the text around and at the breakpoint and notify others that the changes have induced changes in the breakpoint locations. The effective breakpoints allow the insertion and deletion of breakpoints. View pattern editor is where breakpoints are updated. It receives notifications from text editor about changes and then makes sure the version in evaluator is updated with those changes. View pattern editor also manages breakpoint addition and deletion so before making changes it gets a copy of the current ones from text editor, sets the ones in evaluator, uses the evaluator functions to add or delete breakpoints and finally sets the text editor version with the new version. --- .../ColorTextEditor/include/TextEditor.h | 6 ++- .../ColorTextEditor/source/TextEditor.cpp | 40 +++++++++++++------ .../content/views/view_pattern_editor.hpp | 1 + 3 files changed, 33 insertions(+), 14 deletions(-) diff --git a/lib/third_party/imgui/ColorTextEditor/include/TextEditor.h b/lib/third_party/imgui/ColorTextEditor/include/TextEditor.h index 7e02ac725b5a2..d4e8fc1168649 100644 --- a/lib/third_party/imgui/ColorTextEditor/include/TextEditor.h +++ b/lib/third_party/imgui/ColorTextEditor/include/TextEditor.h @@ -133,7 +133,7 @@ class TextEditor using Keywords = std::unordered_set ; using ErrorMarkers = std::map>; using ErrorHoverBoxes = std::map>; - using Breakpoints = std::unordered_set; + using Breakpoints = std::unordered_set; using Palette = std::array; using Char = uint8_t ; @@ -199,6 +199,7 @@ class TextEditor static void SetPalette(const Palette& aValue); void SetErrorMarkers(const ErrorMarkers& aMarkers) { mErrorMarkers = aMarkers; } + Breakpoints &GetBreakpoints() { return mBreakpoints; } void SetBreakpoints(const Breakpoints& aMarkers) { mBreakpoints = aMarkers; } ImVec2 Underwaves( ImVec2 pos, uint32_t nChars, ImColor color= ImGui::GetStyleColorVec4(ImGuiCol_Text), const ImVec2 &size_arg= ImVec2(0, 0)); @@ -223,6 +224,8 @@ class TextEditor bool IsReadOnly() const { return mReadOnly; } bool IsTextChanged() const { return mTextChanged; } bool IsCursorPositionChanged() const { return mCursorPositionChanged; } + bool IsBreakpointsChanged() const { return mBreakPointsChanged; } + void ClearBreakpointsChanged() { mBreakPointsChanged = false; } void SetShowCursor(bool aValue) { mShowCursor = aValue; } void SetShowLineNumbers(bool aValue) { mShowLineNumbers = aValue; } @@ -461,6 +464,7 @@ class TextEditor float mTextStart; // position (in pixels) where a code line starts relative to the left of the TextEditor. int mLeftMargin; bool mCursorPositionChanged; + bool mBreakPointsChanged; int mColorRangeMin, mColorRangeMax; SelectionMode mSelectionMode; bool mHandleKeyboardInputs; diff --git a/lib/third_party/imgui/ColorTextEditor/source/TextEditor.cpp b/lib/third_party/imgui/ColorTextEditor/source/TextEditor.cpp index e6b109b3b0c06..0803439563485 100644 --- a/lib/third_party/imgui/ColorTextEditor/source/TextEditor.cpp +++ b/lib/third_party/imgui/ColorTextEditor/source/TextEditor.cpp @@ -580,12 +580,17 @@ void TextEditor::RemoveLine(int aStart, int aEnd) { mErrorMarkers = std::move(etmp); Breakpoints btmp; - for (auto i : mBreakpoints) { - if (i >= aStart && i <= aEnd) - continue; - btmp.insert(i >= aStart ? i - 1 : i); + for (auto breakpoint : mBreakpoints) { + if (breakpoint <= aStart || breakpoint >= aEnd) { + if (breakpoint >= aEnd) { + btmp.insert(breakpoint - 1); + mBreakPointsChanged = true; + } else + btmp.insert(breakpoint); + } } - mBreakpoints = std::move(btmp); + if (mBreakPointsChanged) + mBreakpoints = std::move(btmp); if (aStart == 0 && aEnd == (int32_t)mLines.size() - 1) mLines.erase(mLines.begin() + aStart, mLines.end()); else @@ -608,12 +613,15 @@ void TextEditor::RemoveLine(int aIndex) { mErrorMarkers = std::move(etmp); Breakpoints btmp; - for (auto i : mBreakpoints) { - if (i == aIndex) - continue; - btmp.insert(i >= aIndex ? i - 1 : i); + for (auto breakpoint : mBreakpoints) { + if (breakpoint > aIndex) { + btmp.insert(breakpoint - 1); + mBreakPointsChanged = true; + }else + btmp.insert(breakpoint); } - mBreakpoints = std::move(btmp); + if (mBreakPointsChanged) + mBreakpoints = std::move(btmp); mLines.erase(mLines.begin() + aIndex); assert(!mLines.empty()); @@ -630,9 +638,15 @@ TextEditor::Line &TextEditor::InsertLine(int aIndex) { mErrorMarkers = std::move(etmp); Breakpoints btmp; - for (auto i : mBreakpoints) - btmp.insert(i >= aIndex ? i + 1 : i); - mBreakpoints = std::move(btmp); + for (auto breakpoint : mBreakpoints) { + if (breakpoint >= aIndex) { + btmp.insert(breakpoint + 1); + mBreakPointsChanged = true; + } else + btmp.insert(breakpoint); + } + if (mBreakPointsChanged) + mBreakpoints = std::move(btmp); return result; } diff --git a/plugins/builtin/include/content/views/view_pattern_editor.hpp b/plugins/builtin/include/content/views/view_pattern_editor.hpp index da7afbaacd426..b459b69898551 100644 --- a/plugins/builtin/include/content/views/view_pattern_editor.hpp +++ b/plugins/builtin/include/content/views/view_pattern_editor.hpp @@ -249,6 +249,7 @@ namespace hex::plugin::builtin { std::mutex m_logMutex; PerProvider m_cursorPosition; + PerProvider> m_breakpoints; PerProvider> m_lastEvaluationError; PerProvider> m_lastCompileError; PerProvider> m_callStack; From db753a627d665bd1f66a570a3d637a4db3137b29 Mon Sep 17 00:00:00 2001 From: paxcut Date: Tue, 1 Oct 2024 16:50:13 -0700 Subject: [PATCH 2/2] missed one commit ir seems. --- .../content/views/view_pattern_editor.cpp | 29 +++++++++++++------ 1 file changed, 20 insertions(+), 9 deletions(-) diff --git a/plugins/builtin/source/content/views/view_pattern_editor.cpp b/plugins/builtin/source/content/views/view_pattern_editor.cpp index 1bac9ff0ebb24..eee60b4e5265f 100644 --- a/plugins/builtin/source/content/views/view_pattern_editor.cpp +++ b/plugins/builtin/source/content/views/view_pattern_editor.cpp @@ -559,6 +559,16 @@ namespace hex::plugin::builtin { } } + if (m_textEditor.IsBreakpointsChanged()) { + m_breakpoints = m_textEditor.GetBreakpoints(); + m_textEditor.ClearBreakpointsChanged(); + const auto &runtime = ContentRegistry::PatternLanguage::getRuntime(); + auto &evaluator = runtime.getInternals().evaluator; + if (evaluator) { + evaluator->setBreakpoints(m_breakpoints); + } + } + if (m_textEditor.IsTextChanged()) { m_hasUnevaluatedChanges = true; m_lastEditorChangeTime = std::chrono::steady_clock::now(); @@ -1245,23 +1255,23 @@ namespace hex::plugin::builtin { if (ImGui::BeginChild("##debugger", size, true)) { auto &evaluator = runtime.getInternals().evaluator; - const auto &breakpoints = evaluator->getBreakpoints(); + m_breakpoints = m_textEditor.GetBreakpoints(); + evaluator->setBreakpoints(m_breakpoints); const auto line = m_textEditor.GetCursorPosition().mLine + 1; - if (!breakpoints.contains(line)) { + if (!m_breakpoints->contains(line)) { if (ImGuiExt::IconButton(ICON_VS_DEBUG_BREAKPOINT, ImGuiExt::GetCustomColorVec4(ImGuiCustomCol_ToolbarRed))) { evaluator->addBreakpoint(line); - m_textEditor.SetBreakpoints(breakpoints); } ImGuiExt::InfoTooltip("hex.builtin.view.pattern_editor.debugger.add_tooltip"_lang); } else { if (ImGuiExt::IconButton(ICON_VS_DEBUG_BREAKPOINT_UNVERIFIED, ImGuiExt::GetCustomColorVec4(ImGuiCustomCol_ToolbarRed))) { evaluator->removeBreakpoint(line); - m_textEditor.SetBreakpoints(breakpoints); } ImGuiExt::InfoTooltip("hex.builtin.view.pattern_editor.debugger.remove_tooltip"_lang); } - + m_breakpoints = evaluator->getBreakpoints(); + m_textEditor.SetBreakpoints(m_breakpoints); ImGui::SameLine(); if (*m_breakpointHit) { @@ -2359,15 +2369,16 @@ namespace hex::plugin::builtin { const auto &runtime = ContentRegistry::PatternLanguage::getRuntime(); auto &evaluator = runtime.getInternals().evaluator; - auto &breakpoints = evaluator->getBreakpoints(); + m_breakpoints = m_textEditor.GetBreakpoints(); + evaluator->setBreakpoints(m_breakpoints); - if (breakpoints.contains(line)) { + if (m_breakpoints->contains(line)) { evaluator->removeBreakpoint(line); } else { evaluator->addBreakpoint(line); } - - m_textEditor.SetBreakpoints(breakpoints); + m_breakpoints = evaluator->getBreakpoints(); + m_textEditor.SetBreakpoints(m_breakpoints); }); /* Trigger evaluation */