1
0
mirror of synced 2024-11-13 18:50:53 +01:00

fix: F3 failed to locate the correct set of matches if file was edited after doing a search (#1867)

### Problem description
The bug can be reproduced as follows:
1) Using Ctrl-F do a search for a term that occurs several times in the
file. and press F3 to visit them.
2) Go back to the fop of the file and insert 3 blank lines. 
3) Pressing F3 once or many times will not find the term entered above.


### Implementation description
The reason for this bug is that the positions of the matches are not
being reset when changes can potentially move them.
The fix consists on resetting the search locations when changing the
contents of the file and redoing the search after the changes are made.
The bug was specially problematic when doing replace because the
replacement position would be identified as a match. This PR fixes
replace as well.

---------

Co-authored-by: Nik <werwolv98@gmail.com>
This commit is contained in:
paxcut 2024-09-15 06:32:10 -07:00 committed by GitHub
parent 866b956680
commit 96a588bd86
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 75 additions and 27 deletions

View File

@ -275,7 +275,7 @@ public:
ImVec2 &GetCharAdvance() { return mCharAdvance; } ImVec2 &GetCharAdvance() { return mCharAdvance; }
bool CanUndo() const; bool CanUndo();
bool CanRedo() const; bool CanRedo() const;
void Undo(int aSteps = 1); void Undo(int aSteps = 1);
void Redo(int aSteps = 1); void Redo(int aSteps = 1);

View File

@ -794,7 +794,8 @@ void TextEditor::HandleMouseInputs() {
mSelectionMode = SelectionMode::Normal; mSelectionMode = SelectionMode::Normal;
} }
SetSelection(mInteractiveStart, mInteractiveEnd, mSelectionMode); SetSelection(mInteractiveStart, mInteractiveEnd, mSelectionMode);
resetBlinking=true; ResetCursorBlinkTime();
EnsureCursorVisible(); EnsureCursorVisible();
mLastClick = (float)ImGui::GetTime(); mLastClick = (float)ImGui::GetTime();
} }
@ -1412,6 +1413,13 @@ void TextEditor::EnterCharacter(ImWchar aChar, bool aShift) {
AddUndo(u); AddUndo(u);
Colorize(coord.mLine - 1, 3); Colorize(coord.mLine - 1, 3);
std::string findWord = mFindReplaceHandler.GetFindWord();
if (!findWord.empty()) {
mFindReplaceHandler.resetMatches();
mFindReplaceHandler.FindAllMatches(this, findWord);
}
EnsureCursorVisible(); EnsureCursorVisible();
} }
@ -1499,6 +1507,12 @@ void TextEditor::InsertText(const char *aValue) {
SetSelection(pos, pos); SetSelection(pos, pos);
SetCursorPosition(pos); SetCursorPosition(pos);
std::string findWord = mFindReplaceHandler.GetFindWord();
if (!findWord.empty()) {
mFindReplaceHandler.resetMatches();
mFindReplaceHandler.FindAllMatches(this, findWord);
}
Colorize(start.mLine - 1, totalLines + 2); Colorize(start.mLine - 1, totalLines + 2);
} }
@ -1512,6 +1526,11 @@ void TextEditor::DeleteSelection() {
SetSelection(mState.mSelectionStart, mState.mSelectionStart); SetSelection(mState.mSelectionStart, mState.mSelectionStart);
SetCursorPosition(mState.mSelectionStart); SetCursorPosition(mState.mSelectionStart);
std::string findWord = mFindReplaceHandler.GetFindWord();
if (!findWord.empty()) {
mFindReplaceHandler.resetMatches();
mFindReplaceHandler.FindAllMatches(this, findWord);
}
Colorize(mState.mSelectionStart.mLine, 1); Colorize(mState.mSelectionStart.mLine, 1);
} }
@ -1798,6 +1817,11 @@ void TextEditor::Delete() {
u.mAfter = mState; u.mAfter = mState;
AddUndo(u); AddUndo(u);
std::string findWord = mFindReplaceHandler.GetFindWord();
if (!findWord.empty()) {
mFindReplaceHandler.resetMatches();
mFindReplaceHandler.FindAllMatches(this, findWord);
}
} }
void TextEditor::Backspace() { void TextEditor::Backspace() {
@ -1866,6 +1890,11 @@ void TextEditor::Backspace() {
u.mAfter = mState; u.mAfter = mState;
AddUndo(u); AddUndo(u);
std::string findWord = mFindReplaceHandler.GetFindWord();
if (!findWord.empty()) {
mFindReplaceHandler.resetMatches();
mFindReplaceHandler.FindAllMatches(this, findWord);
}
} }
void TextEditor::SelectWordUnderCursor() { void TextEditor::SelectWordUnderCursor() {
@ -1913,6 +1942,11 @@ void TextEditor::Cut() {
AddUndo(u); AddUndo(u);
} }
} }
std::string findWord = mFindReplaceHandler.GetFindWord();
if (!findWord.empty()) {
mFindReplaceHandler.resetMatches();
mFindReplaceHandler.FindAllMatches(this, findWord);
}
} }
void TextEditor::Paste() { void TextEditor::Paste() {
@ -1940,9 +1974,14 @@ void TextEditor::Paste() {
u.mAfter = mState; u.mAfter = mState;
AddUndo(u); AddUndo(u);
} }
std::string findWord = mFindReplaceHandler.GetFindWord();
if (!findWord.empty()) {
mFindReplaceHandler.resetMatches();
mFindReplaceHandler.FindAllMatches(this, findWord);
}
} }
bool TextEditor::CanUndo() const { bool TextEditor::CanUndo() {
return !mReadOnly && mUndoIndex > 0; return !mReadOnly && mUndoIndex > 0;
} }
@ -1953,11 +1992,21 @@ bool TextEditor::CanRedo() const {
void TextEditor::Undo(int aSteps) { void TextEditor::Undo(int aSteps) {
while (CanUndo() && aSteps-- > 0) while (CanUndo() && aSteps-- > 0)
mUndoBuffer[--mUndoIndex].Undo(this); mUndoBuffer[--mUndoIndex].Undo(this);
std::string findWord = mFindReplaceHandler.GetFindWord();
if (!findWord.empty()) {
mFindReplaceHandler.resetMatches();
mFindReplaceHandler.FindAllMatches(this, findWord);
}
} }
void TextEditor::Redo(int aSteps) { void TextEditor::Redo(int aSteps) {
while (CanRedo() && aSteps-- > 0) while (CanRedo() && aSteps-- > 0)
mUndoBuffer[mUndoIndex++].Redo(this); mUndoBuffer[mUndoIndex++].Redo(this);
std::string findWord = mFindReplaceHandler.GetFindWord();
if (!findWord.empty()) {
mFindReplaceHandler.resetMatches();
mFindReplaceHandler.FindAllMatches(this, findWord);
}
} }
// the index here is array index so zero based // the index here is array index so zero based
@ -2096,7 +2145,7 @@ bool TextEditor::FindReplaceHandler::FindNext(TextEditor *editor, bool wrapAroun
curPos.mLine = mMatches.empty() ? editor->mState.mCursorPosition.mLine : mMatches.back().mCursorPosition.mLine; curPos.mLine = mMatches.empty() ? editor->mState.mCursorPosition.mLine : mMatches.back().mCursorPosition.mLine;
curPos.mColumn = mMatches.empty() ? editor->mState.mCursorPosition.mColumn : editor->Utf8CharsToBytes( curPos.mColumn = mMatches.empty() ? editor->mState.mCursorPosition.mColumn : editor->Utf8CharsToBytes(
mMatches.back().mCursorPosition); mMatches.back().mCursorPosition);
unsigned long selectionLength = editor->GetStringCharacterCount(mFindWord); unsigned long selectionLength = editor->GetStringCharacterCount(mFindWord);
size_t byteIndex = 0; size_t byteIndex = 0;
@ -2123,13 +2172,13 @@ bool TextEditor::FindReplaceHandler::FindNext(TextEditor *editor, bool wrapAroun
if (GetFindRegEx()) { if (GetFindRegEx()) {
try { try {
regularExpression.assign(wordLower); regularExpression.assign(wordLower);
} catch (std::regex_error &e) { } catch (const std::regex_error &e) {
return false; return false;
} }
} else { } else {
try { try {
regularExpression.assign(make_wholeWord(wordLower)); regularExpression.assign(make_wholeWord(wordLower));
} catch (std::regex_error &e) { } catch (const std::regex_error &e) {
return false; return false;
} }
} }
@ -2159,10 +2208,8 @@ bool TextEditor::FindReplaceHandler::FindNext(TextEditor *editor, bool wrapAroun
textLoc = pos; textLoc = pos;
if (wrapAround) { if (wrapAround) {
if (iter == end) { if (iter == end)
pos = firstLoc;
selectionLength = firstLength; selectionLength = firstLength;
}
} }
} else { } else {
// non regex search // non regex search
@ -2203,16 +2250,18 @@ bool TextEditor::FindReplaceHandler::FindNext(TextEditor *editor, bool wrapAroun
selStart.mColumn = editor->Utf8BytesToChars(curPos); selStart.mColumn = editor->Utf8BytesToChars(curPos);
selEnd = selStart; selEnd = selStart;
selEnd.mColumn += selectionLength; selEnd.mColumn += selectionLength;
editor->SetSelection(selStart, selEnd); TextEditor::EditorState state;
editor->SetCursorPosition(selEnd); state.mSelectionStart = selStart;
editor->mScrollToCursor = true; state.mSelectionEnd = selEnd;
state.mCursorPosition = selEnd;
mMatches.push_back(state);
return true; return true;
} }
void TextEditor::FindReplaceHandler::FindAllMatches(TextEditor *editor,std::string findWord) { void TextEditor::FindReplaceHandler::FindAllMatches(TextEditor *editor,std::string findWord) {
if (findWord.empty()) { if (findWord.empty()) {
editor->mScrollToCursor = true; editor->EnsureCursorVisible();
mFindWord = ""; mFindWord = "";
mMatches.clear(); mMatches.clear();
return; return;
@ -2227,32 +2276,30 @@ void TextEditor::FindReplaceHandler::FindAllMatches(TextEditor *editor,std::stri
mMatches.clear(); mMatches.clear();
mFindWord = findWord; mFindWord = findWord;
auto startingPos = editor->mState.mCursorPosition; auto startingPos = editor->mState.mCursorPosition;
auto state = editor->mState; auto saveState = editor->mState;
Coordinates begin = Coordinates(0,0); Coordinates begin = Coordinates(0,0);
editor->mState.mCursorPosition = begin; editor->mState.mCursorPosition = begin;
if (!FindNext(editor,false)) { if (!FindNext(editor,false)) {
editor->mState = state; editor->mState = saveState;
editor->mScrollToCursor = true; editor->EnsureCursorVisible();
return; return;
} }
auto initialPos = editor->mState.mCursorPosition; TextEditor::EditorState state = mMatches.back();
mMatches.push_back(editor->mState);
while( editor->mState.mCursorPosition < startingPos) { while( state.mCursorPosition < startingPos) {
if (!FindNext(editor,false)) { if (!FindNext(editor,false)) {
editor->mState = state; editor->mState = saveState;
editor->mScrollToCursor = true; editor->EnsureCursorVisible();
return; return;
} }
mMatches.push_back(editor->mState); state = mMatches.back();
} }
while (FindNext(editor,false)) while (FindNext(editor,false));
mMatches.push_back(editor->mState);
editor->mState = state; editor->mState = saveState;
editor->mScrollToCursor = true; editor->EnsureCursorVisible();
return; return;
} }
@ -2299,7 +2346,7 @@ bool TextEditor::FindReplaceHandler::Replace(TextEditor *editor, bool next) {
u.mAddedEnd = editor->GetActualCursorCoordinates(); u.mAddedEnd = editor->GetActualCursorCoordinates();
editor->mScrollToCursor = true; editor->EnsureCursorVisible();
ImGui::SetKeyboardFocusHere(0); ImGui::SetKeyboardFocusHere(0);
u.mAfter = editor->mState; u.mAfter = editor->mState;
@ -2885,6 +2932,7 @@ void TextEditor::UndoRecord::Redo(TextEditor *aEditor) {
aEditor->mState = mAfter; aEditor->mState = mAfter;
aEditor->EnsureCursorVisible(); aEditor->EnsureCursorVisible();
} }
bool TokenizeCStyleString(const char *in_begin, const char *in_end, const char *&out_begin, const char *&out_end) { bool TokenizeCStyleString(const char *in_begin, const char *in_end, const char *&out_begin, const char *&out_end) {