From e9a1b6cde9c90baa239324bf8c7b4d2804837e54 Mon Sep 17 00:00:00 2001 From: paxcut Date: Sat, 30 May 2026 16:28:43 -0700 Subject: [PATCH 1/3] fix: bad selections on delete. This attempts to fix the problems described in issue 2748. When a selection is deleted, the selection ends are changed correctly, but the interactive selection is not so attempting to use it after the deletion produces unexpected results. The fix is to update the interactive selection as well. I also made some code more efficient by removing the creation of temporary objects that were not necessary. Some code was repeated several times, so I move the code into their own function. Cleaned the code handling mouse clicks and added some `using` typedefs to shorten code. --- plugins/ui/include/ui/text_editor.hpp | 5 + .../ui/source/ui/text_editor/codeFolder.cpp | 66 +++--- plugins/ui/source/ui/text_editor/editor.cpp | 68 +++--- .../ui/source/ui/text_editor/highlighter.cpp | 38 ++-- plugins/ui/source/ui/text_editor/navigate.cpp | 210 ++++++++---------- plugins/ui/source/ui/text_editor/render.cpp | 49 ++-- plugins/ui/source/ui/text_editor/support.cpp | 114 +++++----- plugins/ui/source/ui/text_editor/utf8.cpp | 75 +++---- 8 files changed, 309 insertions(+), 316 deletions(-) diff --git a/plugins/ui/include/ui/text_editor.hpp b/plugins/ui/include/ui/text_editor.hpp index 5a11f90e0531b..64e35c16c78b1 100644 --- a/plugins/ui/include/ui/text_editor.hpp +++ b/plugins/ui/include/ui/text_editor.hpp @@ -676,6 +676,9 @@ namespace hex::ui { Keys getDeactivatedBlocks(); std::string getSelectedText(); void deleteSelection(); + void selectUsingEnd(bool select, const Coordinates &oldPos); + void selectUsingStart(bool select, const Coordinates &oldPos); + void resetInteractiveSelection(); void setTextChanged(bool value) { m_textChanged = value; } bool isTextChanged() { return m_textChanged; } void setLanguageDefinition(const LanguageDefinition &aLanguageDef); @@ -723,6 +726,7 @@ namespace hex::ui { float textDistanceToLineStart(const Coordinates &from); std::string getText(bool addHiddenLines = false); void setCursorPosition(); + void setEditorState(const Coordinates &coordinates, bool setInteractiveStart = true); void ensureSelectionNotFolded(); bool hasSelection(); i32 insertTextAtCursor(const std::string &value); @@ -1003,6 +1007,7 @@ namespace hex::ui { void setSelection(const Range &selection); Range getSelection() const; void selectWordUnderCursor(); + void selectLineUnderCursor(); void selectAll(); bool hasSelection() { return m_lines.hasSelection(); } std::string getSelectedText() { return m_lines.getSelectedText(); } diff --git a/plugins/ui/source/ui/text_editor/codeFolder.cpp b/plugins/ui/source/ui/text_editor/codeFolder.cpp index a61b245fd2884..60eac51e27018 100644 --- a/plugins/ui/source/ui/text_editor/codeFolder.cpp +++ b/plugins/ui/source/ui/text_editor/codeFolder.cpp @@ -14,8 +14,10 @@ namespace hex::ui { using Coordinates = TextEditor::Coordinates; using RangeFromCoordinates = TextEditor::RangeFromCoordinates; using CodeFoldState = TextEditor::CodeFoldState; + using Lines = TextEditor::Lines; + using CodeFoldBlocks = TextEditor::CodeFoldBlocks; - void TextEditor::Lines::skipAttribute() { + void Lines::skipAttribute() { if (sequence(tkn::Separator::LeftBracket, tkn::Separator::LeftBracket)) { while (!sequence(tkn::Separator::RightBracket, tkn::Separator::RightBracket)) @@ -23,7 +25,7 @@ namespace hex::ui { } } - Interval TextEditor::Lines::findBlockInRange(Interval interval) { + Interval Lines::findBlockInRange(Interval interval) { Interval result = NotValid; auto tokenStart = SafeTokenIterator(m_tokens.begin(), m_tokens.end()); @@ -98,7 +100,7 @@ namespace hex::ui { return NotValid; } - Coordinates TextEditor::Lines::findCommentEndCoord(i32 tokenId) { + Coordinates Lines::findCommentEndCoord(i32 tokenId) { Coordinates result = Invalid; auto save = m_curr; m_curr = SafeTokenIterator(m_tokens.begin(), m_tokens.end()) + tokenId; @@ -135,7 +137,7 @@ namespace hex::ui { } //comments imports and includes - void TextEditor::Lines::nonDelimitedFolds() { + void Lines::nonDelimitedFolds() { auto size = m_tokens.size(); if (size > 0) { Interval block = {0,static_cast(size-1)}; @@ -162,7 +164,7 @@ namespace hex::ui { } } - RangeFromCoordinates TextEditor::Lines::getDelimiterLineNumbers(i32 start, i32 end, const std::string &delimiters) { + RangeFromCoordinates Lines::getDelimiterLineNumbers(i32 start, i32 end, const std::string &delimiters) { RangeFromCoordinates result = {Invalid, Invalid}; Coordinates first = Invalid; auto tokenStart = SafeTokenIterator(m_tokens.begin(), m_tokens.end()); @@ -240,7 +242,7 @@ namespace hex::ui { return result; } - void TextEditor::Lines::advanceToNextLine(i32 &lineIndex, i32 ¤tTokenId, Location &location) { + void Lines::advanceToNextLine(i32 &lineIndex, i32 ¤tTokenId, Location &location) { i32 tempLineIndex; if (tempLineIndex = nextLineIndex(lineIndex); lineIndex == tempLineIndex) { lineIndex++; @@ -254,14 +256,14 @@ namespace hex::ui { location = m_curr->location; } - void TextEditor::Lines::incrementTokenId(i32 &lineIndex, i32 ¤tTokenId, Location &location) { + void Lines::incrementTokenId(i32 &lineIndex, i32 ¤tTokenId, Location &location) { currentTokenId++; m_curr = m_startToken + currentTokenId; location = m_curr->location; lineIndex = location.line - 1; } - void TextEditor::Lines::moveToStringIndex(i32 stringIndex, i32 ¤tTokenId, Location &location) { + void Lines::moveToStringIndex(i32 stringIndex, i32 ¤tTokenId, Location &location) { auto curr = m_curr; i32 tempTokenId; auto &line = operator[](location.line - 1); @@ -280,13 +282,13 @@ namespace hex::ui { } - void TextEditor::Lines::resetToTokenId(i32 &lineIndex, i32 ¤tTokenId, Location &location) { + void Lines::resetToTokenId(i32 &lineIndex, i32 ¤tTokenId, Location &location) { m_curr = m_startToken + currentTokenId; location = m_curr->location; lineIndex = location.line - 1; } - i32 TextEditor::Lines::findNextDelimiter(bool openOnly) { + i32 Lines::findNextDelimiter(bool openOnly) { while (!peek(tkn::Separator::EndOfProgram)) { if (peek(tkn::Separator::LeftBrace) || peek(tkn::Separator::LeftBracket) || peek(tkn::Separator::LeftParenthesis) || peek(tkn::Operator::BoolLessThan)) @@ -300,7 +302,7 @@ namespace hex::ui { return getTokenId(); } - TextEditor::CodeFoldBlocks TextEditor::Lines::foldPointsFromSource() { + CodeFoldBlocks Lines::foldPointsFromSource() { auto code = getText(); if (code.empty()) return m_foldPoints; @@ -380,7 +382,7 @@ namespace hex::ui { } - std::pair TextEditor::Lines::findMatchingDelimiter(i32 from) { + std::pair Lines::findMatchingDelimiter(i32 from) { std::string blockDelimiters = "{}[]()<>"; std::pair result = std::make_pair(-1, '\0'); auto tokenStart = SafeTokenIterator(m_tokens.begin(), m_tokens.end()); @@ -466,7 +468,7 @@ namespace hex::ui { m_lines.saveCodeFoldStates(); } - void TextEditor::Lines::saveCodeFoldStates() { + void Lines::saveCodeFoldStates() { i32 codeFoldIndex = 0; Indices closedFoldIncrements; for (auto key: m_codeFoldKeys) { @@ -494,22 +496,22 @@ namespace hex::ui { m_lines.applyCodeFoldStates(); } - void TextEditor::Lines::setCodeFoldState(CodeFoldState state) { + void Lines::setCodeFoldState(CodeFoldState state) { m_codeFoldState = state; saveCodeFoldStates(); } - CodeFoldState TextEditor::Lines::getCodeFoldState() const { + CodeFoldState Lines::getCodeFoldState() const { return m_codeFoldState; } - void TextEditor::Lines::resetCodeFoldStates() { + void Lines::resetCodeFoldStates() { m_codeFoldState.clear(); for (auto key: m_codeFoldKeys) m_codeFoldState[key] = true; } - void TextEditor::Lines::applyCodeFoldStates() { + void Lines::applyCodeFoldStates() { std::string commentLine; for (const auto& line: m_hiddenLines) { @@ -552,7 +554,7 @@ namespace hex::ui { } } - void TextEditor::Lines::closeCodeFold(const Range &key, bool userTriggered) { + void Lines::closeCodeFold(const Range &key, bool userTriggered) { float topRow = 0.0f; if (userTriggered) { @@ -684,7 +686,7 @@ namespace hex::ui { m_foldedLines[currentFoldedLine.m_row].loadSegments(); } - void TextEditor::Lines::openCodeFold(const Range &key) { + void Lines::openCodeFold(const Range &key) { for (const auto& foldedLine : m_foldedLines) { for (auto foldKey : foldedLine.second.m_keys) { if (foldKey.contains(key) && foldKey != key) { @@ -754,11 +756,11 @@ namespace hex::ui { } template - T *TextEditor::Lines::getValue(const i32 index) { + T *Lines::getValue(const i32 index) { return const_cast(std::get_if(&m_curr[index].value)); } - void TextEditor::Lines::next(i32 count) { + void Lines::next(i32 count) { if (count == 0) return; i32 id = getTokenId(); @@ -771,32 +773,32 @@ namespace hex::ui { } enum : u32 { Normal = 0, Not = 1 }; - bool TextEditor::Lines::begin() { + bool Lines::begin() { m_originalPosition = m_curr; return true; } - void TextEditor::Lines::partBegin() { + void Lines::partBegin() { m_partOriginalPosition = m_curr; } - void TextEditor::Lines::reset() { + void Lines::reset() { m_curr = m_originalPosition; } - void TextEditor::Lines::partReset() { + void Lines::partReset() { m_curr = m_partOriginalPosition; } - bool TextEditor::Lines::resetIfFailed(const bool value) { + bool Lines::resetIfFailed(const bool value) { if (!value) reset(); return value; } template - bool TextEditor::Lines::sequenceImpl() { + bool Lines::sequenceImpl() { if constexpr (S == Normal) return true; else if constexpr (S == Not) @@ -806,7 +808,7 @@ namespace hex::ui { } template - bool TextEditor::Lines::matchOne(const Token &token) { + bool Lines::matchOne(const Token &token) { if constexpr (S == Normal) { if (!peek(token)) { partReset(); @@ -827,19 +829,19 @@ namespace hex::ui { } template - bool TextEditor::Lines::sequenceImpl(const auto &... args) { + bool Lines::sequenceImpl(const auto &... args) { return (matchOne(args) && ...); } template - bool TextEditor::Lines::sequence(const Token &token, const auto &... args) { + bool Lines::sequence(const Token &token, const auto &... args) { partBegin(); return sequenceImpl(token, args...); } - bool TextEditor::Lines::isValid() { + bool Lines::isValid() { Token token; try { token = m_curr[0]; @@ -853,7 +855,7 @@ namespace hex::ui { return isLocationValid(token.location); } - bool TextEditor::Lines::peek(const Token &token, const i32 index) { + bool Lines::peek(const Token &token, const i32 index) { if (!isValid()) return false; i32 id = getTokenId(); diff --git a/plugins/ui/source/ui/text_editor/editor.cpp b/plugins/ui/source/ui/text_editor/editor.cpp index 13a16291892be..c1e7aa29492b4 100644 --- a/plugins/ui/source/ui/text_editor/editor.cpp +++ b/plugins/ui/source/ui/text_editor/editor.cpp @@ -11,11 +11,16 @@ #include "imgui.h" namespace hex::ui { - using StringVector = TextEditor::StringVector; - using Range = TextEditor::Range; - using EditorState = TextEditor::EditorState; + using StringVector = TextEditor::StringVector; + using Range = TextEditor::Range; + using EditorState = TextEditor::EditorState; + using FindReplaceHandler = TextEditor::FindReplaceHandler; + using Lines = TextEditor::Lines; + using Line = TextEditor::Line; + using UndoRecord = TextEditor::UndoRecord; + using UndoAction = TextEditor::UndoAction; - TextEditor::FindReplaceHandler::FindReplaceHandler() : m_matchCase(false), m_wholeWord(false), m_findRegEx(false), m_optionsChanged(false) {} + FindReplaceHandler::FindReplaceHandler() : m_matchCase(false), m_wholeWord(false), m_findRegEx(false), m_optionsChanged(false) {} TextEditor::TextEditor() { m_lines.m_startTime = ImGui::GetTime() * 1000; @@ -30,7 +35,7 @@ namespace hex::ui { TextEditor::~TextEditor() = default; - std::string TextEditor::Lines::getRange(const Range &rangeToGet) { + std::string Lines::getRange(const Range &rangeToGet) { std::string result; auto selection = lineCoordinates(const_cast(rangeToGet)); selection.m_end = rangeToGet.m_end; @@ -52,7 +57,7 @@ namespace hex::ui { return result; } - void TextEditor::Lines::deleteRange(const Range &rangeToDelete) { + void Lines::deleteRange(const Range &rangeToDelete) { if (m_readOnly) return; Range selection = lineCoordinates(const_cast(rangeToDelete)); @@ -81,18 +86,19 @@ namespace hex::ui { m_textChanged = true; } - void TextEditor::Lines::appendLine(const std::string &value) { + void Lines::appendLine(const std::string &value) { auto text = wolv::util::replaceStrings(wolv::util::preprocessText(value), "\000", "."); if (text.empty()) return; + auto maxColumn = stringCharacterCount(text); if (isEmpty()) { m_unfoldedLines[0].m_chars = text; m_unfoldedLines[0].m_colors = std::string(text.size(), 0); m_unfoldedLines[0].m_flags = std::string(text.size(), 0); + m_unfoldedLines[0].m_lineMaxColumn = maxColumn; } else { m_unfoldedLines.emplace_back(text); - auto line = m_unfoldedLines.back(); - line.m_lineMaxColumn = line.maxColumn(); + m_unfoldedLines.back().m_lineMaxColumn = maxColumn; } m_unfoldedLines.back().m_colorized = false; } @@ -105,7 +111,7 @@ namespace hex::ui { m_lines.m_textChanged = true; } - i32 TextEditor::Lines::insertTextAtCursor(const std::string &value) { + i32 Lines::insertTextAtCursor(const std::string &value) { if (value.empty()) return 0; auto start = lineCoordinates(m_state.m_cursorPosition); @@ -131,7 +137,7 @@ namespace hex::ui { return lineCount; } - i32 TextEditor::Lines::insertTextAt(Coordinates /* inout */ &where, const std::string &value) { + i32 Lines::insertTextAt(Coordinates /* inout */ &where, const std::string &value) { if (value.empty()) return 0; auto start = lineCoordinates(where); @@ -167,7 +173,7 @@ namespace hex::ui { backspace(); } - void TextEditor::Lines::removeLines(i32 lineStart, i32 lineEnd) { + void Lines::removeLines(i32 lineStart, i32 lineEnd) { ErrorMarkers errorMarkers; for (auto &errorMarker : m_errorMarkers) { if (errorMarker.first.m_line <= lineStart || errorMarker.first.m_line > lineEnd + 1) { @@ -237,11 +243,11 @@ namespace hex::ui { m_globalRowMaxChanged = true; } - void TextEditor::Lines::removeLine(i32 index) { + void Lines::removeLine(i32 index) { removeLines(index, index); } - void TextEditor::Lines::insertLine(i32 index, const std::string &text) { + void Lines::insertLine(i32 index, const std::string &text) { if (index < 0 || index > size()) return; auto &line = insertLine(index); @@ -250,7 +256,7 @@ namespace hex::ui { m_textChanged = true; } - TextEditor::Line &TextEditor::Lines::insertLine(i32 index) { + Line &Lines::insertLine(i32 index) { m_globalRowMaxChanged = true; if (isEmpty()) return *m_unfoldedLines.insert(m_unfoldedLines.begin(), Line()); @@ -258,7 +264,7 @@ namespace hex::ui { if (index == size()) return *m_unfoldedLines.insert(m_unfoldedLines.end(), Line()); - TextEditor::Line &result = *m_unfoldedLines.insert(m_unfoldedLines.begin() + index, Line()); + Line &result = *m_unfoldedLines.insert(m_unfoldedLines.begin() + index, Line()); result.m_colorized = false; @@ -334,11 +340,12 @@ namespace hex::ui { m_lines.m_unfoldedLines.resize(lineCount); for (const auto &line: vectorString) { + auto maxColumn = stringCharacterCount(line); auto &unfoldedLine = m_lines.m_unfoldedLines[i]; unfoldedLine.setLine(line); unfoldedLine.m_colorized = false; - unfoldedLine.m_lineMaxColumn = unfoldedLine.maxColumn(); + unfoldedLine.m_lineMaxColumn = maxColumn; i++; } } @@ -597,7 +604,7 @@ namespace hex::ui { m_lines.ensureCursorVisible(); } - void TextEditor::Lines::refreshSearchResults() { + void Lines::refreshSearchResults() { std::string findWord = m_findReplaceHandler.getFindWord(); if (!findWord.empty()) { m_findReplaceHandler.resetMatches(); @@ -605,11 +612,11 @@ namespace hex::ui { } } - void TextEditor::Lines::insertText(const std::string &value) { + void Lines::insertText(const std::string &value) { insertText(value.c_str()); } - void TextEditor::Lines::insertText(const char *value) { + void Lines::insertText(const char *value) { if (value == nullptr) return; @@ -619,14 +626,15 @@ namespace hex::ui { colorize(); } - void TextEditor::Lines::deleteSelection() { + void Lines::deleteSelection() { if (m_state.m_selection.m_end == m_state.m_selection.m_start) return; - deleteRange(m_state.m_selection); + deleteRange(m_interactiveSelection); + m_interactiveSelection.m_end = m_interactiveSelection.m_start; - setSelection(Range(m_state.m_selection.m_start, m_state.m_selection.m_start)); + setSelection(m_interactiveSelection); setCursorPosition(m_state.m_selection.m_start, false); refreshSearchResults(); colorize(); @@ -881,7 +889,7 @@ namespace hex::ui { m_lines.refreshSearchResults(); } - std::string TextEditor::Lines::getText(bool includeHiddenLines) { + std::string Lines::getText(bool includeHiddenLines) { auto start = lineCoordinates(0, 0); auto size = m_unfoldedLines.size(); auto line = m_unfoldedLines[size - 1]; @@ -911,7 +919,7 @@ namespace hex::ui { return result; } - std::string TextEditor::Lines::getSelectedText() { + std::string Lines::getSelectedText() { return getRange(m_state.m_selection); } @@ -923,7 +931,7 @@ namespace hex::ui { return m_lines.getRange(Range(sanitizedLine, endLine)); } - TextEditor::UndoRecord::UndoRecord( + UndoRecord::UndoRecord( std::string added, Range addedRange, std::string removed, @@ -931,7 +939,7 @@ namespace hex::ui { EditorState before, EditorState after) : m_added(std::move(added)), m_addedRange(addedRange), m_removed(std::move(removed)), m_removedRange(removedRange), m_before(std::move(before)), m_after(std::move(after)) {} - void TextEditor::UndoRecord::undo(TextEditor *editor) { + void UndoRecord::undo(TextEditor *editor) { if (!m_added.empty()) { editor->m_lines.deleteRange(m_addedRange); editor->m_lines.colorize(); @@ -947,7 +955,7 @@ namespace hex::ui { editor->m_lines.ensureCursorVisible(); } - void TextEditor::UndoRecord::redo(TextEditor *editor) { + void UndoRecord::redo(TextEditor *editor) { if (!m_removed.empty()) { editor->m_lines.deleteRange(m_removedRange); editor->m_lines.colorize(); @@ -963,12 +971,12 @@ namespace hex::ui { editor->m_lines.ensureCursorVisible(); } - void TextEditor::UndoAction::undo(TextEditor *editor) { + void UndoAction::undo(TextEditor *editor) { for (auto &record : m_records | std::views::reverse) record.undo(editor); } - void TextEditor::UndoAction::redo(TextEditor *editor) { + void UndoAction::redo(TextEditor *editor) { for (auto &record : m_records) record.redo(editor); } diff --git a/plugins/ui/source/ui/text_editor/highlighter.cpp b/plugins/ui/source/ui/text_editor/highlighter.cpp index 3205b274fb741..624792445253c 100644 --- a/plugins/ui/source/ui/text_editor/highlighter.cpp +++ b/plugins/ui/source/ui/text_editor/highlighter.cpp @@ -4,8 +4,12 @@ #include namespace hex::ui { - extern TextEditor::Palette s_paletteBase; + using Palette = TextEditor::Palette; using Keys = TextEditor::Keys; + using Lines = TextEditor::Lines; + using LanguageDefinition = TextEditor::LanguageDefinition; + + extern Palette s_paletteBase; void TextEditor::setEnableHighlighting(bool enable) { @@ -56,7 +60,7 @@ namespace hex::ui { } } - Keys TextEditor::Lines::getDeactivatedBlocks() { + Keys Lines::getDeactivatedBlocks() { colorizeInternal(); Keys deactivatedBlocks; if (isEmpty()) @@ -93,11 +97,11 @@ namespace hex::ui { } - void TextEditor::Lines::colorize() { + void Lines::colorize() { m_updateFlags = true; } - void TextEditor::Lines::colorizeRange(bool force) { + void Lines::colorizeRange(bool force) { if (isEmpty()) return; @@ -221,7 +225,7 @@ namespace hex::ui { } } - void TextEditor::Lines::colorizeInternal(bool force) { + void Lines::colorizeInternal(bool force) { if (isEmpty()) return; @@ -458,7 +462,7 @@ namespace hex::ui { colorizeRange(force); } - void TextEditor::Lines::setLanguageDefinition(const LanguageDefinition &languageDef) { + void Lines::setLanguageDefinition(const LanguageDefinition &languageDef) { m_languageDefinition = languageDef; m_regexList.clear(); @@ -468,13 +472,13 @@ namespace hex::ui { colorize(); } - const TextEditor::Palette &TextEditor::getPalette() { return s_paletteBase; } + const Palette &TextEditor::getPalette() { return s_paletteBase; } void TextEditor::setPalette(const Palette &value) { s_paletteBase = value; } - const TextEditor::Palette &TextEditor::getDarkPalette() { + const Palette &TextEditor::getDarkPalette() { const static Palette p = { { 0xff7f7f7f, // Default @@ -506,7 +510,7 @@ namespace hex::ui { return p; } - const TextEditor::Palette &TextEditor::getLightPalette() { + const Palette &TextEditor::getLightPalette() { const static Palette p = { { 0xff7f7f7f, // None @@ -538,7 +542,7 @@ namespace hex::ui { return p; } - const TextEditor::Palette &TextEditor::getRetroBluePalette() { + const Palette &TextEditor::getRetroBluePalette() { const static Palette p = { { 0xff00ffff, // None @@ -570,7 +574,7 @@ namespace hex::ui { return p; } - const TextEditor::LanguageDefinition &TextEditor::LanguageDefinition::CPlusPlus() { + const LanguageDefinition &LanguageDefinition::CPlusPlus() { static bool inited = false; static LanguageDefinition langDef; if (!inited) { @@ -643,7 +647,7 @@ namespace hex::ui { return langDef; } - const TextEditor::LanguageDefinition &TextEditor::LanguageDefinition::HLSL() { + const LanguageDefinition &LanguageDefinition::HLSL() { static bool inited = false; static LanguageDefinition langDef; if (!inited) { @@ -729,7 +733,7 @@ namespace hex::ui { return langDef; } - const TextEditor::LanguageDefinition &TextEditor::LanguageDefinition::GLSL() { + const LanguageDefinition &LanguageDefinition::GLSL() { static bool inited = false; static LanguageDefinition langDef; if (!inited) { @@ -780,7 +784,7 @@ namespace hex::ui { return langDef; } - const TextEditor::LanguageDefinition &TextEditor::LanguageDefinition::C() { + const LanguageDefinition &LanguageDefinition::C() { static bool inited = false; static LanguageDefinition langDef; if (!inited) { @@ -847,7 +851,7 @@ namespace hex::ui { return langDef; } - const TextEditor::LanguageDefinition &TextEditor::LanguageDefinition::SQL() { + const LanguageDefinition &LanguageDefinition::SQL() { static bool inited = false; static LanguageDefinition langDef; if (!inited) { @@ -925,7 +929,7 @@ namespace hex::ui { return langDef; } - const TextEditor::LanguageDefinition &TextEditor::LanguageDefinition::AngelScript() { + const LanguageDefinition &LanguageDefinition::AngelScript() { static bool inited = false; static LanguageDefinition langDef; if (!inited) { @@ -978,7 +982,7 @@ namespace hex::ui { return langDef; } - const TextEditor::LanguageDefinition &TextEditor::LanguageDefinition::Lua() { + const LanguageDefinition &LanguageDefinition::Lua() { static bool inited = false; static LanguageDefinition langDef; if (!inited) { diff --git a/plugins/ui/source/ui/text_editor/navigate.cpp b/plugins/ui/source/ui/text_editor/navigate.cpp index 0879bfd5a0560..c5986fca712e2 100644 --- a/plugins/ui/source/ui/text_editor/navigate.cpp +++ b/plugins/ui/source/ui/text_editor/navigate.cpp @@ -4,6 +4,13 @@ namespace hex::ui { + using Coordinates = TextEditor::Coordinates; + using Range = TextEditor::Range; + using Line = TextEditor::Line; + using Lines = TextEditor::Lines; + using MatchedDelimiter = TextEditor::MatchedDelimiter; + + static bool isWordChar(char c) { auto asUChar = static_cast(c); return std::isalnum(asUChar) || c == '_' || asUChar > 0x7F; @@ -30,7 +37,7 @@ namespace hex::ui { m_lines.moveToMatchedDelimiter(select); } - TextEditor::Coordinates TextEditor::Lines::rfind( const std::string &text, const Coordinates &from) { + Coordinates Lines::rfind( const std::string &text, const Coordinates &from) { Coordinates result = Invalid; if (text.empty() || isEmpty() || from.m_line >= size() || from.m_line < 0) return result; @@ -46,7 +53,7 @@ namespace hex::ui { } - TextEditor::Coordinates TextEditor::Lines::find(const std::string &text, const Coordinates &from) { + Coordinates Lines::find(const std::string &text, const Coordinates &from) { Coordinates result = Invalid; if (text.empty() || isEmpty() || from.m_line >= size() || from.m_line < 0) return result; @@ -62,7 +69,40 @@ namespace hex::ui { return result; } - void TextEditor::Lines::moveToMatchedDelimiter(bool select) { + void Lines::resetInteractiveSelection() { + m_interactiveSelection.m_start = m_interactiveSelection.m_end = m_state.m_cursorPosition; + } + + void Lines::selectUsingStart(bool select, const Coordinates &oldPos) { + if (select) { + if (oldPos == m_interactiveSelection.m_end) + m_interactiveSelection.m_end = m_state.m_cursorPosition; + else if (oldPos == m_interactiveSelection.m_start) + m_interactiveSelection.m_start = m_state.m_cursorPosition; + else { + m_interactiveSelection.m_start = oldPos; + m_interactiveSelection.m_end = m_state.m_cursorPosition; + } + } else + resetInteractiveSelection(); + } + + + void Lines::selectUsingEnd(bool select, const Coordinates &oldPos) { + if (select) { + if (oldPos == m_interactiveSelection.m_start) + m_interactiveSelection.m_start = m_state.m_cursorPosition; + else if (oldPos == m_interactiveSelection.m_end) + m_interactiveSelection.m_end = m_state.m_cursorPosition; + else { + m_interactiveSelection.m_start = m_state.m_cursorPosition; + m_interactiveSelection.m_end = oldPos; + } + } else + resetInteractiveSelection(); + } + + void Lines::moveToMatchedDelimiter(bool select) { resetCursorBlinkTime(); if (m_matchedDelimiter.coordinatesNearDelimiter(this, m_state.m_cursorPosition)) { auto oldPos = m_matchedDelimiter.m_nearCursor; @@ -96,7 +136,7 @@ namespace hex::ui { m_lines.ensureCursorVisible(); } - void TextEditor::Lines::moveUp(i32 amount, bool select) { + void Lines::moveUp(i32 amount, bool select) { auto oldPos = m_state.m_cursorPosition; if (amount < 0) { m_scrollYIncrement = -1.0; @@ -117,19 +157,8 @@ namespace hex::ui { m_state.m_cursorPosition.m_line = rowToLineIndex(row); } - if (oldPos != m_state.m_cursorPosition) { - if (select) { - if (oldPos == m_interactiveSelection.m_start) - m_interactiveSelection.m_start = m_state.m_cursorPosition; - else if (oldPos == m_interactiveSelection.m_end) - m_interactiveSelection.m_end = m_state.m_cursorPosition; - else { - m_interactiveSelection.m_start = m_state.m_cursorPosition; - m_interactiveSelection.m_end = oldPos; - } - } else - m_interactiveSelection.m_start = m_interactiveSelection.m_end = m_state.m_cursorPosition; - } + if (oldPos != m_state.m_cursorPosition) + selectUsingEnd(select, oldPos); } void TextEditor::moveDown(i32 amount, bool select) { @@ -140,7 +169,7 @@ namespace hex::ui { m_lines.ensureCursorVisible(); } - void TextEditor::Lines::moveDown(i32 amount, bool select) { + void Lines::moveDown(i32 amount, bool select) { auto oldPos = m_state.m_cursorPosition; if (amount < 0) { m_scrollYIncrement = 1.0; @@ -170,20 +199,8 @@ namespace hex::ui { m_state.m_cursorPosition.m_line = rowToLineIndex(row); } - - if (m_state.m_cursorPosition != oldPos) { - if (select) { - if (oldPos == m_interactiveSelection.m_end) - m_interactiveSelection.m_end = m_state.m_cursorPosition; - else if (oldPos == m_interactiveSelection.m_start) - m_interactiveSelection.m_start = m_state.m_cursorPosition; - else { - m_interactiveSelection.m_start = oldPos; - m_interactiveSelection.m_end = m_state.m_cursorPosition; - } - } else - m_interactiveSelection.m_start = m_interactiveSelection.m_end = m_state.m_cursorPosition; - } + if (m_state.m_cursorPosition != oldPos) + selectUsingStart(select, oldPos); } void TextEditor::moveLeft(i32 amount, bool select, bool wordMode) { @@ -193,7 +210,7 @@ namespace hex::ui { m_lines.ensureCursorVisible(); } - void TextEditor::Lines::moveLeft(i32 amount, bool select, bool wordMode) { + void Lines::moveLeft(i32 amount, bool select, bool wordMode) { auto oldPos = m_state.m_cursorPosition; auto foldedPos = unfoldedToFoldedCoords(oldPos); @@ -201,9 +218,8 @@ namespace hex::ui { return; auto lindex = foldedPos.m_line; - auto line = operator[](lindex); - auto lineMaxColumn = line.maxColumn(); - auto column = std::min(foldedPos.m_column, lineMaxColumn); + auto lineMaxCol = lineMaxColumn(lindex); + auto column = std::min(foldedPos.m_column, lineMaxCol); auto row = lineIndexToRow(lindex); while (amount-- > 0) { @@ -219,17 +235,7 @@ namespace hex::ui { m_state.m_cursorPosition = foldedToUnfoldedCoords(Coordinates( lindex, column - 1)); } - if (select) { - if (oldPos == m_interactiveSelection.m_start) - m_interactiveSelection.m_start = m_state.m_cursorPosition; - else if (oldPos == m_interactiveSelection.m_end) - m_interactiveSelection.m_end = m_state.m_cursorPosition; - else { - m_interactiveSelection.m_start = m_state.m_cursorPosition; - m_interactiveSelection.m_end = oldPos; - } - } else - m_interactiveSelection.m_start = m_interactiveSelection.m_end = m_state.m_cursorPosition; + selectUsingEnd(select, oldPos); } void TextEditor::moveRight(i32 amount, bool select, bool wordMode) { @@ -239,7 +245,7 @@ namespace hex::ui { m_lines.ensureCursorVisible(); } - void TextEditor::Lines::moveRight(i32 amount, bool select, bool wordMode) { + void Lines::moveRight(i32 amount, bool select, bool wordMode) { auto oldPos = m_state.m_cursorPosition; auto foldedPos = unfoldedToFoldedCoords(oldPos); @@ -265,17 +271,7 @@ namespace hex::ui { m_state.m_cursorPosition = foldedToUnfoldedCoords(Coordinates(lindex, column + 1)); } - if (select) { - if (oldPos == m_interactiveSelection.m_end) - m_interactiveSelection.m_end = m_state.m_cursorPosition; - else if (oldPos == m_interactiveSelection.m_start) - m_interactiveSelection.m_start = m_state.m_cursorPosition; - else { - m_interactiveSelection.m_start = oldPos; - m_interactiveSelection.m_end = m_state.m_cursorPosition; - } - } else - m_interactiveSelection.m_start = m_interactiveSelection.m_end = m_state.m_cursorPosition; + selectUsingStart(select, oldPos); } void TextEditor::moveTop(bool select) { @@ -310,7 +306,7 @@ namespace hex::ui { setSelection(m_lines.m_interactiveSelection); } - void TextEditor::Lines::moveHome(bool select) { + void Lines::moveHome(bool select) { auto oldPos = m_state.m_cursorPosition; Coordinates foldedPos = oldPos; auto row = lineIndexToRow(oldPos.m_line); @@ -360,19 +356,9 @@ namespace hex::ui { setCursorPosition(foldedToUnfoldedCoords(Coordinates(foldedPos.m_line, home))); } else setCursorPosition(Coordinates(m_state.m_cursorPosition.m_line, home)); - if (m_state.m_cursorPosition != oldPos) { - if (select) { - if (oldPos == m_interactiveSelection.m_start) - m_interactiveSelection.m_start = m_state.m_cursorPosition; - else if (oldPos == m_interactiveSelection.m_end) - m_interactiveSelection.m_end = m_state.m_cursorPosition; - else { - m_interactiveSelection.m_start = m_state.m_cursorPosition; - m_interactiveSelection.m_end = oldPos; - } - } else - m_interactiveSelection.m_start = m_interactiveSelection.m_end = m_state.m_cursorPosition; - } + + if (m_state.m_cursorPosition != oldPos) + selectUsingEnd(select, oldPos); } void TextEditor::moveEnd(bool select) { @@ -381,7 +367,7 @@ namespace hex::ui { setSelection(m_lines.m_interactiveSelection); } - void TextEditor::Lines::moveEnd(bool select) { + void Lines::moveEnd(bool select) { auto oldPos = m_state.m_cursorPosition; auto row = lineIndexToRow(oldPos.m_line); if (isMultiLineRow(row)) { @@ -394,22 +380,12 @@ namespace hex::ui { setCursorPosition(lineCoordinates(m_state.m_cursorPosition.m_line, lineMaxColumn(oldPos.m_line))); } - if (m_state.m_cursorPosition != oldPos) { - if (select) { - if (oldPos == m_interactiveSelection.m_end) - m_interactiveSelection.m_end = m_state.m_cursorPosition; - else if (oldPos == m_interactiveSelection.m_start) - m_interactiveSelection.m_start = m_state.m_cursorPosition; - else { - m_interactiveSelection.m_start = oldPos; - m_interactiveSelection.m_end = m_state.m_cursorPosition; - } - } else - m_interactiveSelection.m_start = m_interactiveSelection.m_end = m_state.m_cursorPosition; - } + if (m_state.m_cursorPosition != oldPos) + selectUsingStart(select, oldPos); + } - void TextEditor::Lines::setScrollY() { + void Lines::setScrollY() { if (!m_withinRender) { m_setScrollY = true; return; @@ -435,16 +411,17 @@ namespace hex::ui { m_lines.setFocusAtCoords(m_lines.m_state.m_cursorPosition, scrollToCursor); } - void TextEditor::Lines::setFocusAtCoords(const Coordinates &coords, bool scrollToCursor) { + void Lines::setFocusAtCoords(const Coordinates &coords, bool scrollToCursor) { m_focusAtCoords = coords; m_state.m_cursorPosition = coords; m_updateFocus = true; m_scrollToCursor = scrollToCursor; } - void TextEditor::Lines::setCursorPosition(const Coordinates &position, bool unfoldIfNeeded, bool scrollToCursor) { - if (m_state.m_cursorPosition != position) - m_state.m_cursorPosition = lineCoordinates(position); + void Lines::setCursorPosition(const Coordinates &position, bool unfoldIfNeeded, bool scrollToCursor) { + auto positionCoordinates = lineCoordinates(position); + if (m_state.m_cursorPosition != positionCoordinates) + m_state.m_cursorPosition = positionCoordinates; m_unfoldIfNeeded = unfoldIfNeeded; m_focusAtCoords = m_state.m_cursorPosition; @@ -453,11 +430,18 @@ namespace hex::ui { ensureCursorVisible(); } - void TextEditor::Lines::setCursorPosition() { + void Lines::setCursorPosition() { setCursorPosition(m_state.m_selection.m_end); } - bool TextEditor::Coordinates::isValid(Lines &lines) { + void Lines::setEditorState(const Coordinates &coordinates, bool setInteractiveStart) { + m_state.m_cursorPosition = m_interactiveSelection.m_end = coordinates; + if (setInteractiveStart) + m_interactiveSelection.m_start = coordinates; + setSelection(m_interactiveSelection); + } + + bool Coordinates::isValid(Lines &lines) { auto maxLine = lines.size(); if (std::abs(m_line) > maxLine) @@ -466,7 +450,7 @@ namespace hex::ui { return std::abs(m_column) <= maxColumn; } - TextEditor::Coordinates TextEditor::Coordinates::sanitize(Lines &lines) { + Coordinates Coordinates::sanitize(Lines &lines) { i32 lineCount = lines.size(); if (m_line < 0) { @@ -486,11 +470,11 @@ namespace hex::ui { return *this; } - TextEditor::Range::Coordinates TextEditor::lineCoordinates(i32 lineIndex, i32 column) { + Coordinates TextEditor::lineCoordinates(i32 lineIndex, i32 column) { return m_lines.lineCoordinates(lineIndex, column); } - TextEditor::Range::Coordinates TextEditor::Lines::lineCoordinates(i32 lineIndex, i32 column) { + Coordinates Lines::lineCoordinates(i32 lineIndex, i32 column) { if (isEmpty()) return {0, 0}; Coordinates result(lineIndex, column); @@ -498,21 +482,21 @@ namespace hex::ui { return result.sanitize(*this); } - TextEditor::Coordinates TextEditor::lineCoordinates(const Coordinates &value) { + Coordinates TextEditor::lineCoordinates(const Coordinates &value) { return m_lines.lineCoordinates(value); } - TextEditor::Coordinates TextEditor::Lines::lineCoordinates(const Coordinates &value) { + Coordinates Lines::lineCoordinates(const Coordinates &value) { auto result = value; return result.sanitize(*this); } - TextEditor::Range TextEditor::lineCoordinates(const Range &value) { + Range TextEditor::lineCoordinates(const Range &value) { return m_lines.lineCoordinates(value); } - TextEditor::Range TextEditor::Lines::lineCoordinates(const Range &value) { + Range TextEditor::Lines::lineCoordinates(const Range &value) { auto start = lineCoordinates(value.m_start); auto end = lineCoordinates(value.m_end); if (start == Invalid || end == Invalid) @@ -540,7 +524,7 @@ namespace hex::ui { coordinates.m_column += incr; } - TextEditor::Coordinates TextEditor::findWordStart(const Coordinates &from) { + Coordinates TextEditor::findWordStart(const Coordinates &from) { Coordinates at = m_lines.lineCoordinates(from); if (at.m_line >= m_lines.size()) return at; @@ -562,7 +546,7 @@ namespace hex::ui { return m_lines.lineIndexCoords(at.m_line + 1, charIndex); } - TextEditor::Coordinates TextEditor::findWordEnd(const Coordinates &from) { + Coordinates TextEditor::findWordEnd(const Coordinates &from) { Coordinates at = m_lines.lineCoordinates(from); if (at.m_line >= m_lines.size()) return at; @@ -585,7 +569,7 @@ namespace hex::ui { return m_lines.lineIndexCoords(at.m_line + 1, charIndex); } - TextEditor::Coordinates TextEditor::Lines::findNextWord(const Coordinates &from) { + Coordinates Lines::findNextWord(const Coordinates &from) { Coordinates at = unfoldedToFoldedCoords(from); if (at.m_line >= size()) return from; @@ -606,7 +590,7 @@ namespace hex::ui { return foldedToUnfoldedCoords(lineIndexCoords(at.m_line + 1, charIndex)); } - TextEditor::Coordinates TextEditor::Lines::findPreviousWord(const Coordinates &from) { + Coordinates Lines::findPreviousWord(const Coordinates &from) { Coordinates at = unfoldedToFoldedCoords(from); if (at.m_line >= size()) return from; @@ -628,13 +612,13 @@ namespace hex::ui { return foldedToUnfoldedCoords(lineIndexCoords(at.m_line + 1, charIndex)); } - u32 TextEditor::Line::skipSpaces(i32 charIndex) { + u32 Line::skipSpaces(i32 charIndex) { u32 s; for (s = 0; charIndex < (i32) m_chars.size() && m_chars[charIndex] == ' ' && m_flags[charIndex] == 0x00; ++s, ++charIndex); return s; } - u32 TextEditor::Lines::skipSpaces(const Coordinates &from) { + u32 Lines::skipSpaces(const Coordinates &from) { auto lineIndex = from.m_line; if (lineIndex >= (i64) size()) return 0; @@ -643,7 +627,7 @@ namespace hex::ui { return line.skipSpaces(charIndex); } - bool TextEditor::MatchedDelimiter::setNearCursor(Lines *lines,const Coordinates &from) { + bool MatchedDelimiter::setNearCursor(Lines *lines,const Coordinates &from) { Coordinates fromCopy = from; if (fromCopy.m_line >= lines->size()) return false; @@ -658,7 +642,7 @@ namespace hex::ui { return false; } - bool TextEditor::MatchedDelimiter::checkPosition(Lines *lines, Coordinates &from) { + bool MatchedDelimiter::checkPosition(Lines *lines, Coordinates &from) { auto start = lines->lineCoordinates(from); auto lineIndex = start.m_line; auto line = lines->m_unfoldedLines[lineIndex].m_chars; @@ -680,7 +664,7 @@ namespace hex::ui { return false; } - i32 TextEditor::MatchedDelimiter::detectDirection(Lines *lines, const Coordinates &from) { + i32 MatchedDelimiter::detectDirection(Lines *lines, const Coordinates &from) { auto start = lines->lineCoordinates(from); std::string delimiters = "()[]{}<>"; i32 result = -2; // dont check either @@ -715,7 +699,7 @@ namespace hex::ui { return result; } - bool TextEditor::MatchedDelimiter::coordinatesNearDelimiter(Lines *lines, Coordinates &from) { + bool MatchedDelimiter::coordinatesNearDelimiter(Lines *lines, Coordinates &from) { auto start = lines->lineCoordinates(from); if (lines->isEmpty()) return false; @@ -787,7 +771,7 @@ namespace hex::ui { return false; } - TextEditor::Coordinates TextEditor::MatchedDelimiter::findMatchingDelimiter(Lines *lines, Coordinates &from, bool folded) { + Coordinates MatchedDelimiter::findMatchingDelimiter(Lines *lines, Coordinates &from, bool folded) { Coordinates start; Coordinates result = Invalid; if (!folded) @@ -936,7 +920,7 @@ namespace hex::ui { return result; } - void TextEditor::MatchedDelimiter::findMatchingDelimiter(Lines *lines, bool folded) { + void MatchedDelimiter::findMatchingDelimiter(Lines *lines, bool folded) { Coordinates from = m_nearCursor; Coordinates result = findMatchingDelimiter(lines, from, folded); if (result != Invalid) { diff --git a/plugins/ui/source/ui/text_editor/render.cpp b/plugins/ui/source/ui/text_editor/render.cpp index ba72ca810d0dd..f955e94535247 100644 --- a/plugins/ui/source/ui/text_editor/render.cpp +++ b/plugins/ui/source/ui/text_editor/render.cpp @@ -9,7 +9,10 @@ namespace hex::ui { TextEditor::Palette s_paletteBase = TextEditor::getDarkPalette(); - using Keys = TextEditor::Keys; + using Keys = TextEditor::Keys; + using Line = TextEditor::Line; + using Lines = TextEditor::Lines; + using FoldedLine = TextEditor::FoldedLine; inline void TextUnformattedColored(const ImU32 &color, const char *text) { ImGui::PushStyleColor(ImGuiCol_Text, color); @@ -35,7 +38,7 @@ namespace hex::ui { return x; } - void TextEditor::Line::print(i32 lineIndex, i32 maxLineIndex, std::optional position) { + void Line::print(i32 lineIndex, i32 maxLineIndex, std::optional position) { u32 idx = 0; std::string lineNumberStr = std::to_string(lineIndex + 1); auto padding = std::string(std::to_string(maxLineIndex + 1).size() - lineNumberStr.size(),' '); @@ -82,23 +85,23 @@ namespace hex::ui { m_lines.clearErrorMarkers(); } - void TextEditor::Lines::clearErrorMarkers() { + void Lines::clearErrorMarkers() { m_errorMarkers.clear(); m_errorHoverBoxes.clear(); } - void TextEditor::Lines::clearCodeFolds() { + void Lines::clearCodeFolds() { m_codeFolds.clear(); m_codeFoldKeys.clear(); } - void TextEditor::Lines::clearActionables() { + void Lines::clearActionables() { clearErrorMarkers(); clearGotoBoxes(); clearCursorBoxes(); } - bool TextEditor::Lines::lineNeedsDelimiter(i32 lineIndex) { + bool Lines::lineNeedsDelimiter(i32 lineIndex) { auto row = lineIndexToRow(lineIndex); if (row == -1.0 || !m_foldedLines.contains(row)) { if (lineIndex >= (i64)m_unfoldedLines.size() || lineIndex < 0) @@ -112,7 +115,7 @@ namespace hex::ui { auto delimiter = m_codeFoldDelimiters[key].first; if (!delimiter || (delimiter != '(' && delimiter != '[' && delimiter != '{' && delimiter != '<')) return false; - if (key.m_start.m_column >= m_unfoldedLines[lineIndex].m_lineMaxColumn) + if (key.m_start.m_column >= lineMaxColumn(lineIndex)) return true; return !line.contains(delimiter); } @@ -122,15 +125,15 @@ namespace hex::ui { return m_foldedLines.at(row).firstLineNeedsDelimiter(); } - bool TextEditor::FoldedLine::firstLineNeedsDelimiter() { + bool FoldedLine::firstLineNeedsDelimiter() { return ((u8)m_type & (u8)FoldedLine::FoldType::FirstLineNeedsDelimiter); } - bool TextEditor::FoldedLine::addsLastLineToFold() { + bool FoldedLine::addsLastLineToFold() { return (u8)m_type & (u8)FoldedLine::FoldType::AddsLastLine; } - bool TextEditor::FoldedLine::addsFullFirstLineToFold() { + bool FoldedLine::addsFullFirstLineToFold() { return (u8)m_type & (u8)FoldedLine::FoldType::AddsFirstLine; } @@ -174,37 +177,37 @@ namespace hex::ui { return ImGui::GetCurrentWindow()->InnerClipRect.GetHeight() / m_lines.m_charAdvance.y; } - bool TextEditor::Lines::isEndOfLine() { + bool Lines::isEndOfLine() { return isEndOfLine(m_state.m_cursorPosition); } - bool TextEditor::Lines::isStartOfLine() const { + bool Lines::isStartOfLine() const { return m_state.m_cursorPosition.m_column == 0; } - bool TextEditor::Line::isEndOfLine(i32 column) { + bool Line::isEndOfLine(i32 column) { return column >= maxColumn(); } - bool TextEditor::Lines::isEndOfLine(const Coordinates &coordinates) { + bool Lines::isEndOfLine(const Coordinates &coordinates) { if (coordinates.m_line < size()) return m_unfoldedLines[coordinates.m_line].isEndOfLine(coordinates.m_column); return true; } - bool TextEditor::Lines::isEndOfFile(const Coordinates &coordinates) { + bool Lines::isEndOfFile(const Coordinates &coordinates) { if (coordinates.m_line < size()) return isLastLine(coordinates.m_line) && isEndOfLine(coordinates); return true; } - bool TextEditor::Lines::isLastLine() { + bool Lines::isLastLine() { return isLastLine(m_state.m_cursorPosition.m_line); } - bool TextEditor::Lines::isLastLine(i32 lineIndex) { + bool Lines::isLastLine(i32 lineIndex) { auto row = lineIndexToRow(lineIndex); return row == getMaxDisplayedRow(); } @@ -219,14 +222,14 @@ namespace hex::ui { } } - float TextEditor::Lines::getMaxDisplayedRow() { + float Lines::getMaxDisplayedRow() { auto maxRow = getGlobalRowMax(); if (maxRow - m_topRow < m_numberOfLinesDisplayed) return maxRow; return m_topRow + m_numberOfLinesDisplayed; } - float TextEditor::Lines::getGlobalRowMax() { + float Lines::getGlobalRowMax() { float maxRow = size() - 1.0f; if (m_codeFoldsDisabled || m_foldedLines.empty() || m_codeFoldKeys.empty()) return std::floor(maxRow); @@ -1063,8 +1066,8 @@ namespace hex::ui { lineIndex = key.m_end.m_line; m_foldedSegments[2] = m_lines->lineCoordinates( foldedLineIndex, m_ellipsisIndices[0] + Ellipsis.size() - 1); m_foldedSegments[3] = m_lines->lineCoordinates( foldedLineIndex, m_ellipsisIndices[0] + Ellipsis.size()); - m_unfoldedSegments[2] = m_lines->lineCoordinates( lineIndex , m_lines->m_unfoldedLines[lineIndex].maxColumn() - 1); - m_unfoldedSegments[3] = m_lines->lineCoordinates( lineIndex , m_lines->m_unfoldedLines[lineIndex].maxColumn()); + m_unfoldedSegments[2] = m_lines->lineCoordinates( lineIndex , m_lines->lineMaxColumn(lineIndex) - 1); + m_unfoldedSegments[3] = m_lines->lineCoordinates( lineIndex , m_lines->lineMaxColumn(lineIndex)); return; } @@ -1094,7 +1097,7 @@ namespace hex::ui { m_foldedSegments[2 * keyCount] = m_lines->lineCoordinates(foldedLineIndex, m_ellipsisIndices.back() + 3); m_foldedSegments[2 * keyCount + 1] = m_lines->lineCoordinates(foldedLineIndex, m_foldedLine.maxColumn()); m_unfoldedSegments[2 * keyCount] = m_lines->lineCoordinates( lineIndex, delimiterCoordinates.m_end.m_column); - m_unfoldedSegments[2 * keyCount + 1] = m_lines->lineCoordinates( lineIndex, m_lines->m_unfoldedLines[lineIndex].maxColumn()); + m_unfoldedSegments[2 * keyCount + 1] = m_lines->lineCoordinates( lineIndex, m_lines->lineMaxColumn(lineIndex)); } void TextEditor::Lines::removeKeys() { @@ -1270,7 +1273,7 @@ namespace hex::ui { i64 start = ImGui::GetScrollX(); Coordinates head = Coordinates(lineIndex, start / m_lines.m_charAdvance.x); i64 textSize = m_lines.textDistanceToLineStart(head); - auto maxColumn = line.indexColumn(line.size()); + auto maxColumn = line.maxColumn(); if (textSize < start) { while (textSize < start && head.m_column < maxColumn) { head.m_column += 1; diff --git a/plugins/ui/source/ui/text_editor/support.cpp b/plugins/ui/source/ui/text_editor/support.cpp index 665466aa66cf4..2c2b70c4449b4 100644 --- a/plugins/ui/source/ui/text_editor/support.cpp +++ b/plugins/ui/source/ui/text_editor/support.cpp @@ -586,7 +586,7 @@ namespace hex::ui { return m_selection == o.m_selection && m_cursorPosition == o.m_cursorPosition; } - void TextEditor::Lines::setSelection(const Range &selection) { + void Lines::setSelection(const Range &selection) { m_state.m_selection = lineCoordinates(const_cast(selection)); } @@ -594,7 +594,7 @@ namespace hex::ui { m_lines.setSelection(selection); } - Range TextEditor::Lines::getSelection() const { + Range Lines::getSelection() const { return m_state.m_selection; } @@ -607,15 +607,24 @@ namespace hex::ui { setSelection(Range(wordStart, findWordEnd(wordStart))); } + void TextEditor::selectLineUnderCursor() { + auto coordinates = m_lines.m_state.m_cursorPosition; + auto lineIndex = rowToLineIndex(lineIndexToRow(coordinates.m_line)); + auto maxColumn = m_lines.lineMaxColumn(lineIndex); + m_lines.m_state.m_selection.m_start = m_lines.foldedToUnfoldedCoords(Coordinates(lineIndex, 0)); + m_lines.m_state.m_selection.m_end = m_lines.foldedToUnfoldedCoords(Coordinates(lineIndex, maxColumn)); + m_lines.resetInteractiveSelection(); + } + void TextEditor::selectAll() { setSelection(Range(m_lines.lineCoordinates(0, 0), m_lines.lineCoordinates(-1, -1))); } - bool TextEditor::Lines::hasSelection() { + bool Lines::hasSelection() { return !isEmpty() && m_state.m_selection.m_end > m_state.m_selection.m_start; } - void TextEditor::Lines::addUndo(std::vector value) { + void Lines::addUndo(std::vector value) { if (m_readOnly) return; @@ -624,7 +633,7 @@ namespace hex::ui { m_undoIndex++; } - TextEditor::PaletteIndex TextEditor::Lines::getColorIndexFromFlags(Line::Flags flags) { + TextEditor::PaletteIndex Lines::getColorIndexFromFlags(Line::Flags flags) { auto commentBits = flags.m_value & inComment; if (commentBits == (i32) Line::FlagValues::Global) return PaletteIndex::GlobalDocComment; @@ -695,83 +704,62 @@ namespace hex::ui { Left mouse button triple click */ + auto coordinates = screenPosCoordinates(ImGui::GetMousePos()); + if (coordinates == Invalid) + return; + if (tripleClick) { - auto coordinates = screenPosCoordinates(ImGui::GetMousePos()); - if (coordinates == Invalid) - return; if (!ctrl) { m_lines.m_state.m_cursorPosition = coordinates; - auto lineIndex = rowToLineIndex(lineIndexToRow(coordinates.m_line)); - auto line = m_lines[lineIndex]; - m_lines.m_state.m_selection.m_start = m_lines.foldedToUnfoldedCoords(Coordinates(lineIndex, 0)); - m_lines.m_state.m_selection.m_end = m_lines.foldedToUnfoldedCoords(Coordinates(lineIndex, line.maxColumn())); + selectLineUnderCursor(); } m_lastClick = -1.0f; resetBlinking = true; } - /* - Left mouse button double click - */ - + /* + Left mouse button double click + */ else if (doubleClick) { - auto coordinates = screenPosCoordinates(ImGui::GetMousePos()); - if (coordinates == Invalid) - return; if (!ctrl) { - m_lines.m_state.m_cursorPosition = coordinates; - m_lines.m_state.m_selection.m_start = findWordStart(m_lines.m_state.m_cursorPosition); - m_lines.m_state.m_selection.m_end = findWordEnd(m_lines.m_state.m_cursorPosition); + m_lines.setEditorState(coordinates); + selectWordUnderCursor(); } m_lastClick = (float) ImGui::GetTime(); resetBlinking = true; } - /* - Left mouse button click - */ + /* + Left mouse button click + */ else if (click) { - auto coordinates = screenPosCoordinates(ImGui::GetMousePos()); - if (coordinates == Invalid) - return; if (ctrl) { - m_lines.m_state.m_cursorPosition = m_lines.m_interactiveSelection.m_start = m_lines.m_interactiveSelection.m_end = coordinates; + m_lines.setEditorState(coordinates); selectWordUnderCursor(); - } else if (shift) { - m_lines.m_state.m_cursorPosition = m_lines.m_interactiveSelection.m_end = coordinates; - setSelection(m_lines.m_interactiveSelection); - } else { - m_lines.m_state.m_cursorPosition = m_lines.m_interactiveSelection.m_end = m_lines.m_interactiveSelection.m_start = coordinates; - setSelection(m_lines.m_interactiveSelection); - } - m_lines.resetCursorBlinkTime(); + } else if (shift) + m_lines.setEditorState(coordinates, false); + else + m_lines.setEditorState(coordinates); + m_lines.resetCursorBlinkTime(); m_lines.ensureCursorVisible(); m_lastClick = (float) ImGui::GetTime(); } else if (rightClick) { - auto coordinates = screenPosCoordinates(ImGui::GetMousePos()); - if (coordinates == Invalid) - return; auto cursorPosition = coordinates; - if (!m_lines.hasSelection() || m_lines.m_state.m_selection.m_start > cursorPosition || cursorPosition > m_lines.m_state.m_selection.m_end) { - m_lines.m_state.m_cursorPosition = m_lines.m_interactiveSelection.m_start = m_lines.m_interactiveSelection.m_end = cursorPosition; - setSelection(m_lines.m_interactiveSelection); - } - m_lines.resetCursorBlinkTime(); + if (!m_lines.hasSelection() || !m_lines.m_state.m_selection.contains(cursorPosition,Range::EndsInclusive::Both)) + m_lines.setEditorState(cursorPosition); + + resetBlinking = true; m_raiseContextMenu = true; ImGui::SetWindowFocus(); } - // Mouse left button dragging (=> update selection) + // Mouse left button dragging (=> update selection) else if (ImGui::IsMouseDragging(0) && ImGui::IsMouseDown(0)) { - auto coordinates = screenPosCoordinates(ImGui::GetMousePos()); - if (coordinates == Invalid) - return; io.WantCaptureMouse = true; - m_lines.m_state.m_cursorPosition = m_lines.m_interactiveSelection.m_end = coordinates; - setSelection(m_lines.m_interactiveSelection); + m_lines.setEditorState(coordinates, false); m_lines.ensureCursorVisible(); resetBlinking = true; } @@ -1181,7 +1169,7 @@ namespace hex::ui { return true; } - ImRect TextEditor::Lines::getBoxForRow(u32 row) { + ImRect Lines::getBoxForRow(u32 row) { auto boxSize = m_charAdvance.x + (((u32) m_charAdvance.x % 2) ? 2.0f : 1.0f); auto lineStartScreenPos = getLineStartScreenPos(0,row); ImVec2 lineNumberStartScreenPos = ImVec2(m_lineNumbersStartPos.x + m_lineNumberFieldWidth, lineStartScreenPos.y); @@ -1279,7 +1267,7 @@ namespace hex::ui { return m_lines.size(); } - void TextEditor::Lines::setAllCodeFolds() { + void Lines::setAllCodeFolds() { initializeCodeFolds(); CodeFoldBlocks intervals = foldPointsFromSource(); m_codeFoldKeys.clear(); @@ -1321,7 +1309,7 @@ namespace hex::ui { } } - void TextEditor::Lines::removeHiddenLinesFromPattern() { + void Lines::removeHiddenLinesFromPattern() { i32 lineIndex = 0; const auto totalLines = (i32)m_unfoldedLines.size(); while (lineIndex < totalLines && m_unfoldedLines[lineIndex].m_chars.starts_with("//+-")) @@ -1339,7 +1327,7 @@ namespace hex::ui { } } - void TextEditor::Lines::addHiddenLinesToPattern() { + void Lines::addHiddenLinesToPattern() { if (m_hiddenLines.empty()) return; for (const auto &hiddenLine : m_hiddenLines) { @@ -1409,11 +1397,11 @@ namespace hex::ui { } } } - bool TextEditor::Lines::isTokenIdValid(i32 tokenId) { + bool Lines::isTokenIdValid(i32 tokenId) { return tokenId >= 0 && tokenId < (i32) m_tokens.size(); } - bool TextEditor::Lines::isLocationValid(Location location) { + bool Lines::isLocationValid(Location location) { const pl::api::Source *source; try { source = location.source; @@ -1426,7 +1414,7 @@ namespace hex::ui { return location > m_tokens.front().location && location < m_tokens.back().location; } - void TextEditor::Lines::loadFirstTokenIdOfLine() { + void Lines::loadFirstTokenIdOfLine() { const u32 tokenCount = m_tokens.size(); m_firstTokenIdOfLine.clear(); u32 tokenId = 0; @@ -1473,14 +1461,14 @@ namespace hex::ui { } - pl::core::Location TextEditor::Lines::getLocation(i32 tokenId) { + pl::core::Location Lines::getLocation(i32 tokenId) { if (tokenId >= (i32) m_tokens.size()) return Location::Empty(); return m_tokens[tokenId].location; } - i32 TextEditor::Lines::getTokenId(hex::ui::TextEditor::SafeTokenIterator tokenIterator) { + i32 Lines::getTokenId(TextEditor::SafeTokenIterator tokenIterator) { auto start = m_tokens.data(); auto m_start = &tokenIterator.front(); auto m_end = &tokenIterator.back(); @@ -1490,7 +1478,7 @@ namespace hex::ui { return m_start - start; } - i32 TextEditor::Lines::getTokenId() { + i32 Lines::getTokenId() { auto start = m_tokens.data(); auto m_start = &m_curr.front(); auto m_end = &m_curr.back(); @@ -1501,7 +1489,7 @@ namespace hex::ui { } // Get the token index for a given location. - i32 TextEditor::Lines::getTokenId(pl::core::Location location) { + i32 Lines::getTokenId(pl::core::Location location) { if (location == m_tokens.at(0).location) return 0; if (location == m_tokens.back().location) @@ -1531,7 +1519,7 @@ namespace hex::ui { return -1; } - i32 TextEditor::Lines::nextLineIndex(i32 lineIndex) { + i32 Lines::nextLineIndex(i32 lineIndex) { if (lineIndex < 0 || lineIndex >= size()) return -1; auto currentTokenId = m_firstTokenIdOfLine[lineIndex]; diff --git a/plugins/ui/source/ui/text_editor/utf8.cpp b/plugins/ui/source/ui/text_editor/utf8.cpp index 068f961e670f3..229e4aa8fb5c0 100644 --- a/plugins/ui/source/ui/text_editor/utf8.cpp +++ b/plugins/ui/source/ui/text_editor/utf8.cpp @@ -9,8 +9,10 @@ namespace hex::ui { using Coordinates = TextEditor::Coordinates; using Segments = TextEditor::Segments; + using Line = TextEditor::Line; + using Lines = TextEditor::Lines; - TextEditor::Line TextEditor::Line::trim(TrimMode trimMode) { + Line Line::trim(TrimMode trimMode) { if (m_chars.empty()) return m_emptyLine; std::string trimmed = wolv::util::trim(m_chars); @@ -27,7 +29,7 @@ namespace hex::ui { return subLine(idx, trimmed.size()); } - i32 TextEditor::Line::columnIndex(i32 column) const { + i32 Line::columnIndex(i32 column) const { i32 idx = 0; for (i32 col = 0; idx < (i32) size() && col < column; ++col) @@ -36,20 +38,20 @@ namespace hex::ui { return idx; } - i32 TextEditor::Line::maxColumn() { + i32 Line::maxColumn() { if (m_lineMaxColumn > 0) return m_lineMaxColumn; m_lineMaxColumn = indexColumn((i32) size()); return m_lineMaxColumn; } - i32 TextEditor::Line::maxColumn() const { + i32 Line::maxColumn() const { if (m_lineMaxColumn > 0) return m_lineMaxColumn; return indexColumn((i32) size()); } - i32 TextEditor::Line::indexColumn(i32 stringIndex) const { + i32 Line::indexColumn(i32 stringIndex) const { i32 limit = std::max(0, std::min(stringIndex, (i32) size())); i32 col = 0; @@ -59,7 +61,7 @@ namespace hex::ui { return col; } - i32 TextEditor::Line::stringTextSize(const std::string &str) const { + i32 Line::stringTextSize(const std::string &str) const { if (str.empty()) return 0; if (ImGui::GetFont() == nullptr) { @@ -71,24 +73,24 @@ namespace hex::ui { return ImGui::GetFont()->CalcTextSizeA(ImGui::GetFontSize(), FLT_MAX, -1.0f, str.c_str(), nullptr, nullptr).x; } - i32 TextEditor::Line::textSize(u32 index) const { + i32 Line::textSize(u32 index) const { if (m_chars.empty()) return 0; return stringTextSize(m_chars.substr(0, index)); } - i32 TextEditor::Line::textSize() const { + i32 Line::textSize() const { if (m_chars.empty()) return 0; return stringTextSize(m_chars); } - i32 TextEditor::Line::lineTextSize(TrimMode trimMode) { + i32 Line::lineTextSize(TrimMode trimMode) { auto trimmedLine = trim(trimMode); return trimmedLine.textSize(); } - i32 TextEditor::Line::textSizeIndex(float textSize, i32 position) { + i32 Line::textSizeIndex(float textSize, i32 position) { i32 result = textSize / ImGui::GetFont()->CalcTextSizeA(ImGui::GetFontSize(), FLT_MAX, -1.0f, "#", nullptr, nullptr).x; auto currentSize = stringTextSize(m_chars.substr(position, result)); while (currentSize < textSize && (u32)(position + result) < size()) { @@ -130,7 +132,7 @@ namespace hex::ui { return line.indexColumn(stringIndex); } - i32 TextEditor::Lines::lineMaxColumn(i32 lineIndex) { + i32 Lines::lineMaxColumn(i32 lineIndex) { if (lineIndex >= (i64) size() || lineIndex < 0) return 0; @@ -227,7 +229,7 @@ namespace hex::ui { return {coordinates.m_line,line.columnIndex(coordinates.m_column)}; } - i32 TextEditor::Lines::lineCoordsIndex(const Coordinates &coordinates) { + i32 Lines::lineCoordsIndex(const Coordinates &coordinates) { if (coordinates.m_line >= (i64) size()) return -1; @@ -235,44 +237,42 @@ namespace hex::ui { return line.columnIndex(coordinates.m_column); } - Coordinates TextEditor::Lines::lineIndexCoords(i32 lineNumber, i32 stringIndex) { + Coordinates Lines::lineIndexCoords(i32 lineNumber, i32 stringIndex) { if (lineNumber < 1 || lineNumber > size()) return lineCoordinates( 0, 0); auto &line = operator[](lineNumber - 1); return lineCoordinates(lineNumber - 1, line.indexColumn(stringIndex)); } - Segments TextEditor::Lines::unfoldedEllipsisCoordinates(Range delimiterCoordinates) { + Segments Lines::unfoldedEllipsisCoordinates(Range delimiterCoordinates) { auto lineStart = m_unfoldedLines[delimiterCoordinates.m_start.m_line]; auto row = lineIndexToRow(delimiterCoordinates.m_start.m_line); float unfoldedSpan1, unfoldedSpan2, unfoldedSpan3; float unprocessedSpan1, unprocessedSpan2, unprocessedSpan3; - bool adddsBothEnds = true; + bool addsBothEnds = true; if (delimiterCoordinates.m_start.m_line == delimiterCoordinates.m_end.m_line) { unprocessedSpan1 = unfoldedSpan1 = delimiterCoordinates.m_end.m_column - delimiterCoordinates.m_start.m_column - 1; unprocessedSpan3 = unfoldedSpan3 = 0.0f; unprocessedSpan2 = unfoldedSpan2 = 0.0f; } else if (!m_foldedLines[row].addsFullFirstLineToFold() && !m_foldedLines[row].addsLastLineToFold()) { - adddsBothEnds = false; - auto innerLine = m_unfoldedLines[delimiterCoordinates.m_start.m_line]; - unprocessedSpan1 = unfoldedSpan1 = std::max(innerLine.maxColumn() - 1, 0); - innerLine = m_unfoldedLines[delimiterCoordinates.m_end.m_line]; - unprocessedSpan3 = unfoldedSpan3 = std::max(innerLine.maxColumn() - 1, 0); + addsBothEnds = false; + unfoldedSpan1 = std::max(lineMaxColumn(delimiterCoordinates.m_start.m_line) - 1, 0); + unprocessedSpan1 = unfoldedSpan1; + unfoldedSpan3 = std::max(lineMaxColumn(delimiterCoordinates.m_end.m_line) - 1, 0); + unprocessedSpan3 = unfoldedSpan3; unfoldedSpan2 = 0; - for (i32 j = delimiterCoordinates.m_start.m_line + 1; j < delimiterCoordinates.m_end.m_line; j++) { - innerLine = m_unfoldedLines[j]; - unfoldedSpan2 += innerLine.maxColumn(); - } + for (i32 j = delimiterCoordinates.m_start.m_line + 1; j < delimiterCoordinates.m_end.m_line; j++) + unfoldedSpan2 += lineMaxColumn(j); + unprocessedSpan2 = unfoldedSpan2; } else { unprocessedSpan1 = unfoldedSpan1 = std::max(lineStart.maxColumn() - delimiterCoordinates.m_start.m_column - 2, 0); unprocessedSpan3 = unfoldedSpan3 = std::max(delimiterCoordinates.m_end.m_column - 1, 0); unfoldedSpan2 = 0; - for (i32 j = delimiterCoordinates.m_start.m_line + 1; j < delimiterCoordinates.m_end.m_line; j++) { - auto innerLine = m_unfoldedLines[j]; - unfoldedSpan2 += innerLine.maxColumn(); - } + for (i32 j = delimiterCoordinates.m_start.m_line + 1; j < delimiterCoordinates.m_end.m_line; j++) + unfoldedSpan2 += lineMaxColumn(j); + unprocessedSpan2 = unfoldedSpan2; } @@ -287,7 +287,7 @@ namespace hex::ui { float spanFragment = totalUnfoldedSpan / 2.0f; Segments unfoldedEllipsisCoordinates(4); - if (adddsBothEnds) { + if (addsBothEnds) { unfoldedEllipsisCoordinates[0] = lineCoordinates(delimiterCoordinates.m_start.m_line, delimiterCoordinates.m_start.m_column + 1); unfoldedEllipsisCoordinates[3] = delimiterCoordinates.m_end; } else { @@ -310,7 +310,7 @@ namespace hex::ui { if ((unprocessedSpan2 > spanFragment || std::fabs(unprocessedSpan2 - spanFragment) < 0.001) && i < 3) { float lineLength = 0.0f; for (i32 j = delimiterCoordinates.m_start.m_line + 1; j < delimiterCoordinates.m_end.m_line; j++) { - auto currentLineLength = (float) m_unfoldedLines[j].maxColumn(); + auto currentLineLength = (float) lineMaxColumn(j); lineLength += currentLineLength + leftOver; leftOver = 0.0f; while ((lineLength > spanFragment || std::fabs(lineLength-spanFragment) < 0.001) && i < 3) { @@ -333,7 +333,7 @@ namespace hex::ui { return unfoldedEllipsisCoordinates; } - Coordinates TextEditor::Lines::foldedToUnfoldedCoords(const Coordinates &coords) { + Coordinates Lines::foldedToUnfoldedCoords(const Coordinates &coords) { auto row = lineIndexToRow(coords.m_line); if (row == -1.0 || !m_foldedLines.contains(row)) return coords; @@ -382,9 +382,8 @@ namespace hex::ui { auto foldedSegmentStart = foldedLine.m_foldedSegments[foundIndex]; if (foundIndex == 0) { if (lineNeedsDelimiter(key.m_start.m_line)) { - auto line = m_unfoldedLines[key.m_start.m_line]; auto delimiterCoordinates = foldedLine.findDelimiterCoordinates(key); - if (coords.m_column > line.maxColumn()) + if (coords.m_column > lineMaxColumn(key.m_start.m_line)) return delimiterCoordinates.m_start; else return lineCoordinates( unfoldedSegmentStart.m_line, coords.m_column); @@ -402,7 +401,7 @@ namespace hex::ui { else return {coordinate.m_line,coordinate.m_column + 1}; } - bool TextEditor::testfoldMaps(TextEditor::Range toTest) { + bool TextEditor::testfoldMaps(Range toTest) { bool result = true; for (auto test = toTest.getStart(); test <= toTest.getEnd(); test = nextCoordinate(test)) { auto data = test; @@ -414,7 +413,7 @@ namespace hex::ui { return result; } - Coordinates TextEditor::Lines::unfoldedToFoldedCoords(const Coordinates &coords) { + Coordinates Lines::unfoldedToFoldedCoords(const Coordinates &coords) { auto row = lineIndexToRow(coords.m_line); Coordinates result; if (row == -1 || !m_foldedLines.contains(row)) @@ -477,8 +476,8 @@ namespace hex::ui { } else { if (foundIndex == 0) { if (foldedLine.firstLineNeedsDelimiter()) { - auto line = m_unfoldedLines[foldedLine.m_full.m_start.m_line]; - if (coords > lineCoordinates(foldedLine.m_full.m_start.m_line, line.maxColumn())) + auto lineIndex = foldedLine.m_full.m_start.m_line; + if (coords > lineCoordinates(lineIndex, lineMaxColumn(lineIndex))) result.m_column = foldedLine.m_ellipsisIndices[0] - 1; else result.m_column = coords.m_column; @@ -494,7 +493,7 @@ namespace hex::ui { } } - Coordinates TextEditor::Lines::stringIndexCoords(i32 strIndex, const std::string &input) { + Coordinates Lines::stringIndexCoords(i32 strIndex, const std::string &input) { if (strIndex < 0 || strIndex > (i32) input.size()) return lineCoordinates( 0, 0); std::string str = input.substr(0, strIndex); From 6fec5338bd2b7e540caf75df9b39879f8fa17586 Mon Sep 17 00:00:00 2001 From: paxcut Date: Sat, 30 May 2026 22:46:49 -0700 Subject: [PATCH 2/3] Before using the interactive selection as a substitute of the state selection, make sure that the interactive selection is equal to the state selection. --- plugins/ui/source/ui/text_editor/editor.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/plugins/ui/source/ui/text_editor/editor.cpp b/plugins/ui/source/ui/text_editor/editor.cpp index c1e7aa29492b4..d0322865ae76b 100644 --- a/plugins/ui/source/ui/text_editor/editor.cpp +++ b/plugins/ui/source/ui/text_editor/editor.cpp @@ -630,6 +630,7 @@ namespace hex::ui { if (m_state.m_selection.m_end == m_state.m_selection.m_start) return; + m_interactiveSelection = m_state.m_selection; deleteRange(m_interactiveSelection); m_interactiveSelection.m_end = m_interactiveSelection.m_start; From cb9da58433577596fa850057f5b2192ae04c857f Mon Sep 17 00:00:00 2001 From: paxcut Date: Sat, 6 Jun 2026 04:24:49 -0700 Subject: [PATCH 3/3] fix: parser won't run again If you open a binary file and accept an auto-detected pattern then running_parsers is not incremented before creating the parser task so ot becomes max u32 and parser cannot be made to run again without quitting ImHex. The fix is to always increment it before the task is created and to not decrement it if it is zero when parser is done parsing. --- .../builtin/source/content/views/view_pattern_editor.cpp | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/plugins/builtin/source/content/views/view_pattern_editor.cpp b/plugins/builtin/source/content/views/view_pattern_editor.cpp index 0ed8301f4b629..c704044900063 100644 --- a/plugins/builtin/source/content/views/view_pattern_editor.cpp +++ b/plugins/builtin/source/content/views/view_pattern_editor.cpp @@ -1500,13 +1500,13 @@ namespace hex::plugin::builtin { } return false; }); + m_runningParsers += 1; TaskManager::createBackgroundTask("hex.builtin.task.parsing_pattern", [this, code = std::move(code), provider](auto &){ this->parsePattern(code, provider); if (m_runAutomatically) m_triggerAutoEvaluate = true; }); - m_runningParsers += 1; m_hasUnevaluatedChanges.get(provider) = false; } @@ -1526,8 +1526,8 @@ namespace hex::plugin::builtin { m_identifierHighlighter.get(provider).updateRequiredInputs(); if (restoreInterruptState) interrupt(); - TaskManager::createBackgroundTask("hex.builtin.task.highlighting_pattern", [this,provider](auto &) { m_identifierHighlighter.get(provider).highlightSourceCode(); }); m_runningHighlighters += 1; + TaskManager::createBackgroundTask("hex.builtin.task.highlighting_pattern", [this,provider](auto &) { m_identifierHighlighter.get(provider).highlightSourceCode(); }); } else if (m_changesWereColored && !m_allStepsCompleted) { m_identifierHighlighter.get(provider).setRequestedIdentifierColors(m_colorizeIdentifiers); m_textEditor.get(provider).getLines().setAllCodeFolds(); @@ -1712,6 +1712,7 @@ namespace hex::plugin::builtin { } return false; }); + m_runningParsers += 1; TaskManager::createBackgroundTask("hex.builtin.task.parsing_pattern", [this, code, provider](auto&) { this->parsePattern(code, provider); }); } } @@ -1755,7 +1756,8 @@ namespace hex::plugin::builtin { m_changesWereParsed = true; m_changesWereColored = false; m_allStepsCompleted = false; - m_runningParsers -= 1; + if (m_runningParsers != 0) + m_runningParsers -= 1; } void ViewPatternEditor::evaluatePattern(const std::string &code, prv::Provider *provider) {