kde-workspace/kate/part/search/kateplaintextsearch.cpp
Ivailo Monev f68295ea28 generic: move sub-projects from kde-baseapps [ci reset]
Signed-off-by: Ivailo Monev <xakepa10@gmail.com>
2022-05-14 21:56:54 +03:00

145 lines
5.1 KiB
C++

/* This file is part of the KDE libraries and the Kate part.
*
* Copyright (C) 2009-2010 Bernhard Beschow <bbeschow@cs.tu-berlin.de>
* Copyright (C) 2007 Sebastian Pipping <webmaster@hartwork.org>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Library General Public
* License as published by the Free Software Foundation; either
* version 2 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Library General Public License for more details.
*
* You should have received a copy of the GNU Library General Public License
* along with this library; see the file COPYING.LIB. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
//BEGIN includes
#include "kateplaintextsearch.h"
#include "kateregexpsearch.h"
#include <ktexteditor/document.h>
#include <kdebug.h>
//END includes
//BEGIN d'tor, c'tor
//
// KateSearch Constructor
//
KatePlainTextSearch::KatePlainTextSearch ( KTextEditor::Document *document, Qt::CaseSensitivity caseSensitivity, bool wholeWords )
: m_document (document)
, m_caseSensitivity (caseSensitivity)
, m_wholeWords (wholeWords)
{
}
//
// KateSearch Destructor
//
KatePlainTextSearch::~KatePlainTextSearch()
{
}
//END
KTextEditor::Range KatePlainTextSearch::search (const QString & text, const KTextEditor::Range & inputRange, bool backwards)
{
// abuse regex for whole word plaintext search
if (m_wholeWords)
{
// escape dot and friends
const QString workPattern = "\\b" + QRegExp::escape(text) + "\\b";
return KateRegExpSearch(m_document, m_caseSensitivity).search(workPattern, inputRange, backwards)[0];
}
if (text.isEmpty() || !inputRange.isValid() || (inputRange.start() == inputRange.end()))
{
return KTextEditor::Range::invalid();
}
// split multi-line needle into single lines
const QStringList needleLines = text.split("\n");
if (needleLines.count() > 1)
{
// multi-line plaintext search (both forwards or backwards)
const int forMin = inputRange.start().line(); // first line in range
const int forMax = inputRange.end().line() + 1 - needleLines.count(); // last line in range
const int forInit = backwards ? forMax : forMin;
const int forInc = backwards ? -1 : +1;
for (int j = forInit; (forMin <= j) && (j <= forMax); j += forInc)
{
// try to match all lines
const int startCol = m_document->lineLength(j) - needleLines[0].length();
for (int k = 0; k < needleLines.count(); k++)
{
// which lines to compare
const QString & needleLine = needleLines[k];
const QString & hayLine = m_document->line(j + k);
// position specific comparison (first, middle, last)
if (k == 0) {
// first line
if (forMin == j && startCol < inputRange.start().column())
break;
if (!hayLine.endsWith(needleLine, m_caseSensitivity))
break;
} else if (k == needleLines.count() - 1) {
// last line
const int maxRight = (j + k == inputRange.end().line()) ? inputRange.end().column() : hayLine.length();
if (hayLine.startsWith(needleLine, m_caseSensitivity) && needleLine.length() <= maxRight)
return KTextEditor::Range(j, startCol, j + k, needleLine.length());
} else {
// mid lines
if (hayLine.compare(needleLine, m_caseSensitivity) != 0) {
break;
}
}
}
}
// not found
return KTextEditor::Range::invalid();
}
else
{
// single-line plaintext search (both forward of backward mode)
const int startCol = inputRange.start().column();
const int endCol = inputRange.end().column(); // first not included
const int startLine = inputRange.start().line();
const int endLine = inputRange.end().line();
const int forInc = backwards ? -1 : +1;
for (int line = backwards ? endLine : startLine; (startLine <= line) && (line <= endLine); line += forInc)
{
if ((line < 0) || (m_document->lines() <= line))
{
kWarning() << "line " << line << " is not within interval [0.." << m_document->lines() << ") ... returning invalid range";
return KTextEditor::Range::invalid();
}
const QString textLine = m_document->line(line);
const int offset = (line == startLine) ? startCol : 0;
const int line_end = (line == endLine) ? endCol : textLine.length();
const int foundAt = backwards ? textLine.lastIndexOf(text, line_end-text.length(), m_caseSensitivity) :
textLine.indexOf(text, offset, m_caseSensitivity);
if ((offset <= foundAt) && (foundAt + text.length() <= line_end))
return KTextEditor::Range(line, foundAt, line, foundAt + text.length());
}
}
return KTextEditor::Range::invalid();
}
// kate: space-indent on; indent-width 2; replace-tabs on;