mirror of https://github.com/WerWolv/ImHex
Various fixes for pattern editor (#2561)
- Fix for vertical scroll bar being too far to the left. - Fix constructor not initializing from const char pointer properly - maxcolumn not being set for console text lines causing crashes on empty pattern evaluation - A replacement using replace all is now undone in one step. - Find/replace no longer need to have enter or return key to accept text. You can use arrows or shortcuts. - More efficient search replace implementation with plans to add even faster. - Tooltips added to find/replace window - Providers now save both horizontal and vertical scroll positions when switching to another one and restore them when switching back. This is independent to the cursor position which is also saved. - Pattern editor no longer takes focus when changing providers via a tab click. This has the effect that menus won't change by just clicking on a tab. - Small fixes and code refactoring.
This commit is contained in:
parent
62732de227
commit
1676342e28
|
|
@ -153,10 +153,10 @@ namespace hex::plugin::builtin {
|
||||||
std::mutex m_logMutex;
|
std::mutex m_logMutex;
|
||||||
|
|
||||||
PerProvider<ui::TextEditor::Coordinates> m_cursorPosition;
|
PerProvider<ui::TextEditor::Coordinates> m_cursorPosition;
|
||||||
|
PerProvider<ImVec2> m_scroll;
|
||||||
|
PerProvider<ImVec2> m_consoleScroll;
|
||||||
|
|
||||||
PerProvider<ui::TextEditor::Coordinates> m_consoleCursorPosition;
|
PerProvider<ui::TextEditor::Coordinates> m_consoleCursorPosition;
|
||||||
PerProvider<bool> m_cursorNeedsUpdate;
|
|
||||||
PerProvider<bool> m_consoleCursorNeedsUpdate;
|
|
||||||
PerProvider<ui::TextEditor::Range> m_selection;
|
PerProvider<ui::TextEditor::Range> m_selection;
|
||||||
PerProvider<ui::TextEditor::Range> m_consoleSelection;
|
PerProvider<ui::TextEditor::Range> m_consoleSelection;
|
||||||
PerProvider<size_t> m_consoleLongestLineLength;
|
PerProvider<size_t> m_consoleLongestLineLength;
|
||||||
|
|
|
||||||
|
|
@ -1048,6 +1048,9 @@
|
||||||
"hex.builtin.view.pattern_data.virtual_files.no_virtual_files": "Visualize regions of data as a virtual folder structure by adding them using the hex::core::add_virtual_file function.",
|
"hex.builtin.view.pattern_data.virtual_files.no_virtual_files": "Visualize regions of data as a virtual folder structure by adding them using the hex::core::add_virtual_file function.",
|
||||||
"hex.builtin.view.pattern_editor.no_env_vars": "The content of Environment Variables created here can be accessed from Pattern scripts using the std::env function.",
|
"hex.builtin.view.pattern_editor.no_env_vars": "The content of Environment Variables created here can be accessed from Pattern scripts using the std::env function.",
|
||||||
"hex.builtin.view.pattern_editor.no_results": "no results",
|
"hex.builtin.view.pattern_editor.no_results": "no results",
|
||||||
|
"hex.builtin.view.pattern_editor.match_case_tooltip": "Match Case Alt-C",
|
||||||
|
"hex.builtin.view.pattern_editor.whole_word_tooltip": "Whole Word Alt-W",
|
||||||
|
"hex.builtin.view.pattern_editor.regex_tooltip": "Regex Alt-R",
|
||||||
"hex.builtin.view.pattern_editor.of": "of",
|
"hex.builtin.view.pattern_editor.of": "of",
|
||||||
"hex.builtin.view.pattern_editor.open_pattern": "Open pattern",
|
"hex.builtin.view.pattern_editor.open_pattern": "Open pattern",
|
||||||
"hex.builtin.view.pattern_editor.replace_hint": "Replace",
|
"hex.builtin.view.pattern_editor.replace_hint": "Replace",
|
||||||
|
|
|
||||||
|
|
@ -477,11 +477,6 @@ namespace hex::plugin::builtin {
|
||||||
m_textEditor.get(provider).selectWordUnderCursor();
|
m_textEditor.get(provider).selectWordUnderCursor();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_cursorNeedsUpdate.get(provider)) {
|
|
||||||
m_textEditor.get(provider).setFocusAtCoords(m_cursorPosition.get(provider));
|
|
||||||
m_cursorNeedsUpdate.get(provider) = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (auto editor = getEditorFromFocusedWindow(); editor != nullptr) {
|
if (auto editor = getEditorFromFocusedWindow(); editor != nullptr) {
|
||||||
setupFindReplace(editor);
|
setupFindReplace(editor);
|
||||||
setupGotoLine(editor);
|
setupGotoLine(editor);
|
||||||
|
|
@ -716,7 +711,7 @@ namespace hex::plugin::builtin {
|
||||||
|
|
||||||
ImGui::TableNextColumn();
|
ImGui::TableNextColumn();
|
||||||
|
|
||||||
static int findFlags = ImGuiInputTextFlags_EnterReturnsTrue;
|
static int findFlags = ImGuiInputTextFlags_None;
|
||||||
|
|
||||||
std::string hint = "hex.builtin.view.pattern_editor.find_hint"_lang.operator std::string();
|
std::string hint = "hex.builtin.view.pattern_editor.find_hint"_lang.operator std::string();
|
||||||
if (m_findHistorySize > 0) {
|
if (m_findHistorySize > 0) {
|
||||||
|
|
@ -724,6 +719,8 @@ namespace hex::plugin::builtin {
|
||||||
hint += ICON_BI_DATA_TRANSFER_BOTH;
|
hint += ICON_BI_DATA_TRANSFER_BOTH;
|
||||||
hint += "hex.builtin.view.pattern_editor.find_hint_history"_lang.operator std::string();
|
hint += "hex.builtin.view.pattern_editor.find_hint_history"_lang.operator std::string();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static bool enterPressedReplace = false;
|
||||||
static bool enterPressedFind = false;
|
static bool enterPressedFind = false;
|
||||||
ImGui::PushItemWidth(ImGui::GetFontSize() * 12);
|
ImGui::PushItemWidth(ImGui::GetFontSize() * 12);
|
||||||
if (ImGui::InputTextWithHint("###findInputTextWidget", hint.c_str(), findWord, findFlags) || enter ) {
|
if (ImGui::InputTextWithHint("###findInputTextWidget", hint.c_str(), findWord, findFlags) || enter ) {
|
||||||
|
|
@ -775,6 +772,12 @@ namespace hex::plugin::builtin {
|
||||||
updateCount = true;
|
updateCount = true;
|
||||||
requestFocusFind = true;
|
requestFocusFind = true;
|
||||||
}
|
}
|
||||||
|
if (ImGui::IsItemHovered()) {
|
||||||
|
if (ImGui::BeginTooltip()) {
|
||||||
|
ImGui::TextUnformatted("hex.builtin.view.pattern_editor.match_case_tooltip"_lang);
|
||||||
|
ImGui::EndTooltip();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
ImGui::SameLine();
|
ImGui::SameLine();
|
||||||
|
|
||||||
|
|
@ -791,7 +794,12 @@ namespace hex::plugin::builtin {
|
||||||
updateCount = true;
|
updateCount = true;
|
||||||
requestFocusFind = true;
|
requestFocusFind = true;
|
||||||
}
|
}
|
||||||
|
if (ImGui::IsItemHovered()) {
|
||||||
|
if (ImGui::BeginTooltip()) {
|
||||||
|
ImGui::TextUnformatted("hex.builtin.view.pattern_editor.whole_word_tooltip"_lang);
|
||||||
|
ImGui::EndTooltip();
|
||||||
|
}
|
||||||
|
}
|
||||||
ImGui::SameLine();
|
ImGui::SameLine();
|
||||||
|
|
||||||
bool useRegex = findReplaceHandler->getFindRegEx();
|
bool useRegex = findReplaceHandler->getFindRegEx();
|
||||||
|
|
@ -807,6 +815,13 @@ namespace hex::plugin::builtin {
|
||||||
updateCount = true;
|
updateCount = true;
|
||||||
requestFocusFind = true;
|
requestFocusFind = true;
|
||||||
}
|
}
|
||||||
|
if (ImGui::IsItemHovered()) {
|
||||||
|
if (ImGui::BeginTooltip()) {
|
||||||
|
ImGui::TextUnformatted("hex.builtin.view.pattern_editor.regex_tooltip"_lang);
|
||||||
|
ImGui::EndTooltip();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
static std::string counterString;
|
static std::string counterString;
|
||||||
|
|
||||||
|
|
@ -852,12 +867,15 @@ namespace hex::plugin::builtin {
|
||||||
if (ImGuiExt::IconButton(ICON_VS_ARROW_UP, ImVec4(1, 1, 1, 1)))
|
if (ImGuiExt::IconButton(ICON_VS_ARROW_UP, ImVec4(1, 1, 1, 1)))
|
||||||
upArrowFind = true;
|
upArrowFind = true;
|
||||||
|
|
||||||
|
static bool downArrowReplace = false;
|
||||||
|
static bool upArrowReplace = false;
|
||||||
|
static std::string replaceWord;
|
||||||
if (m_replaceMode) {
|
if (m_replaceMode) {
|
||||||
ImGui::TableNextRow();
|
ImGui::TableNextRow();
|
||||||
ImGui::TableNextColumn();
|
ImGui::TableNextColumn();
|
||||||
ImGui::TableNextColumn();
|
ImGui::TableNextColumn();
|
||||||
|
|
||||||
static int replaceFlags = ImGuiInputTextFlags_EnterReturnsTrue;
|
static int replaceFlags = ImGuiInputTextFlags_None;
|
||||||
|
|
||||||
hint = "hex.builtin.view.pattern_editor.replace_hint"_lang.operator std::string();
|
hint = "hex.builtin.view.pattern_editor.replace_hint"_lang.operator std::string();
|
||||||
if (m_replaceHistorySize > 0) {
|
if (m_replaceHistorySize > 0) {
|
||||||
|
|
@ -867,31 +885,13 @@ namespace hex::plugin::builtin {
|
||||||
}
|
}
|
||||||
|
|
||||||
ImGui::PushItemWidth(ImGui::GetFontSize() * 12);
|
ImGui::PushItemWidth(ImGui::GetFontSize() * 12);
|
||||||
static std::string replaceWord;
|
if (ImGui::InputTextWithHint("###replaceInputTextWidget", hint.c_str(), replaceWord, replaceFlags) || enter) {
|
||||||
static bool downArrowReplace = false;
|
if (enter)
|
||||||
static bool upArrowReplace = false;
|
enterPressedReplace = true;
|
||||||
if (ImGui::InputTextWithHint("###replaceInputTextWidget", hint.c_str(), replaceWord, replaceFlags) || downArrowReplace || upArrowReplace) {
|
|
||||||
findReplaceHandler->setReplaceWord(replaceWord);
|
|
||||||
historyInsert(m_replaceHistory, m_replaceHistorySize, m_replaceHistoryIndex, replaceWord);
|
|
||||||
|
|
||||||
bool textReplaced = findReplaceHandler->replace(textEditor, !shift && !upArrowReplace);
|
updateCount = true;
|
||||||
if (textReplaced) {
|
|
||||||
if (count > 0) {
|
|
||||||
if (position == count)
|
|
||||||
position -= 1;
|
|
||||||
count -= 1;
|
|
||||||
}
|
|
||||||
updateCount = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
downArrowReplace = false;
|
|
||||||
upArrowReplace = false;
|
|
||||||
|
|
||||||
if (enterPressedFind) {
|
|
||||||
enterPressedFind = false;
|
|
||||||
requestFocusFind = false;
|
|
||||||
}
|
|
||||||
requestFocusReplace = true;
|
requestFocusReplace = true;
|
||||||
|
findReplaceHandler->setReplaceWord(replaceWord);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (requestFocus || requestFocusReplace) {
|
if (requestFocus || requestFocusReplace) {
|
||||||
|
|
@ -947,6 +947,31 @@ namespace hex::plugin::builtin {
|
||||||
requestFocusFind = true;
|
requestFocusFind = true;
|
||||||
enterPressedFind = false;
|
enterPressedFind = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (downArrowReplace || upArrowReplace || enterPressedReplace) {
|
||||||
|
historyInsert(m_replaceHistory, m_replaceHistorySize, m_replaceHistoryIndex, replaceWord);
|
||||||
|
findReplaceHandler->m_undoBuffer.clear();
|
||||||
|
bool textReplaced = findReplaceHandler->replace(textEditor, !shift && !upArrowReplace);
|
||||||
|
textEditor->addUndo(findReplaceHandler->m_undoBuffer);
|
||||||
|
if (textReplaced) {
|
||||||
|
if (count > 0) {
|
||||||
|
if (position == count)
|
||||||
|
position -= 1;
|
||||||
|
count -= 1;
|
||||||
|
}
|
||||||
|
updateCount = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
downArrowReplace = false;
|
||||||
|
upArrowReplace = false;
|
||||||
|
|
||||||
|
if (enterPressedFind) {
|
||||||
|
enterPressedFind = false;
|
||||||
|
requestFocusFind = false;
|
||||||
|
}
|
||||||
|
requestFocusReplace = true;
|
||||||
|
enterPressedReplace = false;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// Escape key to close the popup
|
// Escape key to close the popup
|
||||||
if (ImGui::IsKeyPressed(ImGuiKey_Escape, false)) {
|
if (ImGui::IsKeyPressed(ImGuiKey_Escape, false)) {
|
||||||
|
|
@ -1045,10 +1070,6 @@ namespace hex::plugin::builtin {
|
||||||
m_consoleEditor.get(provider).clearRaiseContextMenu();
|
m_consoleEditor.get(provider).clearRaiseContextMenu();
|
||||||
}
|
}
|
||||||
|
|
||||||
if (m_consoleCursorNeedsUpdate.get(provider)) {
|
|
||||||
m_consoleEditor.get(provider).setFocusAtCoords(m_consoleCursorPosition.get(provider));
|
|
||||||
m_consoleCursorNeedsUpdate.get(provider) = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (m_consoleNeedsUpdate) {
|
if (m_consoleNeedsUpdate) {
|
||||||
std::scoped_lock lock(m_logMutex);
|
std::scoped_lock lock(m_logMutex);
|
||||||
|
|
@ -1847,31 +1868,30 @@ namespace hex::plugin::builtin {
|
||||||
EventProviderChanged::subscribe(this, [this](prv::Provider *oldProvider, prv::Provider *newProvider) {
|
EventProviderChanged::subscribe(this, [this](prv::Provider *oldProvider, prv::Provider *newProvider) {
|
||||||
if (oldProvider != nullptr) {
|
if (oldProvider != nullptr) {
|
||||||
m_sourceCode.get(oldProvider) = m_textEditor.get(oldProvider).getText();
|
m_sourceCode.get(oldProvider) = m_textEditor.get(oldProvider).getText();
|
||||||
|
m_scroll.get(oldProvider) = m_textEditor.get(oldProvider).getScroll();
|
||||||
m_cursorPosition.get(oldProvider) = m_textEditor.get(oldProvider).getCursorPosition();
|
m_cursorPosition.get(oldProvider) = m_textEditor.get(oldProvider).getCursorPosition();
|
||||||
m_selection.get(oldProvider) = m_textEditor.get(oldProvider).getSelection();
|
m_selection.get(oldProvider) = m_textEditor.get(oldProvider).getSelection();
|
||||||
|
m_breakpoints.get(oldProvider) = m_textEditor.get(oldProvider).getBreakpoints();
|
||||||
m_consoleCursorPosition.get(oldProvider) = m_consoleEditor.get(oldProvider).getCursorPosition();
|
m_consoleCursorPosition.get(oldProvider) = m_consoleEditor.get(oldProvider).getCursorPosition();
|
||||||
m_consoleSelection.get(oldProvider) = m_consoleEditor.get(oldProvider).getSelection();
|
m_consoleSelection.get(oldProvider) = m_consoleEditor.get(oldProvider).getSelection();
|
||||||
m_consoleLongestLineLength.get(oldProvider) = m_consoleEditor.get(oldProvider).getLongestLineLength();
|
m_consoleLongestLineLength.get(oldProvider) = m_consoleEditor.get(oldProvider).getLongestLineLength();
|
||||||
m_breakpoints.get(oldProvider) = m_textEditor.get(oldProvider).getBreakpoints();
|
m_consoleScroll.get(oldProvider) = m_consoleEditor.get(oldProvider).getScroll();
|
||||||
m_cursorNeedsUpdate.get(oldProvider) = false;
|
|
||||||
m_consoleCursorNeedsUpdate.get(oldProvider) = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (newProvider != nullptr) {
|
if (newProvider != nullptr) {
|
||||||
m_textEditor.get(newProvider).setText(wolv::util::preprocessText(m_sourceCode.get(newProvider)));
|
m_textEditor.get(newProvider).setText(wolv::util::preprocessText(m_sourceCode.get(newProvider)));
|
||||||
m_textEditor.get(newProvider).setCursorPosition(m_cursorPosition.get(newProvider));
|
m_textEditor.get(newProvider).setCursorPosition(m_cursorPosition.get(newProvider),false);
|
||||||
ui::TextEditor::Range selection = m_selection.get(newProvider);
|
m_textEditor.get(newProvider).setScroll(m_scroll.get(newProvider));
|
||||||
m_textEditor.get(newProvider).setSelection(selection);
|
m_textEditor.get(newProvider).setSelection(m_selection.get(newProvider));
|
||||||
m_textEditor.get(newProvider).setBreakpoints(m_breakpoints.get(newProvider));
|
m_textEditor.get(newProvider).setBreakpoints(m_breakpoints.get(newProvider));
|
||||||
|
m_textEditor.get(newProvider).setTextChanged(false);
|
||||||
|
m_hasUnevaluatedChanges.get(newProvider) = true;
|
||||||
m_consoleEditor.get(newProvider).setText(wolv::util::combineStrings(m_console.get(newProvider), "\n"));
|
m_consoleEditor.get(newProvider).setText(wolv::util::combineStrings(m_console.get(newProvider), "\n"));
|
||||||
m_consoleEditor.get(newProvider).setCursorPosition(m_consoleCursorPosition.get(newProvider));
|
m_consoleEditor.get(newProvider).setCursorPosition(m_consoleCursorPosition.get(newProvider));
|
||||||
m_consoleEditor.get(newProvider).setLongestLineLength(m_consoleLongestLineLength.get(newProvider));
|
m_consoleEditor.get(newProvider).setLongestLineLength(m_consoleLongestLineLength.get(newProvider));
|
||||||
selection = m_consoleSelection.get(newProvider);
|
m_consoleEditor.get(newProvider).setSelection(m_consoleSelection.get(newProvider));
|
||||||
m_consoleEditor.get(newProvider).setSelection(selection);
|
m_consoleEditor.get(newProvider).setScroll(m_consoleScroll.get(newProvider));
|
||||||
m_cursorNeedsUpdate.get(newProvider) = true;
|
|
||||||
m_consoleCursorNeedsUpdate.get(newProvider) = true;
|
|
||||||
m_textEditor.get(newProvider).setTextChanged(false);
|
|
||||||
m_hasUnevaluatedChanges.get(newProvider) = true;
|
|
||||||
}
|
}
|
||||||
m_textHighlighter.m_needsToUpdateColors = false;
|
m_textHighlighter.m_needsToUpdateColors = false;
|
||||||
|
|
||||||
|
|
@ -1970,7 +1990,7 @@ namespace hex::plugin::builtin {
|
||||||
ui::TextEditor::FindReplaceHandler *findReplaceHandler = editor->getFindReplaceHandler();
|
ui::TextEditor::FindReplaceHandler *findReplaceHandler = editor->getFindReplaceHandler();
|
||||||
findReplaceHandler->findMatch(editor, 1);
|
findReplaceHandler->findMatch(editor, 1);
|
||||||
} else {
|
} else {
|
||||||
m_textEditor->getFindReplaceHandler()->findMatch(&*m_textEditor, 1);
|
m_textEditor.get(ImHexApi::Provider::get()).getFindReplaceHandler()->findMatch(&m_textEditor.get(ImHexApi::Provider::get()), 1);
|
||||||
}
|
}
|
||||||
}, [this] {
|
}, [this] {
|
||||||
if (auto editor = getEditorFromFocusedWindow(); editor != nullptr) {
|
if (auto editor = getEditorFromFocusedWindow(); editor != nullptr) {
|
||||||
|
|
@ -1988,11 +2008,11 @@ namespace hex::plugin::builtin {
|
||||||
ui::TextEditor::FindReplaceHandler *findReplaceHandler = editor->getFindReplaceHandler();
|
ui::TextEditor::FindReplaceHandler *findReplaceHandler = editor->getFindReplaceHandler();
|
||||||
findReplaceHandler->findMatch(editor, -1);
|
findReplaceHandler->findMatch(editor, -1);
|
||||||
} else {
|
} else {
|
||||||
m_textEditor->getFindReplaceHandler()->findMatch(&*m_textEditor, -1);
|
m_textEditor.get(ImHexApi::Provider::get()).getFindReplaceHandler()->findMatch(&m_textEditor.get(ImHexApi::Provider::get()), -1);
|
||||||
}
|
}
|
||||||
}, [this] {
|
}, [this] {
|
||||||
if (auto editor = getEditorFromFocusedWindow(); editor != nullptr) {
|
if (auto editor = getEditorFromFocusedWindow(); editor != nullptr) {
|
||||||
return ImHexApi::Provider::isValid() && !m_textEditor->getFindReplaceHandler()->getFindWord().empty();
|
return ImHexApi::Provider::isValid() && !m_textEditor.get(ImHexApi::Provider::get()).getFindReplaceHandler()->getFindWord().empty();
|
||||||
} else {
|
} else {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
@ -2009,22 +2029,22 @@ namespace hex::plugin::builtin {
|
||||||
|
|
||||||
/* Replace Next */
|
/* Replace Next */
|
||||||
ContentRegistry::UserInterface::addMenuItem({ "hex.builtin.menu.file", "hex.builtin.view.pattern_editor.menu.replace_next" }, 1550, Shortcut::None, [this] {
|
ContentRegistry::UserInterface::addMenuItem({ "hex.builtin.menu.file", "hex.builtin.view.pattern_editor.menu.replace_next" }, 1550, Shortcut::None, [this] {
|
||||||
m_textEditor->getFindReplaceHandler()->replace(&*m_textEditor, true);
|
m_textEditor.get(ImHexApi::Provider::get()).getFindReplaceHandler()->replace(&m_textEditor.get(ImHexApi::Provider::get()), true);
|
||||||
}, [this] { return ImHexApi::Provider::isValid() && !m_textEditor->getFindReplaceHandler()->getReplaceWord().empty() && m_focusedSubWindowName.contains(TextEditorView); },
|
}, [this] { return ImHexApi::Provider::isValid() && !m_textEditor.get(ImHexApi::Provider::get()).getFindReplaceHandler()->getReplaceWord().empty() && m_focusedSubWindowName.contains(TextEditorView); },
|
||||||
[]{ return false; },
|
[]{ return false; },
|
||||||
this);
|
this);
|
||||||
|
|
||||||
/* Replace Previous */
|
/* Replace Previous */
|
||||||
ContentRegistry::UserInterface::addMenuItem({ "hex.builtin.menu.file", "hex.builtin.view.pattern_editor.menu.replace_previous" }, 1560, Shortcut::None, [this] {
|
ContentRegistry::UserInterface::addMenuItem({ "hex.builtin.menu.file", "hex.builtin.view.pattern_editor.menu.replace_previous" }, 1560, Shortcut::None, [this] {
|
||||||
m_textEditor->getFindReplaceHandler()->replace(&*m_textEditor, false);
|
m_textEditor.get(ImHexApi::Provider::get()).getFindReplaceHandler()->replace(&m_textEditor.get(ImHexApi::Provider::get()), false);
|
||||||
}, [this] { return ImHexApi::Provider::isValid() && !m_textEditor->getFindReplaceHandler()->getReplaceWord().empty() && m_focusedSubWindowName.contains(TextEditorView); },
|
}, [this] { return ImHexApi::Provider::isValid() && !m_textEditor.get(ImHexApi::Provider::get()).getFindReplaceHandler()->getReplaceWord().empty() && m_focusedSubWindowName.contains(TextEditorView); },
|
||||||
[]{ return false; },
|
[]{ return false; },
|
||||||
this);
|
this);
|
||||||
|
|
||||||
/* Replace All */
|
/* Replace All */
|
||||||
ContentRegistry::UserInterface::addMenuItem({ "hex.builtin.menu.file", "hex.builtin.view.pattern_editor.menu.replace_all" }, ICON_VS_REPLACE_ALL, 1570, Shortcut::None, [this] {
|
ContentRegistry::UserInterface::addMenuItem({ "hex.builtin.menu.file", "hex.builtin.view.pattern_editor.menu.replace_all" }, ICON_VS_REPLACE_ALL, 1570, Shortcut::None, [this] {
|
||||||
m_textEditor->getFindReplaceHandler()->replaceAll(&*m_textEditor);
|
m_textEditor.get(ImHexApi::Provider::get()).getFindReplaceHandler()->replaceAll(&m_textEditor.get(ImHexApi::Provider::get()));
|
||||||
}, [this] { return ImHexApi::Provider::isValid() && !m_textEditor->getFindReplaceHandler()->getReplaceWord().empty() && m_focusedSubWindowName.contains(TextEditorView); },
|
}, [this] { return ImHexApi::Provider::isValid() && !m_textEditor.get(ImHexApi::Provider::get()).getFindReplaceHandler()->getReplaceWord().empty() && m_focusedSubWindowName.contains(TextEditorView); },
|
||||||
this);
|
this);
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -2043,19 +2063,19 @@ namespace hex::plugin::builtin {
|
||||||
ContentRegistry::UserInterface::addMenuItem({ "hex.builtin.menu.file", "hex.builtin.menu.file.export", "hex.builtin.menu.file.export.pattern" }, ICON_VS_FILE_CODE, 7050, Shortcut::None, [this] {
|
ContentRegistry::UserInterface::addMenuItem({ "hex.builtin.menu.file", "hex.builtin.menu.file.export", "hex.builtin.menu.file.export.pattern" }, ICON_VS_FILE_CODE, 7050, Shortcut::None, [this] {
|
||||||
savePatternAsNewFile(false);
|
savePatternAsNewFile(false);
|
||||||
}, [this] {
|
}, [this] {
|
||||||
return ImHexApi::Provider::isValid() && !wolv::util::trim(m_textEditor->getText()).empty();
|
return ImHexApi::Provider::isValid() && !wolv::util::trim(m_textEditor.get(ImHexApi::Provider::get()).getText()).empty();
|
||||||
});
|
});
|
||||||
|
|
||||||
/* Undo */
|
/* Undo */
|
||||||
ContentRegistry::UserInterface::addMenuItem({ "hex.builtin.menu.edit", "hex.builtin.view.pattern_editor.menu.edit.undo" }, ICON_VS_DISCARD, 1250, AllowWhileTyping + CTRLCMD + Keys::Z, [this] {
|
ContentRegistry::UserInterface::addMenuItem({ "hex.builtin.menu.edit", "hex.builtin.view.pattern_editor.menu.edit.undo" }, ICON_VS_DISCARD, 1250, AllowWhileTyping + CTRLCMD + Keys::Z, [this] {
|
||||||
m_textEditor->undo();
|
m_textEditor.get(ImHexApi::Provider::get()).undo();
|
||||||
}, [this] { return ImHexApi::Provider::isValid() && m_textEditor->canUndo() && m_focusedSubWindowName.contains(TextEditorView); },
|
}, [this] { return ImHexApi::Provider::isValid() && m_textEditor.get(ImHexApi::Provider::get()).canUndo() && m_focusedSubWindowName.contains(TextEditorView); },
|
||||||
this);
|
this);
|
||||||
|
|
||||||
/* Redo */
|
/* Redo */
|
||||||
ContentRegistry::UserInterface::addMenuItem({ "hex.builtin.menu.edit", "hex.builtin.view.pattern_editor.menu.edit.redo" }, ICON_VS_REDO, 1275, AllowWhileTyping + CTRLCMD + Keys::Y, [this] {
|
ContentRegistry::UserInterface::addMenuItem({ "hex.builtin.menu.edit", "hex.builtin.view.pattern_editor.menu.edit.redo" }, ICON_VS_REDO, 1275, AllowWhileTyping + CTRLCMD + Keys::Y, [this] {
|
||||||
m_textEditor->redo();
|
m_textEditor.get(ImHexApi::Provider::get()).redo();
|
||||||
}, [this] { return ImHexApi::Provider::isValid() && m_textEditor->canRedo() && m_focusedSubWindowName.contains(TextEditorView); },
|
}, [this] { return ImHexApi::Provider::isValid() && m_textEditor.get(ImHexApi::Provider::get()).canRedo() && m_focusedSubWindowName.contains(TextEditorView); },
|
||||||
this);
|
this);
|
||||||
|
|
||||||
ContentRegistry::UserInterface::addMenuItemSeparator({ "hex.builtin.menu.edit" }, 1280, this);
|
ContentRegistry::UserInterface::addMenuItemSeparator({ "hex.builtin.menu.edit" }, 1280, this);
|
||||||
|
|
@ -2063,8 +2083,8 @@ namespace hex::plugin::builtin {
|
||||||
|
|
||||||
/* Cut */
|
/* Cut */
|
||||||
ContentRegistry::UserInterface::addMenuItem({ "hex.builtin.menu.edit", "hex.builtin.view.pattern_editor.menu.edit.cut" }, ICON_VS_COMBINE, 1300, AllowWhileTyping + CTRLCMD + Keys::X, [this] {
|
ContentRegistry::UserInterface::addMenuItem({ "hex.builtin.menu.edit", "hex.builtin.view.pattern_editor.menu.edit.cut" }, ICON_VS_COMBINE, 1300, AllowWhileTyping + CTRLCMD + Keys::X, [this] {
|
||||||
m_textEditor->cut();
|
m_textEditor.get(ImHexApi::Provider::get()).cut();
|
||||||
}, [this] { return ImHexApi::Provider::isValid() && m_textEditor->hasSelection() && m_focusedSubWindowName.contains(TextEditorView); },
|
}, [this] { return ImHexApi::Provider::isValid() && m_textEditor.get(ImHexApi::Provider::get()).hasSelection() && m_focusedSubWindowName.contains(TextEditorView); },
|
||||||
this);
|
this);
|
||||||
|
|
||||||
/* Copy */
|
/* Copy */
|
||||||
|
|
@ -2072,7 +2092,7 @@ namespace hex::plugin::builtin {
|
||||||
if (auto editor = getEditorFromFocusedWindow(); editor != nullptr) {
|
if (auto editor = getEditorFromFocusedWindow(); editor != nullptr) {
|
||||||
editor->copy();
|
editor->copy();
|
||||||
} else {
|
} else {
|
||||||
m_textEditor->copy();
|
m_textEditor.get(ImHexApi::Provider::get()).copy();
|
||||||
}
|
}
|
||||||
}, [this] {
|
}, [this] {
|
||||||
if (auto editor = getEditorFromFocusedWindow(); editor != nullptr)
|
if (auto editor = getEditorFromFocusedWindow(); editor != nullptr)
|
||||||
|
|
@ -2084,7 +2104,7 @@ namespace hex::plugin::builtin {
|
||||||
|
|
||||||
/* Paste */
|
/* Paste */
|
||||||
ContentRegistry::UserInterface::addMenuItem({ "hex.builtin.menu.edit", "hex.builtin.view.pattern_editor.menu.edit.paste" }, ICON_VS_OUTPUT, 1500, AllowWhileTyping + CTRLCMD + Keys::V, [this] {
|
ContentRegistry::UserInterface::addMenuItem({ "hex.builtin.menu.edit", "hex.builtin.view.pattern_editor.menu.edit.paste" }, ICON_VS_OUTPUT, 1500, AllowWhileTyping + CTRLCMD + Keys::V, [this] {
|
||||||
m_textEditor->paste();
|
m_textEditor.get(ImHexApi::Provider::get()).paste();
|
||||||
}, [this] { return m_focusedSubWindowName.contains(TextEditorView); },
|
}, [this] { return m_focusedSubWindowName.contains(TextEditorView); },
|
||||||
this);
|
this);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -114,23 +114,23 @@ namespace hex::ui {
|
||||||
Coordinates m_cursorPosition;
|
Coordinates m_cursorPosition;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class UndoRecord;
|
||||||
|
class UndoAction;
|
||||||
|
using UndoBuffer = std::vector<UndoAction>;
|
||||||
|
using UndoRecords = std::vector<UndoRecord>;
|
||||||
|
|
||||||
class FindReplaceHandler {
|
class FindReplaceHandler {
|
||||||
public:
|
public:
|
||||||
FindReplaceHandler();
|
FindReplaceHandler();
|
||||||
using Matches = std::vector<EditorState>;
|
using Matches = std::vector<EditorState>;
|
||||||
Matches &getMatches() { return m_matches; }
|
Matches &getMatches() { return m_matches; }
|
||||||
bool findNext(TextEditor *editor);
|
bool findNext(TextEditor *editor, u64 &byteIndex);
|
||||||
u32 findMatch(TextEditor *editor, i32 index);
|
u32 findMatch(TextEditor *editor, i32 index);
|
||||||
bool replace(TextEditor *editor, bool right);
|
bool replace(TextEditor *editor, bool right);
|
||||||
bool replaceAll(TextEditor *editor);
|
bool replaceAll(TextEditor *editor);
|
||||||
std::string &getFindWord() { return m_findWord; }
|
std::string &getFindWord() { return m_findWord; }
|
||||||
|
|
||||||
void setFindWord(TextEditor *editor, const std::string &findWord) {
|
void setFindWord(TextEditor *editor, const std::string &findWord);
|
||||||
if (findWord != m_findWord) {
|
|
||||||
findAllMatches(editor, findWord);
|
|
||||||
m_findWord = findWord;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string &getReplaceWord() { return m_replaceWord; }
|
std::string &getReplaceWord() { return m_replaceWord; }
|
||||||
void setReplaceWord(const std::string &replaceWord) { m_replaceWord = replaceWord; }
|
void setReplaceWord(const std::string &replaceWord) { m_replaceWord = replaceWord; }
|
||||||
|
|
@ -139,37 +139,16 @@ namespace hex::ui {
|
||||||
u32 findPosition(TextEditor *editor, Coordinates pos, bool isNext);
|
u32 findPosition(TextEditor *editor, Coordinates pos, bool isNext);
|
||||||
bool getMatchCase() const { return m_matchCase; }
|
bool getMatchCase() const { return m_matchCase; }
|
||||||
|
|
||||||
void setMatchCase(TextEditor *editor, bool matchCase) {
|
void setMatchCase(TextEditor *editor, bool matchCase);
|
||||||
if (matchCase != m_matchCase) {
|
|
||||||
m_matchCase = matchCase;
|
|
||||||
m_optionsChanged = true;
|
|
||||||
findAllMatches(editor, m_findWord);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool getWholeWord() const { return m_wholeWord; }
|
bool getWholeWord() const { return m_wholeWord; }
|
||||||
void setWholeWord(TextEditor *editor, bool wholeWord) {
|
void setWholeWord(TextEditor *editor, bool wholeWord);
|
||||||
if (wholeWord != m_wholeWord) {
|
|
||||||
m_wholeWord = wholeWord;
|
|
||||||
m_optionsChanged = true;
|
|
||||||
findAllMatches(editor, m_findWord);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool getFindRegEx() const { return m_findRegEx; }
|
bool getFindRegEx() const { return m_findRegEx; }
|
||||||
void setFindRegEx(TextEditor *editor, bool findRegEx) {
|
void setFindRegEx(TextEditor *editor, bool findRegEx);
|
||||||
if (findRegEx != m_findRegEx) {
|
|
||||||
m_findRegEx = findRegEx;
|
|
||||||
m_optionsChanged = true;
|
|
||||||
findAllMatches(editor, m_findWord);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void resetMatches() {
|
|
||||||
m_matches.clear();
|
|
||||||
m_findWord = "";
|
|
||||||
}
|
|
||||||
|
|
||||||
|
void resetMatches();
|
||||||
|
UndoRecords m_undoBuffer;
|
||||||
private:
|
private:
|
||||||
std::string m_findWord;
|
std::string m_findWord;
|
||||||
std::string m_replaceWord;
|
std::string m_replaceWord;
|
||||||
|
|
@ -299,7 +278,7 @@ namespace hex::ui {
|
||||||
enum class LinePart { Chars, Utf8, Colors, Flags };
|
enum class LinePart { Chars, Utf8, Colors, Flags };
|
||||||
|
|
||||||
Line() : m_chars(""), m_colors(""), m_flags(""), m_colorized(false), m_lineMaxColumn(-1) {}
|
Line() : m_chars(""), m_colors(""), m_flags(""), m_colorized(false), m_lineMaxColumn(-1) {}
|
||||||
explicit Line(const char *line) { Line(std::string(line)); }
|
explicit Line(const char *line) : Line(std::string(line)) {}
|
||||||
explicit Line(const std::string &line) : m_chars(line), m_colors(std::string(line.size(), 0x00)), m_flags(std::string(line.size(), 0x00)), m_colorized(false), m_lineMaxColumn(maxColumn()) {}
|
explicit Line(const std::string &line) : m_chars(line), m_colors(std::string(line.size(), 0x00)), m_flags(std::string(line.size(), 0x00)), m_colorized(false), m_lineMaxColumn(maxColumn()) {}
|
||||||
Line(const Line &line) : m_chars(std::string(line.m_chars)), m_colors(std::string(line.m_colors)), m_flags(std::string(line.m_flags)), m_colorized(line.m_colorized), m_lineMaxColumn(line.m_lineMaxColumn) {}
|
Line(const Line &line) : m_chars(std::string(line.m_chars)), m_colors(std::string(line.m_colors)), m_flags(std::string(line.m_flags)), m_colorized(line.m_colorized), m_lineMaxColumn(line.m_lineMaxColumn) {}
|
||||||
Line(Line &&line) noexcept : m_chars(std::move(line.m_chars)), m_colors(std::move(line.m_colors)), m_flags(std::move(line.m_flags)), m_colorized(line.m_colorized), m_lineMaxColumn(line.m_lineMaxColumn) {}
|
Line(Line &&line) noexcept : m_chars(std::move(line.m_chars)), m_colors(std::move(line.m_colors)), m_flags(std::move(line.m_flags)), m_colorized(line.m_colorized), m_lineMaxColumn(line.m_lineMaxColumn) {}
|
||||||
|
|
@ -400,11 +379,11 @@ namespace hex::ui {
|
||||||
UndoRecord() {}
|
UndoRecord() {}
|
||||||
~UndoRecord() {}
|
~UndoRecord() {}
|
||||||
UndoRecord( const std::string &added,
|
UndoRecord( const std::string &added,
|
||||||
const TextEditor::Range addedRange,
|
const Range addedRange,
|
||||||
const std::string &removed,
|
const std::string &removed,
|
||||||
const TextEditor::Range removedRange,
|
const Range removedRange,
|
||||||
TextEditor::EditorState &before,
|
EditorState &before,
|
||||||
TextEditor::EditorState &after);
|
EditorState &after);
|
||||||
|
|
||||||
void undo(TextEditor *editor);
|
void undo(TextEditor *editor);
|
||||||
void redo(TextEditor *editor);
|
void redo(TextEditor *editor);
|
||||||
|
|
@ -417,7 +396,18 @@ namespace hex::ui {
|
||||||
EditorState m_after;
|
EditorState m_after;
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef std::vector<UndoRecord> UndoBuffer;
|
class UndoAction {
|
||||||
|
public:
|
||||||
|
UndoAction() {}
|
||||||
|
~UndoAction() {}
|
||||||
|
explicit UndoAction(const UndoRecords &records) : m_records(records) {}
|
||||||
|
void undo(TextEditor *editor);
|
||||||
|
void redo(TextEditor *editor);
|
||||||
|
private:
|
||||||
|
UndoRecords m_records;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
struct MatchedBracket {
|
struct MatchedBracket {
|
||||||
bool m_active = false;
|
bool m_active = false;
|
||||||
|
|
@ -511,8 +501,8 @@ namespace hex::ui {
|
||||||
void backspace();
|
void backspace();
|
||||||
bool canUndo();
|
bool canUndo();
|
||||||
bool canRedo() const;
|
bool canRedo() const;
|
||||||
void undo(i32 steps = 1);
|
void undo();
|
||||||
void redo(i32 steps = 1);
|
void redo();
|
||||||
void copy();
|
void copy();
|
||||||
void cut();
|
void cut();
|
||||||
void paste();
|
void paste();
|
||||||
|
|
@ -559,8 +549,10 @@ namespace hex::ui {
|
||||||
void moveEnd(bool select = false);
|
void moveEnd(bool select = false);
|
||||||
void moveToMatchedBracket(bool select = false);
|
void moveToMatchedBracket(bool select = false);
|
||||||
void setScrollY();
|
void setScrollY();
|
||||||
|
void setScroll(ImVec2 scroll);
|
||||||
|
ImVec2 getScroll() const { return m_scroll; }
|
||||||
Coordinates getCursorPosition() { return setCoordinates(m_state.m_cursorPosition); }
|
Coordinates getCursorPosition() { return setCoordinates(m_state.m_cursorPosition); }
|
||||||
void setCursorPosition(const Coordinates &position);
|
void setCursorPosition(const Coordinates &position, bool scrollToCursor = true);
|
||||||
void setCursorPosition();
|
void setCursorPosition();
|
||||||
private:
|
private:
|
||||||
Coordinates setCoordinates(const Coordinates &value);
|
Coordinates setCoordinates(const Coordinates &value);
|
||||||
|
|
@ -591,8 +583,8 @@ namespace hex::ui {
|
||||||
void clearRaiseContextMenu() { m_raiseContextMenu = false; }
|
void clearRaiseContextMenu() { m_raiseContextMenu = false; }
|
||||||
TextEditor *getSourceCodeEditor();
|
TextEditor *getSourceCodeEditor();
|
||||||
bool isEmpty() const;
|
bool isEmpty() const;
|
||||||
|
void addUndo(UndoRecords &value);
|
||||||
private:
|
private:
|
||||||
void addUndo(UndoRecord &value);
|
|
||||||
TextEditor::PaletteIndex getColorIndexFromFlags(Line::Flags flags);
|
TextEditor::PaletteIndex getColorIndexFromFlags(Line::Flags flags);
|
||||||
void handleKeyboardInputs();
|
void handleKeyboardInputs();
|
||||||
void handleMouseInputs();
|
void handleMouseInputs();
|
||||||
|
|
@ -662,7 +654,9 @@ namespace hex::ui {
|
||||||
std::vector<std::string> m_defines;
|
std::vector<std::string> m_defines;
|
||||||
TextEditor *m_sourceCodeEditor = nullptr;
|
TextEditor *m_sourceCodeEditor = nullptr;
|
||||||
float m_shiftedScrollY = 0;
|
float m_shiftedScrollY = 0;
|
||||||
|
ImVec2 m_scroll=ImVec2(0, 0);
|
||||||
float m_scrollYIncrement = 0.0F;
|
float m_scrollYIncrement = 0.0F;
|
||||||
|
bool m_setScroll = false;
|
||||||
bool m_setScrollY = false;
|
bool m_setScrollY = false;
|
||||||
float m_numberOfLinesDisplayed = 0;
|
float m_numberOfLinesDisplayed = 0;
|
||||||
float m_lastClick = -1.0F;
|
float m_lastClick = -1.0F;
|
||||||
|
|
|
||||||
|
|
@ -80,9 +80,14 @@ namespace hex::ui {
|
||||||
m_lines[0].m_chars = text;
|
m_lines[0].m_chars = text;
|
||||||
m_lines[0].m_colors = std::string(text.size(), 0);
|
m_lines[0].m_colors = std::string(text.size(), 0);
|
||||||
m_lines[0].m_flags = std::string(text.size(), 0);
|
m_lines[0].m_flags = std::string(text.size(), 0);
|
||||||
} else
|
m_lines[0].m_lineMaxColumn = -1;
|
||||||
|
m_lines[0].m_lineMaxColumn = m_lines[0].maxColumn();
|
||||||
|
} else {
|
||||||
m_lines.push_back(Line(text));
|
m_lines.push_back(Line(text));
|
||||||
|
auto &line = m_lines.back();
|
||||||
|
line.m_lineMaxColumn = -1;
|
||||||
|
line.m_lineMaxColumn = line.maxColumn();
|
||||||
|
}
|
||||||
setCursorPosition(setCoordinates((i32) m_lines.size() - 1, 0));
|
setCursorPosition(setCoordinates((i32) m_lines.size() - 1, 0));
|
||||||
m_lines.back().m_colorized = false;
|
m_lines.back().m_colorized = false;
|
||||||
ensureCursorVisible();
|
ensureCursorVisible();
|
||||||
|
|
@ -129,23 +134,26 @@ namespace hex::ui {
|
||||||
}
|
}
|
||||||
|
|
||||||
void TextEditor::removeLine(i32 lineStart, i32 lineEnd) {
|
void TextEditor::removeLine(i32 lineStart, i32 lineEnd) {
|
||||||
|
ErrorMarkers errorMarkers;
|
||||||
|
for (auto &errorMarker : m_errorMarkers) {
|
||||||
|
if (errorMarker.first.m_line <= lineStart || errorMarker.first.m_line > lineEnd + 1) {
|
||||||
|
if (errorMarker.first.m_line >= lineEnd + 1) {
|
||||||
|
auto newRow = errorMarker.first.m_line - (lineEnd - lineStart + 1);
|
||||||
|
auto newCoord = setCoordinates(newRow, errorMarker.first.m_column);
|
||||||
|
errorMarkers.insert(ErrorMarkers::value_type(newCoord, errorMarker.second));
|
||||||
|
} else
|
||||||
|
errorMarkers.insert(errorMarker);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
m_errorMarkers = std::move(errorMarkers);
|
||||||
|
|
||||||
ErrorMarkers errorMarker;
|
|
||||||
u32 uLineStart = static_cast<u32>(lineStart);
|
u32 uLineStart = static_cast<u32>(lineStart);
|
||||||
u32 uLineEnd = static_cast<u32>(lineEnd);
|
u32 uLineEnd = static_cast<u32>(lineEnd);
|
||||||
for (auto &i: m_errorMarkers) {
|
|
||||||
ErrorMarkers::value_type e(i.first.m_line >= lineStart ? setCoordinates(i.first.m_line - 1, i.first.m_column) : i.first, i.second);
|
|
||||||
if (e.first.m_line >= lineStart && e.first.m_line <= lineEnd)
|
|
||||||
continue;
|
|
||||||
errorMarker.insert(e);
|
|
||||||
}
|
|
||||||
m_errorMarkers = std::move(errorMarker);
|
|
||||||
|
|
||||||
Breakpoints breakpoints;
|
Breakpoints breakpoints;
|
||||||
for (auto breakpoint: m_breakpoints) {
|
for (auto breakpoint : m_breakpoints) {
|
||||||
if (breakpoint <= uLineStart || breakpoint >= uLineEnd) {
|
if (breakpoint <= uLineStart || breakpoint > uLineEnd + 1) {
|
||||||
if (breakpoint >= uLineEnd) {
|
if (breakpoint > uLineEnd + 1) {
|
||||||
breakpoints.insert(breakpoint - 1);
|
breakpoints.insert(breakpoint - (uLineEnd - uLineStart + 1));
|
||||||
m_breakPointsChanged = true;
|
m_breakPointsChanged = true;
|
||||||
} else
|
} else
|
||||||
breakpoints.insert(breakpoint);
|
breakpoints.insert(breakpoint);
|
||||||
|
|
@ -190,10 +198,18 @@ namespace hex::ui {
|
||||||
TextEditor::Line &result = *m_lines.insert(m_lines.begin() + index, newLine);
|
TextEditor::Line &result = *m_lines.insert(m_lines.begin() + index, newLine);
|
||||||
result.m_colorized = false;
|
result.m_colorized = false;
|
||||||
|
|
||||||
ErrorMarkers errorMarker;
|
ErrorMarkers errorMarkers;
|
||||||
for (auto &i: m_errorMarkers)
|
bool errorMarkerChanged = false;
|
||||||
errorMarker.insert(ErrorMarkers::value_type(i.first.m_line >= index ? setCoordinates(i.first.m_line + 1, i.first.m_column) : i.first, i.second));
|
for (auto &errorMarker : m_errorMarkers) {
|
||||||
m_errorMarkers = std::move(errorMarker);
|
if (errorMarker.first.m_line > index) {
|
||||||
|
auto newCoord = setCoordinates(errorMarker.first.m_line + 1, errorMarker.first.m_column);
|
||||||
|
errorMarkers.insert(ErrorMarkers::value_type(newCoord, errorMarker.second));
|
||||||
|
errorMarkerChanged = true;
|
||||||
|
} else
|
||||||
|
errorMarkers.insert(errorMarker);
|
||||||
|
}
|
||||||
|
if (errorMarkerChanged)
|
||||||
|
m_errorMarkers = std::move(errorMarkers);
|
||||||
|
|
||||||
Breakpoints breakpoints;
|
Breakpoints breakpoints;
|
||||||
for (auto breakpoint: m_breakpoints) {
|
for (auto breakpoint: m_breakpoints) {
|
||||||
|
|
@ -231,6 +247,8 @@ namespace hex::ui {
|
||||||
for (auto line: vectorString) {
|
for (auto line: vectorString) {
|
||||||
m_lines[i].setLine(line);
|
m_lines[i].setLine(line);
|
||||||
m_lines[i].m_colorized = false;
|
m_lines[i].m_colorized = false;
|
||||||
|
m_lines[i].m_lineMaxColumn = -1;
|
||||||
|
m_lines[i].m_lineMaxColumn = m_lines[i].maxColumn();
|
||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -245,8 +263,9 @@ namespace hex::ui {
|
||||||
m_scrollToTop = true;
|
m_scrollToTop = true;
|
||||||
if (!m_readOnly && undo) {
|
if (!m_readOnly && undo) {
|
||||||
u.m_after = m_state;
|
u.m_after = m_state;
|
||||||
|
UndoRecords v;
|
||||||
addUndo(u);
|
v.push_back(u);
|
||||||
|
addUndo(v);
|
||||||
}
|
}
|
||||||
|
|
||||||
colorize();
|
colorize();
|
||||||
|
|
@ -325,7 +344,9 @@ namespace hex::ui {
|
||||||
u.m_after = m_state;
|
u.m_after = m_state;
|
||||||
|
|
||||||
m_state.m_selection = Range(start, end);
|
m_state.m_selection = Range(start, end);
|
||||||
addUndo(u);
|
std::vector<UndoRecord> v;
|
||||||
|
v.push_back(u);
|
||||||
|
addUndo(v);
|
||||||
|
|
||||||
m_textChanged = true;
|
m_textChanged = true;
|
||||||
|
|
||||||
|
|
@ -464,7 +485,9 @@ namespace hex::ui {
|
||||||
u.m_after = m_state;
|
u.m_after = m_state;
|
||||||
m_textChanged = true;
|
m_textChanged = true;
|
||||||
|
|
||||||
addUndo(u);
|
UndoRecords v;
|
||||||
|
v.push_back(u);
|
||||||
|
addUndo(v);
|
||||||
colorize();
|
colorize();
|
||||||
refreshSearchResults();
|
refreshSearchResults();
|
||||||
ensureCursorVisible();
|
ensureCursorVisible();
|
||||||
|
|
@ -558,7 +581,9 @@ namespace hex::ui {
|
||||||
}
|
}
|
||||||
|
|
||||||
u.m_after = m_state;
|
u.m_after = m_state;
|
||||||
addUndo(u);
|
UndoRecords v;
|
||||||
|
v.push_back(u);
|
||||||
|
addUndo(v);
|
||||||
refreshSearchResults();
|
refreshSearchResults();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -641,7 +666,9 @@ namespace hex::ui {
|
||||||
}
|
}
|
||||||
|
|
||||||
u.m_after = m_state;
|
u.m_after = m_state;
|
||||||
addUndo(u);
|
UndoRecords v;
|
||||||
|
v.push_back(u);
|
||||||
|
addUndo(v);
|
||||||
refreshSearchResults();
|
refreshSearchResults();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -677,7 +704,9 @@ namespace hex::ui {
|
||||||
deleteSelection();
|
deleteSelection();
|
||||||
|
|
||||||
u.m_after = m_state;
|
u.m_after = m_state;
|
||||||
addUndo(u);
|
std::vector<UndoRecord> v;
|
||||||
|
v.push_back(u);
|
||||||
|
addUndo(v);
|
||||||
}
|
}
|
||||||
refreshSearchResults();
|
refreshSearchResults();
|
||||||
}
|
}
|
||||||
|
|
@ -701,7 +730,9 @@ namespace hex::ui {
|
||||||
|
|
||||||
u.m_addedRange.m_end = setCoordinates(m_state.m_cursorPosition);
|
u.m_addedRange.m_end = setCoordinates(m_state.m_cursorPosition);
|
||||||
u.m_after = m_state;
|
u.m_after = m_state;
|
||||||
addUndo(u);
|
UndoRecords v;
|
||||||
|
v.push_back(u);
|
||||||
|
addUndo(v);
|
||||||
}
|
}
|
||||||
refreshSearchResults();
|
refreshSearchResults();
|
||||||
}
|
}
|
||||||
|
|
@ -731,21 +762,26 @@ namespace hex::ui {
|
||||||
return !m_readOnly && m_undoIndex < (i32) m_undoBuffer.size();
|
return !m_readOnly && m_undoIndex < (i32) m_undoBuffer.size();
|
||||||
}
|
}
|
||||||
|
|
||||||
void TextEditor::undo(i32 steps) {
|
void TextEditor::undo() {
|
||||||
while (canUndo() && steps-- > 0)
|
if (canUndo()) {
|
||||||
m_undoBuffer[--m_undoIndex].undo(this);
|
m_undoIndex--;
|
||||||
|
m_undoBuffer[m_undoIndex].undo(this);
|
||||||
|
}
|
||||||
refreshSearchResults();
|
refreshSearchResults();
|
||||||
}
|
}
|
||||||
|
|
||||||
void TextEditor::redo(i32 steps) {
|
void TextEditor::redo() {
|
||||||
while (canRedo() && steps-- > 0)
|
if (canRedo()) {
|
||||||
m_undoBuffer[m_undoIndex++].redo(this);
|
m_undoBuffer[m_undoIndex].redo(this);
|
||||||
|
m_undoIndex++;
|
||||||
|
}
|
||||||
refreshSearchResults();
|
refreshSearchResults();
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string TextEditor::getText() {
|
std::string TextEditor::getText() {
|
||||||
auto start = setCoordinates(0, 0);
|
auto start = setCoordinates(0, 0);
|
||||||
auto end = setCoordinates(-1, -1);
|
auto size = m_lines.size();
|
||||||
|
auto end = setCoordinates(-1, m_lines[size - 1].m_lineMaxColumn);
|
||||||
if (start == Invalid || end == Invalid)
|
if (start == Invalid || end == Invalid)
|
||||||
return "";
|
return "";
|
||||||
return getText(Range(start, end));
|
return getText(Range(start, end));
|
||||||
|
|
@ -778,11 +814,11 @@ namespace hex::ui {
|
||||||
|
|
||||||
TextEditor::UndoRecord::UndoRecord(
|
TextEditor::UndoRecord::UndoRecord(
|
||||||
const std::string &added,
|
const std::string &added,
|
||||||
const TextEditor::Range addedSelection,
|
const TextEditor::Range addedRange,
|
||||||
const std::string &removed,
|
const std::string &removed,
|
||||||
const TextEditor::Range removedSelection,
|
const TextEditor::Range removedRange,
|
||||||
TextEditor::EditorState &before,
|
TextEditor::EditorState &before,
|
||||||
TextEditor::EditorState &after) : m_added(added), m_addedRange(addedSelection), m_removed(removed), m_removedRange(removedSelection), m_before(before), m_after(after) {}
|
TextEditor::EditorState &after) : m_added(added), m_addedRange(addedRange), m_removed(removed), m_removedRange(removedRange), m_before(before), m_after(after) {}
|
||||||
|
|
||||||
void TextEditor::UndoRecord::undo(TextEditor *editor) {
|
void TextEditor::UndoRecord::undo(TextEditor *editor) {
|
||||||
if (!m_added.empty()) {
|
if (!m_added.empty()) {
|
||||||
|
|
@ -814,7 +850,16 @@ namespace hex::ui {
|
||||||
|
|
||||||
editor->m_state = m_after;
|
editor->m_state = m_after;
|
||||||
editor->ensureCursorVisible();
|
editor->ensureCursorVisible();
|
||||||
|
}
|
||||||
|
|
||||||
|
void TextEditor::UndoAction::undo(TextEditor *editor) {
|
||||||
|
for (i32 i = (i32) m_records.size() - 1; i >= 0; i--)
|
||||||
|
m_records.at(i).undo(editor);
|
||||||
|
}
|
||||||
|
|
||||||
|
void TextEditor::UndoAction::redo(TextEditor *editor) {
|
||||||
|
for (i32 i = 0; i < (i32) m_records.size(); i++)
|
||||||
|
m_records.at(i).redo(editor);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
@ -19,7 +19,7 @@ namespace hex::ui {
|
||||||
|
|
||||||
void TextEditor::jumpToCoords(const Coordinates &coords) {
|
void TextEditor::jumpToCoords(const Coordinates &coords) {
|
||||||
setSelection(Range(coords, coords));
|
setSelection(Range(coords, coords));
|
||||||
setCursorPosition(coords);
|
setCursorPosition(coords, true);
|
||||||
ensureCursorVisible();
|
ensureCursorVisible();
|
||||||
|
|
||||||
setFocusAtCoords(coords, true);
|
setFocusAtCoords(coords, true);
|
||||||
|
|
@ -203,7 +203,7 @@ namespace hex::ui {
|
||||||
void TextEditor::moveTop(bool select) {
|
void TextEditor::moveTop(bool select) {
|
||||||
resetCursorBlinkTime();
|
resetCursorBlinkTime();
|
||||||
auto oldPos = m_state.m_cursorPosition;
|
auto oldPos = m_state.m_cursorPosition;
|
||||||
setCursorPosition(setCoordinates(0, 0));
|
setCursorPosition(setCoordinates(0, 0), false);
|
||||||
|
|
||||||
if (m_state.m_cursorPosition != oldPos) {
|
if (m_state.m_cursorPosition != oldPos) {
|
||||||
if (select) {
|
if (select) {
|
||||||
|
|
@ -218,7 +218,7 @@ namespace hex::ui {
|
||||||
resetCursorBlinkTime();
|
resetCursorBlinkTime();
|
||||||
auto oldPos = getCursorPosition();
|
auto oldPos = getCursorPosition();
|
||||||
auto newPos = setCoordinates(-1, -1);
|
auto newPos = setCoordinates(-1, -1);
|
||||||
setCursorPosition(newPos);
|
setCursorPosition(newPos, false);
|
||||||
if (select) {
|
if (select) {
|
||||||
m_interactiveSelection = Range(oldPos, newPos);
|
m_interactiveSelection = Range(oldPos, newPos);
|
||||||
} else
|
} else
|
||||||
|
|
@ -315,10 +315,33 @@ namespace hex::ui {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void TextEditor::setCursorPosition(const Coordinates &position) {
|
void TextEditor::setScroll(ImVec2 scroll) {
|
||||||
|
if (!m_withinRender) {
|
||||||
|
m_scroll = scroll;
|
||||||
|
m_setScroll = true;
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
m_setScroll = false;
|
||||||
|
ImGui::SetScrollX(scroll.x);
|
||||||
|
ImGui::SetScrollY(scroll.y);
|
||||||
|
//m_updateFocus = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void TextEditor::setFocusAtCoords(const Coordinates &coords, bool scrollToCursor) {
|
||||||
|
m_focusAtCoords = coords;
|
||||||
|
m_state.m_cursorPosition = coords;
|
||||||
|
m_updateFocus = true;
|
||||||
|
m_scrollToCursor = scrollToCursor;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void TextEditor::setCursorPosition(const Coordinates &position, bool scrollToCursor) {
|
||||||
if (m_state.m_cursorPosition != position) {
|
if (m_state.m_cursorPosition != position) {
|
||||||
m_state.m_cursorPosition = position;
|
m_state.m_cursorPosition = position;
|
||||||
ensureCursorVisible();
|
m_scrollToCursor = scrollToCursor;
|
||||||
|
if (scrollToCursor)
|
||||||
|
ensureCursorVisible();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -19,12 +19,6 @@ namespace hex::ui {
|
||||||
m_topMarginChanged = true;
|
m_topMarginChanged = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void TextEditor::setFocusAtCoords(const Coordinates &coords, bool scrollToCursor) {
|
|
||||||
m_focusAtCoords = coords;
|
|
||||||
m_updateFocus = true;
|
|
||||||
m_scrollToCursor = scrollToCursor;
|
|
||||||
}
|
|
||||||
|
|
||||||
void TextEditor::clearErrorMarkers() {
|
void TextEditor::clearErrorMarkers() {
|
||||||
m_errorMarkers.clear();
|
m_errorMarkers.clear();
|
||||||
m_errorHoverBoxes.clear();
|
m_errorHoverBoxes.clear();
|
||||||
|
|
@ -140,8 +134,6 @@ namespace hex::ui {
|
||||||
bool scroll_x = m_longestLineLength * m_charAdvance.x >= textEditorSize.x;
|
bool scroll_x = m_longestLineLength * m_charAdvance.x >= textEditorSize.x;
|
||||||
|
|
||||||
bool scroll_y = m_lines.size() > 1;
|
bool scroll_y = m_lines.size() > 1;
|
||||||
if (!border)
|
|
||||||
textEditorSize.x -= scrollBarSize;
|
|
||||||
ImGui::SetCursorScreenPos(ImVec2(position.x + m_lineNumberFieldWidth, position.y));
|
ImGui::SetCursorScreenPos(ImVec2(position.x + m_lineNumberFieldWidth, position.y));
|
||||||
ImGuiChildFlags childFlags = border ? ImGuiChildFlags_Borders : ImGuiChildFlags_None;
|
ImGuiChildFlags childFlags = border ? ImGuiChildFlags_Borders : ImGuiChildFlags_None;
|
||||||
ImGuiWindowFlags windowFlags = ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoMove;
|
ImGuiWindowFlags windowFlags = ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoMove;
|
||||||
|
|
@ -262,9 +254,16 @@ namespace hex::ui {
|
||||||
auto drawList = ImGui::GetWindowDrawList();
|
auto drawList = ImGui::GetWindowDrawList();
|
||||||
s_cursorScreenPosition = ImGui::GetCursorScreenPos();
|
s_cursorScreenPosition = ImGui::GetCursorScreenPos();
|
||||||
ImVec2 position = lineNumbersStartPos;
|
ImVec2 position = lineNumbersStartPos;
|
||||||
if (m_setScrollY)
|
float scrollY;
|
||||||
setScrollY();
|
if (m_setScroll) {
|
||||||
auto scrollY = ImGui::GetScrollY();
|
setScroll(m_scroll);
|
||||||
|
scrollY = m_scroll.y;
|
||||||
|
} else {
|
||||||
|
scrollY = ImGui::GetScrollY();
|
||||||
|
float scrollX = ImGui::GetScrollX();
|
||||||
|
m_scroll = ImVec2(scrollX, scrollY);
|
||||||
|
}
|
||||||
|
|
||||||
if (m_setTopLine)
|
if (m_setTopLine)
|
||||||
setTopLine();
|
setTopLine();
|
||||||
else
|
else
|
||||||
|
|
|
||||||
|
|
@ -537,13 +537,13 @@ namespace hex::ui {
|
||||||
return !isEmpty() && m_state.m_selection.m_end > m_state.m_selection.m_start;
|
return !isEmpty() && m_state.m_selection.m_end > m_state.m_selection.m_start;
|
||||||
}
|
}
|
||||||
|
|
||||||
void TextEditor::addUndo(UndoRecord &value) {
|
void TextEditor::addUndo(UndoRecords &value) {
|
||||||
if (m_readOnly)
|
if (m_readOnly)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
m_undoBuffer.resize((u64) (m_undoIndex + 1));
|
m_undoBuffer.resize((u64) (m_undoIndex + 1));
|
||||||
m_undoBuffer.back() = value;
|
m_undoBuffer.back() = UndoAction(value);
|
||||||
++m_undoIndex;
|
m_undoIndex++;
|
||||||
}
|
}
|
||||||
|
|
||||||
TextEditor::PaletteIndex TextEditor::getColorIndexFromFlags(Line::Flags flags) {
|
TextEditor::PaletteIndex TextEditor::getColorIndexFromFlags(Line::Flags flags) {
|
||||||
|
|
@ -711,7 +711,7 @@ namespace hex::ui {
|
||||||
i32 count = m_matches.size();
|
i32 count = m_matches.size();
|
||||||
|
|
||||||
if (count == 0) {
|
if (count == 0) {
|
||||||
editor->setCursorPosition(targetPos);
|
editor->setCursorPosition(targetPos, true);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -723,7 +723,7 @@ namespace hex::ui {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (matchIndex >= 0 && matchIndex <count) {
|
if (matchIndex >= 0 && matchIndex < count) {
|
||||||
while (matchIndex + index < 0)
|
while (matchIndex + index < 0)
|
||||||
index += count;
|
index += count;
|
||||||
auto rem = (matchIndex + index) % count;
|
auto rem = (matchIndex + index) % count;
|
||||||
|
|
@ -804,17 +804,98 @@ namespace hex::ui {
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void FindReplaceHandler::setFindWord(TextEditor *editor, const std::string &findWord) {
|
||||||
|
if (findWord != m_findWord) {
|
||||||
|
findAllMatches(editor, findWord);
|
||||||
|
m_findWord = findWord;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void FindReplaceHandler::setMatchCase(TextEditor *editor, bool matchCase) {
|
||||||
|
if (matchCase != m_matchCase) {
|
||||||
|
m_matchCase = matchCase;
|
||||||
|
m_optionsChanged = true;
|
||||||
|
findAllMatches(editor, m_findWord);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void FindReplaceHandler::setWholeWord(TextEditor *editor, bool wholeWord) {
|
||||||
|
if (wholeWord != m_wholeWord) {
|
||||||
|
m_wholeWord = wholeWord;
|
||||||
|
m_optionsChanged = true;
|
||||||
|
findAllMatches(editor, m_findWord);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
void FindReplaceHandler::setFindRegEx(TextEditor *editor, bool findRegEx) {
|
||||||
|
if (findRegEx != m_findRegEx) {
|
||||||
|
m_findRegEx = findRegEx;
|
||||||
|
m_optionsChanged = true;
|
||||||
|
findAllMatches(editor, m_findWord);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void FindReplaceHandler::resetMatches() {
|
||||||
|
m_matches.clear();
|
||||||
|
m_findWord = "";
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
void TextEditor::computeLPSArray(const std::string &pattern, std::vector<i32> & lps) {
|
||||||
|
i32 length = 0; // length of the previous longest prefix suffix
|
||||||
|
i32 i = 1;
|
||||||
|
lps[0] = 0; // lps[0] is always 0
|
||||||
|
i32 patternLength = pattern.length();
|
||||||
|
|
||||||
|
while (i < patternLength) {
|
||||||
|
if (pattern[i] == pattern[length]) {
|
||||||
|
length++;
|
||||||
|
lps[i] = length;
|
||||||
|
i++;
|
||||||
|
} else {
|
||||||
|
if (length != 0)
|
||||||
|
length = lps[length - 1];
|
||||||
|
else {
|
||||||
|
lps[i] = 0;
|
||||||
|
i++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::vector<i32> TextEditor::KMPSearch(const std::string& text, const std::string& pattern) {
|
||||||
|
i32 textLength = text.length();
|
||||||
|
i32 patternLength = pattern.length();
|
||||||
|
std::vector<i32> result;
|
||||||
|
std::vector<i32> lps(patternLength);
|
||||||
|
computeLPSArray(pattern, lps);
|
||||||
|
|
||||||
|
i32 textIndex = 0;
|
||||||
|
i32 patternIndex = 0;
|
||||||
|
|
||||||
|
while (textIndex < textLength) {
|
||||||
|
if (pattern[patternIndex] == text[textIndex]) {
|
||||||
|
textIndex++;
|
||||||
|
patternIndex++;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (patternIndex == patternLength) {
|
||||||
|
result.push_back(textIndex - patternIndex);
|
||||||
|
patternIndex = lps[patternIndex - 1];
|
||||||
|
} else if (textIndex < textLength && pattern[patternIndex] != text[textIndex]) {
|
||||||
|
if (patternIndex != 0)
|
||||||
|
patternIndex = lps[patternIndex - 1];
|
||||||
|
else
|
||||||
|
textIndex++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}*/
|
||||||
|
|
||||||
// Performs actual search to fill mMatches
|
// Performs actual search to fill mMatches
|
||||||
bool FindReplaceHandler::findNext(TextEditor *editor) {
|
bool FindReplaceHandler::findNext(TextEditor *editor, u64 &byteIndex) {
|
||||||
Coordinates curPos = m_matches.empty() ? editor->m_state.m_cursorPosition : editor->lineCoordsToIndexCoords(m_matches.back().m_cursorPosition);
|
|
||||||
|
|
||||||
u64 matchLength = stringCharacterCount(m_findWord);
|
|
||||||
u64 matchBytes = m_findWord.size();
|
u64 matchBytes = m_findWord.size();
|
||||||
u64 byteIndex = 0;
|
|
||||||
|
|
||||||
for (i64 ln = 0; ln < curPos.m_line; ln++)
|
|
||||||
byteIndex += editor->getLineByteCount(ln) + 1;
|
|
||||||
byteIndex += curPos.m_column;
|
|
||||||
|
|
||||||
std::string wordLower = m_findWord;
|
std::string wordLower = m_findWord;
|
||||||
if (!getMatchCase())
|
if (!getMatchCase())
|
||||||
|
|
@ -854,16 +935,14 @@ namespace hex::ui {
|
||||||
if (!iter->ready())
|
if (!iter->ready())
|
||||||
return false;
|
return false;
|
||||||
u64 firstLoc = iter->position();
|
u64 firstLoc = iter->position();
|
||||||
u64 firstLength = iter->length();
|
|
||||||
|
|
||||||
if (firstLoc > byteIndex) {
|
if (firstLoc > byteIndex) {
|
||||||
pos = firstLoc;
|
pos = firstLoc;
|
||||||
matchLength = firstLength;
|
|
||||||
} else {
|
} else {
|
||||||
|
|
||||||
while (iter != end) {
|
while (iter != end) {
|
||||||
iter++;
|
iter++;
|
||||||
if (((pos = iter->position()) > byteIndex) && ((matchLength = iter->length()) > 0))
|
if (((pos = iter->position()) > byteIndex))
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -875,15 +954,16 @@ namespace hex::ui {
|
||||||
} else {
|
} else {
|
||||||
// non regex search
|
// non regex search
|
||||||
textLoc = textSrc.find(wordLower, byteIndex);
|
textLoc = textSrc.find(wordLower, byteIndex);
|
||||||
if (textLoc == std::string::npos)
|
|
||||||
return false;
|
|
||||||
}
|
}
|
||||||
if (textLoc == std::string::npos)
|
if (textLoc == std::string::npos)
|
||||||
return false;
|
return false;
|
||||||
TextEditor::EditorState state;
|
TextEditor::EditorState state;
|
||||||
state.m_selection = Range(TextEditor::stringIndexToCoordinates(textLoc, textSrc), TextEditor::stringIndexToCoordinates(textLoc + matchBytes, textSrc));
|
state.m_selection = Range(TextEditor::stringIndexToCoordinates(textLoc, textSrc), TextEditor::stringIndexToCoordinates(textLoc + matchBytes, textSrc));
|
||||||
state.m_cursorPosition = state.m_selection.m_end;
|
state.m_cursorPosition = state.m_selection.m_end;
|
||||||
|
if (!m_matches.empty() && state == m_matches.back())
|
||||||
|
return false;
|
||||||
m_matches.push_back(state);
|
m_matches.push_back(state);
|
||||||
|
byteIndex = textLoc + 1;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -902,6 +982,7 @@ namespace hex::ui {
|
||||||
if (m_optionsChanged)
|
if (m_optionsChanged)
|
||||||
m_optionsChanged = false;
|
m_optionsChanged = false;
|
||||||
|
|
||||||
|
u64 byteIndex = 0;
|
||||||
m_matches.clear();
|
m_matches.clear();
|
||||||
m_findWord = findWord;
|
m_findWord = findWord;
|
||||||
auto startingPos = editor->m_state.m_cursorPosition;
|
auto startingPos = editor->m_state.m_cursorPosition;
|
||||||
|
|
@ -909,7 +990,7 @@ namespace hex::ui {
|
||||||
Coordinates begin = editor->setCoordinates(0, 0);
|
Coordinates begin = editor->setCoordinates(0, 0);
|
||||||
editor->m_state.m_cursorPosition = begin;
|
editor->m_state.m_cursorPosition = begin;
|
||||||
|
|
||||||
if (!findNext(editor)) {
|
if (!findNext(editor, byteIndex)) {
|
||||||
editor->m_state = saveState;
|
editor->m_state = saveState;
|
||||||
editor->ensureCursorVisible();
|
editor->ensureCursorVisible();
|
||||||
return;
|
return;
|
||||||
|
|
@ -917,7 +998,7 @@ namespace hex::ui {
|
||||||
TextEditor::EditorState state = m_matches.back();
|
TextEditor::EditorState state = m_matches.back();
|
||||||
|
|
||||||
while (state.m_cursorPosition < startingPos) {
|
while (state.m_cursorPosition < startingPos) {
|
||||||
if (!findNext(editor)) {
|
if (!findNext(editor, byteIndex)) {
|
||||||
editor->m_state = saveState;
|
editor->m_state = saveState;
|
||||||
editor->ensureCursorVisible();
|
editor->ensureCursorVisible();
|
||||||
return;
|
return;
|
||||||
|
|
@ -925,7 +1006,7 @@ namespace hex::ui {
|
||||||
state = m_matches.back();
|
state = m_matches.back();
|
||||||
}
|
}
|
||||||
|
|
||||||
while (findNext(editor));
|
while (findNext(editor, byteIndex));
|
||||||
|
|
||||||
editor->m_state = saveState;
|
editor->m_state = saveState;
|
||||||
editor->ensureCursorVisible();
|
editor->ensureCursorVisible();
|
||||||
|
|
@ -972,7 +1053,7 @@ namespace hex::ui {
|
||||||
ImGui::SetKeyboardFocusHere(0);
|
ImGui::SetKeyboardFocusHere(0);
|
||||||
|
|
||||||
u.m_after = editor->m_state;
|
u.m_after = editor->m_state;
|
||||||
editor->addUndo(u);
|
m_undoBuffer.push_back(u);
|
||||||
editor->m_textChanged = true;
|
editor->m_textChanged = true;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
|
@ -983,10 +1064,11 @@ namespace hex::ui {
|
||||||
|
|
||||||
bool FindReplaceHandler::replaceAll(TextEditor *editor) {
|
bool FindReplaceHandler::replaceAll(TextEditor *editor) {
|
||||||
u32 count = m_matches.size();
|
u32 count = m_matches.size();
|
||||||
|
m_undoBuffer.clear();
|
||||||
for (u32 i = 0; i < count; i++)
|
for (u32 i = 0; i < count; i++)
|
||||||
replace(editor, true);
|
replace(editor, true);
|
||||||
|
|
||||||
|
editor->addUndo(m_undoBuffer);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue