KTextEditor

kateplaintextsearch.cpp
1/*
2 SPDX-FileCopyrightText: 2009-2010 Bernhard Beschow <bbeschow@cs.tu-berlin.de>
3 SPDX-FileCopyrightText: 2007 Sebastian Pipping <webmaster@hartwork.org>
4
5 SPDX-License-Identifier: LGPL-2.0-or-later
6*/
7
8// BEGIN includes
9#include "kateplaintextsearch.h"
10
11#include "katepartdebug.h"
12#include "kateregexpsearch.h"
13#include <ktexteditor/document.h>
14
15#include <QRegularExpression>
16// END includes
17
18// BEGIN d'tor, c'tor
19//
20// KateSearch Constructor
21//
22KatePlainTextSearch::KatePlainTextSearch(const KTextEditor::Document *document, Qt::CaseSensitivity caseSensitivity, bool wholeWords)
23 : m_document(document)
24 , m_caseSensitivity(caseSensitivity)
25 , m_wholeWords(wholeWords)
26{
27}
28
29// END
30
32{
33 // abuse regex for whole word plaintext search
34 if (m_wholeWords) {
35 // escape dot and friends
36 const QString workPattern = QStringLiteral("\\b%1\\b").arg(QRegularExpression::escape(text));
37
40
41 return KateRegExpSearch(m_document).search(workPattern, inputRange, backwards, options).at(0);
42 }
43
44 if (text.isEmpty() || !inputRange.isValid() || (inputRange.start() == inputRange.end())) {
46 }
47
48 // split multi-line needle into single lines
49 const QList<QStringView> needleLines = QStringView(text).split(QLatin1Char('\n'));
50
51 if (needleLines.count() > 1) {
52 // multi-line plaintext search (both forwards or backwards)
53 const int forMin = inputRange.start().line(); // first line in range
54 const int forMax = inputRange.end().line() + 1 - needleLines.count(); // last line in range
55 const int forInit = backwards ? forMax : forMin;
56 const int forInc = backwards ? -1 : +1;
57
58 for (int j = forInit; (forMin <= j) && (j <= forMax); j += forInc) {
59 // try to match all lines
60 const int startCol = m_document->lineLength(j) - needleLines[0].length();
61 for (int k = 0; k < needleLines.count(); k++) {
62 // which lines to compare
63 const auto &needleLine = needleLines[k];
64 const QString &hayLine = m_document->line(j + k);
65
66 // position specific comparison (first, middle, last)
67 if (k == 0) {
68 // first line
69 if (forMin == j && startCol < inputRange.start().column()) {
70 break;
71 }
72
73 // NOTE: QString("")::endsWith("") is false in Qt, therefore we need the additional checks.
74 const bool endsWith = hayLine.endsWith(needleLine, m_caseSensitivity) || (hayLine.isEmpty() && needleLine.isEmpty());
75 if (!endsWith) {
76 break;
77 }
78 } else if (k == needleLines.count() - 1) {
79 // last line
80 const int maxRight = (j + k == inputRange.end().line()) ? inputRange.end().column() : hayLine.length();
81
82 // NOTE: QString("")::startsWith("") is false in Qt, therefore we need the additional checks.
83 const bool startsWith = hayLine.startsWith(needleLine, m_caseSensitivity) || (hayLine.isEmpty() && needleLine.isEmpty());
84 if (startsWith && needleLine.length() <= maxRight) {
85 return KTextEditor::Range(j, startCol, j + k, needleLine.length());
86 }
87 } else {
88 // mid lines
89 if (hayLine.compare(needleLine, m_caseSensitivity) != 0) {
90 break;
91 }
92 }
93 }
94 }
95
96 // not found
98 } else {
99 // single-line plaintext search (both forward of backward mode)
100 const int startCol = inputRange.start().column();
101 const int endCol = inputRange.end().column(); // first not included
102 const int startLine = inputRange.start().line();
103 const int endLine = inputRange.end().line();
104 const int forInc = backwards ? -1 : +1;
105
106 for (int line = backwards ? endLine : startLine; (startLine <= line) && (line <= endLine); line += forInc) {
107 if ((line < 0) || (m_document->lines() <= line)) {
108 qCWarning(LOG_KTE) << "line " << line << " is not within interval [0.." << m_document->lines() << ") ... returning invalid range";
110 }
111
112 const QString textLine = m_document->line(line);
113
114 const int offset = (line == startLine) ? startCol : 0;
115 const int line_end = (line == endLine) ? endCol : textLine.length();
116 const int foundAt =
117 backwards ? textLine.lastIndexOf(text, line_end - text.length(), m_caseSensitivity) : textLine.indexOf(text, offset, m_caseSensitivity);
118
119 if ((offset <= foundAt) && (foundAt + text.length() <= line_end)) {
120 return KTextEditor::Range(line, foundAt, line, foundAt + text.length());
121 }
122 }
123 }
125}
constexpr int column() const noexcept
Retrieve the column on which this cursor is situated.
Definition cursor.h:192
constexpr int line() const noexcept
Retrieve the line on which this cursor is situated.
Definition cursor.h:174
A KParts derived class representing a text document.
Definition document.h:284
virtual QString line(int line) const =0
Get a single text line.
virtual int lines() const =0
Get the count of lines of the document.
virtual int lineLength(int line) const =0
Get the length of a given line in characters.
An object representing a section of text, from one Cursor to another.
constexpr Cursor end() const noexcept
Get the end position of this range.
constexpr Cursor start() const noexcept
Get the start position of this range.
static constexpr Range invalid() noexcept
Returns an invalid range.
constexpr bool isValid() const noexcept
Validity check.
KTextEditor::Range search(const QString &text, KTextEditor::Range inputRange, bool backwards=false)
Search for the given text inside the range inputRange taking into account whether to search casesensi...
Object to help to search for regexp.
QList< KTextEditor::Range > search(const QString &pattern, KTextEditor::Range inputRange, bool backwards=false, QRegularExpression::PatternOptions options=QRegularExpression::NoPatternOption)
Search for the regular expression pattern inside the range inputRange.
const_reference at(qsizetype i) const const
qsizetype count() const const
qsizetype length() const const
QString escape(QStringView str)
QString arg(Args &&... args) const const
int compare(QLatin1StringView s1, const QString &s2, Qt::CaseSensitivity cs)
bool endsWith(QChar c, Qt::CaseSensitivity cs) const const
qsizetype indexOf(QChar ch, qsizetype from, Qt::CaseSensitivity cs) const const
bool isEmpty() const const
qsizetype lastIndexOf(QChar ch, Qt::CaseSensitivity cs) const const
qsizetype length() const const
bool startsWith(QChar c, Qt::CaseSensitivity cs) const const
QList< QStringView > split(QChar sep, Qt::SplitBehavior behavior, Qt::CaseSensitivity cs) const const
CaseSensitivity
This file is part of the KDE documentation.
Documentation copyright © 1996-2024 The KDE developers.
Generated on Fri Jul 12 2024 11:53:31 by doxygen 1.11.0 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.