Improve "Remove consecutive duplicate lines" command performance

Rewrite "Remove consecutive duplicate lines" without using regex.

Fix #5538, fix #12548, close #13558
This commit is contained in:
ArkadiuszMichalski 2023-04-20 16:27:55 +02:00 committed by Don Ho
parent 5f2e93ee5f
commit ecb10712c1
1 changed files with 73 additions and 14 deletions

View File

@ -1676,22 +1676,81 @@ void Notepad_plus::removeEmptyLine(bool isBlankContained)
void Notepad_plus::removeDuplicateLines()
{
// whichPart : line head or line tail
FindOption env;
intptr_t mainSelAnchor = _pEditView->execute(SCI_GETANCHOR);
intptr_t mainSelCaretPos = _pEditView->execute(SCI_GETCURRENTPOS);
bool isEntireDoc = (mainSelAnchor == mainSelCaretPos);
env._str2Search = TEXT("^([^\\r\\n]*(?>\\r?\\n|\\r))(?>\\1)+");
env._str4Replace = TEXT("\\1");
env._searchType = FindRegex;
auto mainSelStart = _pEditView->execute(SCI_GETSELECTIONSTART);
auto mainSelEnd = _pEditView->execute(SCI_GETSELECTIONEND);
auto mainSelLength = mainSelEnd - mainSelStart;
bool isEntireDoc = mainSelLength == 0;
env._isInSelection = !isEntireDoc;
_findReplaceDlg.processAll(ProcessReplaceAll, &env, isEntireDoc);
intptr_t startLine = 0;
intptr_t endLine = _pEditView->lastZeroBasedLineNumber();
if (!isEntireDoc)
{
intptr_t startPos = _pEditView->execute(SCI_GETSELECTIONSTART);
startLine = _pEditView->execute(SCI_LINEFROMPOSITION, startPos);
intptr_t endPos = _pEditView->execute(SCI_GETSELECTIONEND);
endLine = _pEditView->execute(SCI_LINEFROMPOSITION, endPos);
if (endPos == _pEditView->execute(SCI_POSITIONFROMLINE, endLine))
endLine -= 1;
}
if (startLine == endLine)
return;
intptr_t firstMatchLineNr = 0;
intptr_t lastMatchLineNr = 0;
generic_string firstMatchLineStr;
generic_string lastMatchLineStr;
for (intptr_t i = startLine; i <= endLine; i++)
{
if (firstMatchLineStr.empty())
{
firstMatchLineNr = lastMatchLineNr = i;
firstMatchLineStr = _pEditView->getLine(i);
continue;
}
else
lastMatchLineStr = _pEditView->getLine(i);
if (firstMatchLineStr == lastMatchLineStr)
{
lastMatchLineNr = i;
if (i != endLine)
continue;
}
if (firstMatchLineNr != lastMatchLineNr)
{
intptr_t startPos = _pEditView->execute(SCI_POSITIONFROMLINE, firstMatchLineNr + 1);
intptr_t endPos = _pEditView->execute(SCI_POSITIONFROMLINE, lastMatchLineNr) + _pEditView->execute(SCI_LINELENGTH, lastMatchLineNr);
_pEditView->execute(SCI_DELETERANGE, startPos, endPos - startPos);
intptr_t removedLines = lastMatchLineNr - firstMatchLineNr;
i -= removedLines;
endLine -= removedLines;
}
firstMatchLineStr = lastMatchLineStr;
firstMatchLineNr = lastMatchLineNr = i;
}
// correct the last line (without EOL) if it's a duplicate line
intptr_t endLineStartPos = _pEditView->execute(SCI_POSITIONFROMLINE, endLine);
intptr_t endLineEndPos = _pEditView->execute(SCI_GETLINEENDPOSITION, endLine);
intptr_t endLineLength = _pEditView->execute(SCI_LINELENGTH, endLine);
if (endLine == _pEditView->lastZeroBasedLineNumber() && endLineLength && ((endLineEndPos - endLineStartPos) == endLineLength))
{
intptr_t prevLine = endLine - 1;
intptr_t prevLineStartPos = _pEditView->execute(SCI_POSITIONFROMLINE, prevLine);
intptr_t prevLineEndPos = _pEditView->execute(SCI_GETLINEENDPOSITION, prevLine);
intptr_t prevLineLength = _pEditView->execute(SCI_LINELENGTH, prevLine);
const generic_string endLineStr = _pEditView->getLine(endLine);
const generic_string prevLineStr = _pEditView->getGenericTextAsString(prevLineStartPos, prevLineEndPos);
if (endLineStr == prevLineStr)
_pEditView->execute(SCI_DELETERANGE, prevLineStartPos, prevLineLength);
}
// remove the last line if it's a duplicate line.
env._str2Search = TEXT("^([^\\r\\n]+)(?>\\r?\\n|\\r)(?>\\1)$");
_findReplaceDlg.processAll(ProcessReplaceAll, &env, isEntireDoc);
}
void Notepad_plus::getMatchedFileNames(const TCHAR *dir, size_t level, const vector<generic_string> & patterns, vector<generic_string> & fileNames, bool isRecursive, bool isInHiddenDir)