feat: Added multiline search/replace and fixed various crashes. (#1911)
### Problem description Previous implementation ignored everything after the first newline. Other changes include: - Added isEmpty() function that checks if editor has no content. - replaced asserts with default behavior to avoid unneeded crashes. - fixed off by one error in DeleteRange() - some crashes occurred because readily available corrective actions were not being taken. For example start/end being -1 in DeleteRange(). - At the heart of search/replace is the ability to translate from indices into the text string to line/column coordinates used for everything. To this end a function (StringIndexToCoordinates) was added to do the translation taking utf-8 chars into account. This made the recently added Utf8BytesToChars function unneeded, so it was removed. - Removed commented out code that is not useful anymore. Also removed tooltip code which is also unused. - Removed unused parameter wrapAround to FindNext().
This commit is contained in:
parent
05c25b6aff
commit
6d2761f141
@ -211,6 +211,10 @@ public:
|
||||
void Render(const char* aTitle, const ImVec2& aSize = ImVec2(), bool aBorder = false);
|
||||
void SetText(const std::string& aText);
|
||||
std::string GetText() const;
|
||||
bool isEmpty() const {
|
||||
auto text = GetText();
|
||||
return text.empty() || text == "\n";
|
||||
}
|
||||
|
||||
void SetTextLines(const std::vector<std::string>& aLines);
|
||||
std::vector<std::string> GetTextLines() const;
|
||||
@ -314,7 +318,7 @@ public:
|
||||
FindReplaceHandler();
|
||||
typedef std::vector<EditorState> Matches;
|
||||
Matches &GetMatches() { return mMatches; }
|
||||
bool FindNext(TextEditor *editor,bool wrapAround);
|
||||
bool FindNext(TextEditor *editor);
|
||||
unsigned FindMatch(TextEditor *editor,bool isNex);
|
||||
bool Replace(TextEditor *editor,bool right);
|
||||
bool ReplaceAll(TextEditor *editor);
|
||||
@ -428,10 +432,10 @@ private:
|
||||
Coordinates FindWordStart(const Coordinates& aFrom) const;
|
||||
Coordinates FindWordEnd(const Coordinates& aFrom) const;
|
||||
Coordinates FindNextWord(const Coordinates& aFrom) const;
|
||||
Coordinates StringIndexToCoordinates(int aIndex, const std::string &str) const;
|
||||
int GetCharacterIndex(const Coordinates& aCoordinates) const;
|
||||
int GetCharacterColumn(int aLine, int aIndex) const;
|
||||
int GetLineCharacterCount(int aLine) const;
|
||||
int Utf8BytesToChars(const Coordinates &aCoordinates) const;
|
||||
int Utf8CharsToBytes(const Coordinates &aCoordinates) const;
|
||||
unsigned long long GetLineByteCount(int aLine) const;
|
||||
int GetStringCharacterCount(std::string str) const;
|
||||
|
@ -123,7 +123,7 @@ TextEditor::Coordinates TextEditor::SanitizeCoordinates(const Coordinates &aValu
|
||||
auto line = aValue.mLine;
|
||||
auto column = aValue.mColumn;
|
||||
if (line >= (int)mLines.size()) {
|
||||
if (mLines.empty()) {
|
||||
if (isEmpty()) {
|
||||
line = 0;
|
||||
column = 0;
|
||||
} else {
|
||||
@ -132,7 +132,7 @@ TextEditor::Coordinates TextEditor::SanitizeCoordinates(const Coordinates &aValu
|
||||
}
|
||||
return Coordinates(line, column);
|
||||
} else {
|
||||
column = mLines.empty() ? 0 : std::min(column, GetLineMaxColumn(line));
|
||||
column = isEmpty() ? 0 : std::min(column, GetLineMaxColumn(line));
|
||||
return Coordinates(line, column);
|
||||
}
|
||||
}
|
||||
@ -213,6 +213,8 @@ void TextEditor::DeleteRange(const Coordinates &aStart, const Coordinates &aEnd)
|
||||
|
||||
auto start = GetCharacterIndex(aStart);
|
||||
auto end = GetCharacterIndex(aEnd);
|
||||
if (start == -1 || end == -1)
|
||||
return;
|
||||
|
||||
if (aStart.mLine == aEnd.mLine) {
|
||||
auto &line = mLines[aStart.mLine];
|
||||
@ -232,7 +234,7 @@ void TextEditor::DeleteRange(const Coordinates &aStart, const Coordinates &aEnd)
|
||||
firstLine.insert(firstLine.end(), lastLine.begin(), lastLine.end());
|
||||
|
||||
if (aStart.mLine < aEnd.mLine)
|
||||
RemoveLine(aStart.mLine + 1, aEnd.mLine + 1);
|
||||
RemoveLine(aStart.mLine + 1, aEnd.mLine);
|
||||
}
|
||||
|
||||
mTextChanged = true;
|
||||
@ -242,7 +244,10 @@ int TextEditor::InsertTextAt(Coordinates & /* inout */ aWhere, const char *aValu
|
||||
int cindex = GetCharacterIndex(aWhere);
|
||||
int totalLines = 0;
|
||||
while (*aValue != '\0') {
|
||||
assert(!mLines.empty());
|
||||
if (mLines.empty()) {
|
||||
mLines.push_back(Line());
|
||||
mTextChanged = true;
|
||||
}
|
||||
|
||||
if (*aValue == '\r') {
|
||||
// skip
|
||||
@ -422,7 +427,7 @@ TextEditor::Coordinates TextEditor::FindNextWord(const Coordinates &aFrom) const
|
||||
bool isword = false;
|
||||
bool skip = false;
|
||||
if (cindex < (int)mLines[at.mLine].size()) {
|
||||
auto &line = mLines[at.mLine];
|
||||
const auto &line = mLines[at.mLine];
|
||||
isword = isalnum(line[cindex].mChar);
|
||||
skip = isword;
|
||||
}
|
||||
@ -455,26 +460,12 @@ TextEditor::Coordinates TextEditor::FindNextWord(const Coordinates &aFrom) const
|
||||
return at;
|
||||
}
|
||||
|
||||
int TextEditor::Utf8BytesToChars(const Coordinates &aCoordinates) const {
|
||||
if (aCoordinates.mLine >= mLines.size())
|
||||
return -1;
|
||||
auto &line = mLines[aCoordinates.mLine];
|
||||
int c = 0;
|
||||
int i = 0;
|
||||
while (i < aCoordinates.mColumn) {
|
||||
i += UTF8CharLength(line[i].mChar);
|
||||
if (line[i].mChar == '\t')
|
||||
c = (c / mTabSize) * mTabSize + mTabSize;
|
||||
else
|
||||
++c;
|
||||
}
|
||||
return c;
|
||||
}
|
||||
|
||||
int TextEditor::Utf8CharsToBytes(const Coordinates &aCoordinates) const {
|
||||
if (aCoordinates.mLine >= mLines.size())
|
||||
return -1;
|
||||
auto &line = mLines[aCoordinates.mLine];
|
||||
if (line.empty())
|
||||
return 0;
|
||||
int c = 0;
|
||||
int i = 0;
|
||||
while (i < line.size() && c < aCoordinates.mColumn) {
|
||||
@ -487,6 +478,18 @@ int TextEditor::Utf8CharsToBytes(const Coordinates &aCoordinates) const {
|
||||
return i;
|
||||
}
|
||||
|
||||
TextEditor::Coordinates TextEditor::StringIndexToCoordinates(int aIndex, const std::string &input ) const {
|
||||
if (aIndex < 0 || aIndex > (int)input.size())
|
||||
return Coordinates(0, 0);
|
||||
std::string str = input.substr(0, aIndex);
|
||||
auto line = std::count(str.begin(),str.end(),'\n');
|
||||
auto index = str.find_last_of('\n');
|
||||
str = str.substr(index+1);
|
||||
auto col = GetStringCharacterCount(str);
|
||||
|
||||
return Coordinates(line, col);
|
||||
}
|
||||
|
||||
int TextEditor::GetCharacterIndex(const Coordinates &aCoordinates) const {
|
||||
if (aCoordinates.mLine >= mLines.size())
|
||||
return -1;
|
||||
@ -580,7 +583,6 @@ bool TextEditor::IsOnWordBoundary(const Coordinates &aAt) const {
|
||||
void TextEditor::RemoveLine(int aStart, int aEnd) {
|
||||
assert(!mReadOnly);
|
||||
assert(aEnd >= aStart);
|
||||
assert(mLines.size() > (size_t)(aEnd - aStart));
|
||||
|
||||
ErrorMarkers etmp;
|
||||
for (auto &i : mErrorMarkers) {
|
||||
@ -601,12 +603,12 @@ void TextEditor::RemoveLine(int aStart, int aEnd) {
|
||||
btmp.insert(breakpoint);
|
||||
}
|
||||
}
|
||||
if (mBreakPointsChanged)
|
||||
mBreakpoints = std::move(btmp);
|
||||
if (aStart == 0 && aEnd == (int32_t)mLines.size() - 1)
|
||||
mLines.erase(mLines.begin() + aStart, mLines.end());
|
||||
else
|
||||
mLines.erase(mLines.begin() + aStart, mLines.begin() + aEnd + 1);
|
||||
|
||||
mBreakpoints = std::move(btmp);
|
||||
// use clamp to ensure valid results instead of assert.
|
||||
auto start = std::clamp(aStart, 0, (int)mLines.size()-1);
|
||||
auto end = std::clamp(aEnd, 0, (int)mLines.size());
|
||||
mLines.erase(mLines.begin() + aStart, mLines.begin() + aEnd + 1);
|
||||
|
||||
mTextChanged = true;
|
||||
}
|
||||
@ -642,7 +644,16 @@ void TextEditor::RemoveLine(int aIndex) {
|
||||
}
|
||||
|
||||
TextEditor::Line &TextEditor::InsertLine(int aIndex) {
|
||||
auto &result = *mLines.insert(mLines.begin() + aIndex, Line());
|
||||
|
||||
if (isEmpty())
|
||||
return *mLines.insert(mLines.begin(), Line());
|
||||
|
||||
if (aIndex == mLines.size())
|
||||
return *mLines.insert(mLines.end(), Line());
|
||||
|
||||
auto newLine = Line();
|
||||
|
||||
TextEditor::Line &result = *mLines.insert(mLines.begin() + aIndex, newLine);
|
||||
|
||||
ErrorMarkers etmp;
|
||||
for (auto &i : mErrorMarkers)
|
||||
@ -717,22 +728,10 @@ void TextEditor::HandleKeyboardInputs() {
|
||||
auto ctrl = io.KeyCtrl;
|
||||
auto alt = io.KeyAlt;
|
||||
auto shift = io.KeyShift;
|
||||
/* auto left = ImGui::IsKeyPressed(ImGuiKey_LeftArrow);
|
||||
auto right = ImGui::IsKeyPressed(ImGuiKey_RightArrow);
|
||||
auto up = ImGui::IsKeyPressed(ImGuiKey_UpArrow);
|
||||
auto down = ImGui::IsKeyPressed(ImGuiKey_DownArrow);
|
||||
|
||||
auto home = io.ConfigMacOSXBehaviors ? io.KeySuper && left : ImGui::IsKeyPressed(ImGuiKey_Home);
|
||||
auto end = io.ConfigMacOSXBehaviors ? io.KeySuper && right : ImGui::IsKeyPressed(ImGuiKey_End);
|
||||
auto top = io.ConfigMacOSXBehaviors ? io.KeySuper && up : ctrl && ImGui::IsKeyPressed(ImGuiKey_Home);
|
||||
auto bottom = io.ConfigMacOSXBehaviors ? io.KeySuper && down : ctrl && ImGui::IsKeyPressed(ImGuiKey_End);
|
||||
auto pageUp = io.ConfigMacOSXBehaviors ? ctrl && up : ImGui::IsKeyPressed(ImGuiKey_PageUp);
|
||||
auto pageDown = io.ConfigMacOSXBehaviors ? ctrl && down : ImGui::IsKeyPressed(ImGuiKey_PageDown);
|
||||
*/
|
||||
if (ImGui::IsWindowFocused()) {
|
||||
if (ImGui::IsWindowHovered())
|
||||
ImGui::SetMouseCursor(ImGuiMouseCursor_TextInput);
|
||||
// ImGui::CaptureKeyboardFromApp(true);
|
||||
|
||||
io.WantCaptureKeyboard = true;
|
||||
io.WantTextInput = true;
|
||||
@ -865,7 +864,7 @@ void TextEditor::Render() {
|
||||
auto scrollX = ImGui::GetScrollX();
|
||||
auto scrollY = ImGui::GetScrollY();
|
||||
|
||||
auto lineNo = (int)(std::floor(scrollY / mCharAdvance.y));// + linesAdded);
|
||||
auto lineNo = (int)(std::floor(scrollY / mCharAdvance.y));
|
||||
auto globalLineMax = (int)mLines.size();
|
||||
auto lineMax = std::max(0, std::min((int)mLines.size() - 1, lineNo + (int)std::ceil((scrollY + contentSize.y) / mCharAdvance.y)));
|
||||
|
||||
@ -878,7 +877,7 @@ void TextEditor::Render() {
|
||||
buf[0] = '\0';
|
||||
mTextStart = ImGui::GetFont()->CalcTextSizeA(ImGui::GetFontSize(), FLT_MAX, -1.0f, buf, nullptr, nullptr).x + mLeftMargin;
|
||||
|
||||
if (!mLines.empty()) {
|
||||
if (!isEmpty()) {
|
||||
float spaceSize = ImGui::GetFont()->CalcTextSizeA(ImGui::GetFontSize(), FLT_MAX, -1.0f, " ", nullptr, nullptr).x;
|
||||
|
||||
while (lineNo <= lineMax) {
|
||||
@ -1048,25 +1047,6 @@ void TextEditor::Render() {
|
||||
if (lineNo < mLines.size() && ImGui::GetScrollMaxX() > 0.0f)
|
||||
longest = std::max(mTextStart + TextDistanceToLineStart(Coordinates(lineNo, GetLineMaxColumn(lineNo))), longest);
|
||||
|
||||
// Draw a tooltip on known identifiers/preprocessor symbols
|
||||
if (ImGui::IsMousePosValid()) {
|
||||
auto id = GetWordAt(ScreenPosToCoordinates(ImGui::GetMousePos()));
|
||||
if (!id.empty()) {
|
||||
auto it = mLanguageDefinition.mIdentifiers.find(id);
|
||||
if (it != mLanguageDefinition.mIdentifiers.end() && !it->second.mDeclaration.empty()) {
|
||||
ImGui::BeginTooltip();
|
||||
ImGui::TextUnformatted(it->second.mDeclaration.c_str());
|
||||
ImGui::EndTooltip();
|
||||
} else {
|
||||
auto pi = mLanguageDefinition.mPreprocIdentifiers.find(id);
|
||||
if (pi != mLanguageDefinition.mPreprocIdentifiers.end() && !pi->second.mDeclaration.empty()) {
|
||||
ImGui::BeginTooltip();
|
||||
ImGui::TextUnformatted(pi->second.mDeclaration.c_str());
|
||||
ImGui::EndTooltip();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ImGui::Dummy(ImVec2((longest + 2), mLines.size() * mCharAdvance.y));
|
||||
@ -1098,8 +1078,7 @@ void TextEditor::Render() {
|
||||
auto popupStack = g.OpenPopupStack;
|
||||
if (popupStack.Size > 0) {
|
||||
for (int n = 0; n < popupStack.Size; n++){
|
||||
auto window = popupStack[n].Window;
|
||||
if (window != nullptr) {
|
||||
if (auto window = popupStack[n].Window; window != nullptr) {
|
||||
if (window->Size.x == mFindReplaceHandler.GetFindWindowSize().x &&
|
||||
window->Size.y == mFindReplaceHandler.GetFindWindowSize().y &&
|
||||
window->Pos.x == mFindReplaceHandler.GetFindWindowPos().x &&
|
||||
@ -1112,11 +1091,9 @@ void TextEditor::Render() {
|
||||
mTopMargin = 0;
|
||||
}
|
||||
|
||||
static float linesAdded = 0;
|
||||
static float pixelsAdded = 0;
|
||||
static float savedScrollY = 0;
|
||||
static float shiftedScrollY = 0;
|
||||
|
||||
if (mTopMargin != oldTopMargin) {
|
||||
static float savedScrollY = 0;
|
||||
if (oldTopMargin == 0)
|
||||
savedScrollY = ImGui::GetScrollY();
|
||||
auto window = ImGui::GetCurrentWindow();
|
||||
@ -1124,6 +1101,7 @@ void TextEditor::Render() {
|
||||
if (maxScroll > 0) {
|
||||
float lineCount;
|
||||
float pixelCount;
|
||||
static float linesAdded = 0;
|
||||
if (mTopMargin > oldTopMargin) {
|
||||
pixelCount = mTopMargin - oldTopMargin;
|
||||
lineCount = pixelCount / mCharAdvance.y;
|
||||
@ -1148,6 +1126,7 @@ void TextEditor::Render() {
|
||||
else
|
||||
mLines.erase(mLines.begin() + mLines.size() - 1);
|
||||
}
|
||||
static float pixelsAdded = 0;
|
||||
if (mTopMargin > oldTopMargin) {
|
||||
linesAdded += lineCount;
|
||||
pixelsAdded += pixelCount;
|
||||
@ -1159,6 +1138,7 @@ void TextEditor::Render() {
|
||||
pixelsAdded = 0;
|
||||
}
|
||||
if (oldScrollY + pixelCount < maxScroll) {
|
||||
static float shiftedScrollY = 0;
|
||||
if (mTopMargin > oldTopMargin)
|
||||
shiftedScrollY = oldScrollY + pixelCount;
|
||||
else if (mTopMargin > 0)
|
||||
@ -1211,15 +1191,15 @@ void TextEditor::Render(const char *aTitle, const ImVec2 &aSize, bool aBorder) {
|
||||
}
|
||||
|
||||
void TextEditor::SetText(const std::string &aText) {
|
||||
mLines.clear();
|
||||
mLines.emplace_back(Line());
|
||||
mLines.resize(1);
|
||||
mLines[0].clear();
|
||||
for (auto chr : aText) {
|
||||
if (chr == '\r') {
|
||||
// ignore the carriage return character
|
||||
} else if (chr == '\n')
|
||||
mLines.emplace_back(Line());
|
||||
mLines.push_back(Line());
|
||||
else {
|
||||
mLines.back().emplace_back(Glyph(chr, PaletteIndex::Default));
|
||||
mLines.back().push_back(Glyph(chr, PaletteIndex::Default));
|
||||
}
|
||||
}
|
||||
|
||||
@ -1235,7 +1215,7 @@ void TextEditor::SetText(const std::string &aText) {
|
||||
void TextEditor::SetTextLines(const std::vector<std::string> &aLines) {
|
||||
mLines.clear();
|
||||
|
||||
if (aLines.empty()) {
|
||||
if (isEmpty()) {
|
||||
mLines.emplace_back(Line());
|
||||
} else {
|
||||
mLines.resize(aLines.size());
|
||||
@ -1281,7 +1261,7 @@ void TextEditor::EnterCharacter(ImWchar aChar, bool aShift) {
|
||||
if (end.mColumn == 0 && end.mLine > 0)
|
||||
--end.mLine;
|
||||
if (end.mLine >= (int)mLines.size())
|
||||
end.mLine = mLines.empty() ? 0 : (int)mLines.size() - 1;
|
||||
end.mLine = isEmpty() ? 0 : (int)mLines.size() - 1;
|
||||
end.mColumn = GetLineMaxColumn(end.mLine);
|
||||
|
||||
u.mRemovedStart = start;
|
||||
@ -1350,6 +1330,10 @@ void TextEditor::EnterCharacter(ImWchar aChar, bool aShift) {
|
||||
auto coord = GetActualCursorCoordinates();
|
||||
u.mAddedStart = coord;
|
||||
|
||||
|
||||
if (mLines.empty())
|
||||
mLines.push_back(Line());
|
||||
|
||||
if (aChar == '\n') {
|
||||
InsertLine(coord.mLine + 1);
|
||||
auto &line = mLines[coord.mLine];
|
||||
@ -1613,7 +1597,7 @@ void TextEditor::MoveLeft(int aAmount, bool aSelect, bool aWordMode) {
|
||||
auto oldPos = mState.mCursorPosition;
|
||||
|
||||
ResetCursorBlinkTime();
|
||||
if (mLines.empty() || oldPos.mLine >= mLines.size())
|
||||
if (isEmpty() || oldPos.mLine >= mLines.size())
|
||||
return;
|
||||
|
||||
mState.mCursorPosition = GetActualCursorCoordinates();
|
||||
@ -1670,7 +1654,7 @@ void TextEditor::MoveRight(int aAmount, bool aSelect, bool aWordMode) {
|
||||
ResetCursorBlinkTime();
|
||||
auto oldPos = mState.mCursorPosition;
|
||||
|
||||
if (mLines.empty() || oldPos.mLine >= mLines.size())
|
||||
if (isEmpty() || oldPos.mLine >= mLines.size())
|
||||
return;
|
||||
|
||||
mState.mCursorPosition = GetActualCursorCoordinates();
|
||||
@ -1796,7 +1780,7 @@ void TextEditor::Delete() {
|
||||
ResetCursorBlinkTime();
|
||||
assert(!mReadOnly);
|
||||
|
||||
if (mLines.empty())
|
||||
if (isEmpty())
|
||||
return;
|
||||
|
||||
UndoRecord u;
|
||||
@ -1853,7 +1837,7 @@ void TextEditor::Backspace() {
|
||||
ResetCursorBlinkTime();
|
||||
assert(!mReadOnly);
|
||||
|
||||
if (mLines.empty())
|
||||
if (isEmpty())
|
||||
return;
|
||||
|
||||
UndoRecord u;
|
||||
@ -1932,14 +1916,14 @@ void TextEditor::SelectAll() {
|
||||
}
|
||||
|
||||
bool TextEditor::HasSelection() const {
|
||||
return mState.mSelectionEnd > mState.mSelectionStart;
|
||||
return !isEmpty() && mState.mSelectionEnd > mState.mSelectionStart;
|
||||
}
|
||||
|
||||
void TextEditor::Copy() {
|
||||
if (HasSelection()) {
|
||||
ImGui::SetClipboardText(GetSelectedText().c_str());
|
||||
} else {
|
||||
if (!mLines.empty()) {
|
||||
if (!isEmpty()) {
|
||||
std::string str;
|
||||
auto &line = mLines[GetActualCursorCoordinates().mLine];
|
||||
for (auto &g : line)
|
||||
@ -2165,13 +2149,13 @@ std::string make_wholeWord(const std::string &s) {
|
||||
}
|
||||
|
||||
// Performs actual search to fill mMatches
|
||||
bool TextEditor::FindReplaceHandler::FindNext(TextEditor *editor, bool wrapAround) {
|
||||
bool TextEditor::FindReplaceHandler::FindNext(TextEditor *editor) {
|
||||
Coordinates curPos;
|
||||
curPos.mLine = mMatches.empty() ? editor->mState.mCursorPosition.mLine : mMatches.back().mCursorPosition.mLine;
|
||||
curPos.mColumn = mMatches.empty() ? editor->mState.mCursorPosition.mColumn : editor->Utf8CharsToBytes(
|
||||
mMatches.back().mCursorPosition);
|
||||
|
||||
unsigned long selectionLength = editor->GetStringCharacterCount(mFindWord);
|
||||
unsigned long matchLength = editor->GetStringCharacterCount(mFindWord);
|
||||
size_t byteIndex = 0;
|
||||
|
||||
for (size_t ln = 0; ln < curPos.mLine; ln++)
|
||||
@ -2218,67 +2202,32 @@ bool TextEditor::FindReplaceHandler::FindNext(TextEditor *editor, bool wrapAroun
|
||||
|
||||
if(firstLoc > byteIndex) {
|
||||
pos = firstLoc;
|
||||
selectionLength = firstLength;
|
||||
matchLength = firstLength;
|
||||
} else {
|
||||
|
||||
while (iter != end) {
|
||||
iter++;
|
||||
if (((pos = iter->position()) > byteIndex) && ((selectionLength = iter->length()) > 0))
|
||||
if (((pos = iter->position()) > byteIndex) && ((matchLength = iter->length()) > 0))
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (iter == end && !wrapAround)
|
||||
if (iter == end)
|
||||
return false;
|
||||
|
||||
textLoc = pos;
|
||||
if (wrapAround) {
|
||||
if (iter == end)
|
||||
selectionLength = firstLength;
|
||||
}
|
||||
} else {
|
||||
// non regex search
|
||||
textLoc = textSrc.find(wordLower, byteIndex);
|
||||
if (textLoc == std::string::npos) {
|
||||
if (wrapAround)
|
||||
textLoc = textSrc.find(wordLower, 0);
|
||||
else
|
||||
return false;
|
||||
}
|
||||
if (textLoc == std::string::npos)
|
||||
return false;
|
||||
}
|
||||
if (textLoc != std::string::npos) {
|
||||
curPos.mLine = curPos.mColumn = 0;
|
||||
byteIndex = 0;
|
||||
|
||||
for (size_t ln = 0; ln < editor->mLines.size(); ln++) {
|
||||
auto byteCount = editor->GetLineByteCount(ln) + 1;
|
||||
|
||||
if (byteIndex + byteCount > textLoc) {
|
||||
curPos.mLine = ln;
|
||||
curPos.mColumn = textLoc - byteIndex;
|
||||
|
||||
auto &line = editor->mLines[curPos.mLine];
|
||||
int lineSize = line.size();
|
||||
for (int i = 0; i < std::min(lineSize,curPos.mColumn); i++) {
|
||||
if (line[i].mChar == '\t')
|
||||
curPos.mColumn += (editor->mTabSize - 1);
|
||||
}
|
||||
break;
|
||||
} else {// just keep adding
|
||||
byteIndex += byteCount;
|
||||
}
|
||||
}
|
||||
} else
|
||||
if (textLoc == std::string::npos)
|
||||
return false;
|
||||
Coordinates selStart, selEnd;
|
||||
selStart.mLine = curPos.mLine;
|
||||
selStart.mColumn = editor->Utf8BytesToChars(curPos);
|
||||
selEnd = selStart;
|
||||
selEnd.mColumn += selectionLength;
|
||||
TextEditor::EditorState state;
|
||||
state.mSelectionStart = selStart;
|
||||
state.mSelectionEnd = selEnd;
|
||||
state.mCursorPosition = selEnd;
|
||||
state.mSelectionStart = editor->StringIndexToCoordinates(textLoc,textSrc);
|
||||
state.mSelectionEnd = editor->StringIndexToCoordinates(textLoc + matchLength,textSrc);
|
||||
state.mCursorPosition = state.mSelectionEnd;
|
||||
mMatches.push_back(state);
|
||||
return true;
|
||||
}
|
||||
@ -2305,7 +2254,7 @@ void TextEditor::FindReplaceHandler::FindAllMatches(TextEditor *editor,std::stri
|
||||
Coordinates begin = Coordinates(0,0);
|
||||
editor->mState.mCursorPosition = begin;
|
||||
|
||||
if (!FindNext(editor,false)) {
|
||||
if (!FindNext(editor)) {
|
||||
editor->mState = saveState;
|
||||
editor->EnsureCursorVisible();
|
||||
return;
|
||||
@ -2313,7 +2262,7 @@ void TextEditor::FindReplaceHandler::FindAllMatches(TextEditor *editor,std::stri
|
||||
TextEditor::EditorState state = mMatches.back();
|
||||
|
||||
while( state.mCursorPosition < startingPos) {
|
||||
if (!FindNext(editor,false)) {
|
||||
if (!FindNext(editor)) {
|
||||
editor->mState = saveState;
|
||||
editor->EnsureCursorVisible();
|
||||
return;
|
||||
@ -2321,7 +2270,7 @@ void TextEditor::FindReplaceHandler::FindAllMatches(TextEditor *editor,std::stri
|
||||
state = mMatches.back();
|
||||
}
|
||||
|
||||
while (FindNext(editor,false));
|
||||
while (FindNext(editor));
|
||||
|
||||
editor->mState = saveState;
|
||||
editor->EnsureCursorVisible();
|
||||
@ -2538,7 +2487,7 @@ void TextEditor::Colorize(int aFromLine, int aLines) {
|
||||
}
|
||||
|
||||
void TextEditor::ColorizeRange(int aFromLine, int aToLine) {
|
||||
if (mLines.empty() || aFromLine >= aToLine)
|
||||
if (isEmpty() || aFromLine >= aToLine)
|
||||
return;
|
||||
|
||||
std::string buffer;
|
||||
@ -2628,7 +2577,7 @@ void TextEditor::ColorizeRange(int aFromLine, int aToLine) {
|
||||
}
|
||||
|
||||
void TextEditor::ColorizeInternal() {
|
||||
if (mLines.empty() || !mColorizerEnabled)
|
||||
if (isEmpty() || !mColorizerEnabled)
|
||||
return;
|
||||
|
||||
if (mCheckComments) {
|
||||
|
Loading…
Reference in New Issue
Block a user