34 #ifdef FAST_DEBUG_ENABLE
35 # define FAST_DEBUG(x) kDebug( 13020 ) << x
37 # define FAST_DEBUG(x)
41 class KateRegExpSearch::ReplacementStream
45 counter(
int value,
int minWidth)
71 ReplacementStream(
const QStringList &capturedTexts);
73 QString str()
const {
return m_str; }
76 ReplacementStream &
operator<<(
const counter &);
82 CaseConversion m_caseConversion;
87 KateRegExpSearch::ReplacementStream::ReplacementStream(
const QStringList &capturedTexts)
88 : m_capturedTexts(capturedTexts)
89 , m_caseConversion(keepCase)
95 switch (m_caseConversion) {
98 m_str.append(str.toUpper());
102 if (str.length() > 0) {
103 m_str.append(str.at(0).toUpper());
104 m_str.append(str.mid(1));
105 m_caseConversion = keepCase;
111 m_str.append(str.toLower());
115 if (str.length() > 0) {
116 m_str.append(str.at(0).toLower());
117 m_str.append(str.mid(1));
118 m_caseConversion = keepCase;
137 m_str.append(
QString(
"%1").arg(c.value, c.minWidth, 10, QLatin1Char(
'0')));
145 if (0 <= cap.n && cap.n < m_capturedTexts.size()) {
146 (*this) << m_capturedTexts[cap.n];
149 m_str.append(QString::number(cap.n));
158 m_caseConversion = caseConversion;
169 : m_document (document)
170 , m_caseSensitivity (caseSensitivity)
183 struct TwoViewCursor {
207 KateRegExp regexp(pattern, m_caseSensitivity);
211 QVector<KTextEditor::Range> result;
221 const bool dotMatchesNewline =
false;
223 if (dotMatchesNewline && (replacements > 0))
228 const int firstLineIndex = inputRange.
start().
line();
229 const int minColStart = inputRange.
start().
column();
235 const int inputLineCount = inputRange.
end().
line() - inputRange.
start().
line() + 1;
236 FAST_DEBUG(
"multi line search (lines " << firstLineIndex <<
".." << firstLineIndex + inputLineCount - 1 <<
")");
239 if (firstLineIndex >= m_document->
lines())
241 QVector<KTextEditor::Range> result;
246 QVector<int> lineLens (inputLineCount);
249 if (firstLineIndex < 0 || m_document->lines() <= firstLineIndex)
251 QVector<KTextEditor::Range> result;
256 const QString firstLine = m_document->
line(firstLineIndex);
258 const int firstLineLen = firstLine.length() - minColStart;
259 wholeDocument.append(firstLine.right(firstLineLen));
260 lineLens[0] = firstLineLen;
261 FAST_DEBUG(
" line" << 0 <<
"has length" << lineLens[0]);
265 for (
int i = 1; i < inputLineCount; i++)
267 const int lineNum = firstLineIndex + i;
268 if (lineNum < 0 || m_document->lines() <= lineNum)
270 QVector<KTextEditor::Range> result;
276 lineLens[i] = text.length();
277 wholeDocument.append(sep);
278 wholeDocument.append(text);
279 FAST_DEBUG(
" line" << i <<
"has length" << lineLens[i]);
282 const int pos = backwards
283 ? regexp.
lastIndexIn(wholeDocument, 0, wholeDocument.length())
284 : regexp.
indexIn(wholeDocument, 0, wholeDocument.length());
290 QVector<KTextEditor::Range> result;
296 #ifdef FAST_DEBUG_ENABLE
298 FAST_DEBUG(
"found at relative pos " << pos <<
", length " << matchLen);
305 QVector<IndexPair> indexPairs(1 + numCaptures);
306 for (
int z = 0; z <= numCaptures; z++)
308 const int openIndex = regexp.
pos(z);
309 IndexPair & pair = indexPairs[z];
314 pair.closeIndex = -1;
319 const int closeIndex = openIndex + regexp.
cap(z).length();
320 pair.openIndex = openIndex;
321 pair.closeIndex = closeIndex;
322 FAST_DEBUG(
"capture [" << pair.openIndex <<
".." << pair.closeIndex <<
"]");
325 if (!indicesToCursors.contains(openIndex))
327 TwoViewCursor * twoViewCursor =
new TwoViewCursor;
328 twoViewCursor->index = openIndex;
329 indicesToCursors.insert(openIndex, twoViewCursor);
330 FAST_DEBUG(
" border index added: " << openIndex);
332 if (!indicesToCursors.contains(closeIndex))
334 TwoViewCursor * twoViewCursor =
new TwoViewCursor;
335 twoViewCursor->index = closeIndex;
336 indicesToCursors.insert(closeIndex, twoViewCursor);
337 FAST_DEBUG(
" border index added: " << closeIndex);
347 while (iter != indicesToCursors.constEnd())
350 const int index = (*iter)->index;
352 TwoViewCursor & twoViewCursor = *(*iter);
353 while (curRelIndex <= index)
355 FAST_DEBUG(
"walk pos (" << curRelLine <<
"," << curRelCol <<
") = "
356 << curRelIndex <<
"relative, steps more to go" << index - curRelIndex);
357 const int curRelLineLen = lineLens[curRelLine];
358 const int curLineRemainder = curRelLineLen - curRelCol;
359 const int lineFeedIndex = curRelIndex + curLineRemainder;
360 if (index <= lineFeedIndex) {
361 if (index == lineFeedIndex) {
364 const int absLine = curRelLine + firstLineIndex;
365 twoViewCursor.openLine
366 = twoViewCursor.closeLine
368 twoViewCursor.openCol
369 = twoViewCursor.closeCol
370 = ((curRelLine == 0) ? minColStart : 0) + curRelLineLen;
373 const int advance = (index - curRelIndex) + 1;
376 curRelIndex += advance;
380 const int diff = (index - curRelIndex);
381 const int absLine = curRelLine + firstLineIndex;
382 const int absCol = ((curRelLine == 0) ? minColStart : 0) + curRelCol + diff;
383 twoViewCursor.openLine
384 = twoViewCursor.closeLine
386 twoViewCursor.openCol
387 = twoViewCursor.closeCol
391 const int advance = diff + 1;
392 curRelCol += advance;
393 curRelIndex += advance;
395 FAST_DEBUG(
"open(" << twoViewCursor.openLine <<
"," << twoViewCursor.openCol
396 <<
") close(" << twoViewCursor.closeLine <<
"," << twoViewCursor.closeCol <<
")");
403 const int advance = curLineRemainder + 1;
406 curRelIndex += advance;
414 QVector<KTextEditor::Range> result(1 + numCaptures);
415 for (
int y = 0; y <= numCaptures; y++)
417 IndexPair & pair = indexPairs[y];
418 if ((pair.openIndex == -1) || (pair.closeIndex == -1))
424 const TwoViewCursor *
const openCursors = indicesToCursors[pair.openIndex];
425 const TwoViewCursor *
const closeCursors = indicesToCursors[pair.closeIndex];
426 const int startLine = openCursors->openLine;
427 const int startCol = openCursors->openCol;
428 const int endLine = closeCursors->closeLine;
429 const int endCol = closeCursors->closeCol;
430 FAST_DEBUG(
"range " << y <<
": (" << startLine <<
", " << startCol <<
")..(" << endLine <<
", " << endCol <<
")");
436 iter = indicesToCursors.constBegin();
437 while (iter != indicesToCursors.constEnd())
439 TwoViewCursor *
const twoViewCursor = *iter;
440 delete twoViewCursor;
449 const uint maxRight = inputRange.
end().
column();
450 const int forMin = inputRange.
start().
line();
451 const int forMax = inputRange.
end().
line();
452 const int forInit = backwards ? forMax : forMin;
453 const int forInc = backwards ? -1 : +1;
454 FAST_DEBUG(
"single line " << (backwards ? forMax : forMin) <<
".."
455 << (backwards ? forMin : forMax));
456 for (
int j = forInit; (forMin <= j) && (j <= forMax); j += forInc)
458 if (j < 0 || m_document->lines() <= j)
460 FAST_DEBUG(
"searchText | line " << j <<
": no");
461 QVector<KTextEditor::Range> result;
468 const int first = (j == forMin) ? minLeft : 0;
469 const int last = (j == forMax) ? maxRight : textLine.length();
470 const int foundAt = (backwards ? regexp.
lastIndexIn(textLine, first, last)
471 : regexp.
indexIn(textLine, first, last));
472 const bool found = (foundAt != -1);
497 QVector<KTextEditor::Range> result(1 + numCaptures);
499 FAST_DEBUG(
"result range " << 0 <<
": (" << j <<
", " << foundAt <<
")..(" << j <<
", " <<
501 for (
int y = 1; y <= numCaptures; y++)
503 const int openIndex = regexp.
pos(y);
511 const int closeIndex = openIndex + regexp.
cap(y).length();
512 FAST_DEBUG(
"result range " << y <<
": (" << j <<
", " << openIndex <<
")..(" << j <<
", " << closeIndex <<
")");
520 FAST_DEBUG(
"searchText | line " << j <<
": no");
525 QVector<KTextEditor::Range> result;
545 const int inputLen = text.length();
549 ReplacementStream out(capturedTexts);
551 while (input < inputLen)
553 switch (text[input].unicode())
561 if (input + 1 >= inputLen)
569 switch (text[input + 1].unicode())
572 if (input + 4 >= inputLen)
574 out << ReplacementStream::cap(0);
579 bool stripAndSkip =
false;
580 const ushort text_2 = text[input + 2].unicode();
581 if ((text_2 >= L
'0') && (text_2 <= L
'3'))
583 const ushort text_3 = text[input + 3].unicode();
584 if ((text_3 >= L
'0') && (text_3 <= L
'7'))
586 const ushort text_4 = text[input + 4].unicode();
587 if ((text_4 >= L
'0') && (text_4 <= L
'7'))
590 for (
int i = 0; i < 3; i++)
592 digits[i] = 7 - (L
'7' - text[input + 2 + i].unicode());
594 const int ch = 64 * digits[0] + 8 * digits[1] + digits[2];
615 out << ReplacementStream::cap(0);
630 out << ReplacementStream::cap(9 - (L
'9' - text[input + 1].unicode()));
639 if (!replacementGoodies) {
641 out << text[input + 1];
644 switch (text[input + 1].unicode()) {
646 out << ReplacementStream::lowerCase;
650 out << ReplacementStream::lowerCaseFirst;
654 out << ReplacementStream::upperCase;
658 out << ReplacementStream::upperCaseFirst;
663 out << ReplacementStream::keepCase;
671 if (!replacementGoodies) {
673 out << text[input + 1];
680 while ((input + minWidth + 1 < inputLen) && (text[input + minWidth + 1].unicode() == L
'#')) {
683 out << ReplacementStream::counter(replacementCounter, minWidth);
684 input += 1 + minWidth;
719 if (input + 5 >= inputLen)
722 out << text[input + 1];
727 bool stripAndSkip =
false;
728 const ushort text_2 = text[input + 2].unicode();
729 if (((text_2 >= L
'0') && (text_2 <= L
'9'))
730 || ((text_2 >= L
'a') && (text_2 <= L
'f'))
731 || ((text_2 >= L
'A') && (text_2 <= L
'F')))
733 const ushort text_3 = text[input + 3].unicode();
734 if (((text_3 >= L
'0') && (text_3 <= L
'9'))
735 || ((text_3 >= L
'a') && (text_3 <= L
'f'))
736 || ((text_3 >= L
'A') && (text_3 <= L
'F')))
738 const ushort text_4 = text[input + 4].unicode();
739 if (((text_4 >= L
'0') && (text_4 <= L
'9'))
740 || ((text_4 >= L
'a') && (text_4 <= L
'f'))
741 || ((text_4 >= L
'A') && (text_4 <= L
'F')))
743 const ushort text_5 = text[input + 5].unicode();
744 if (((text_5 >= L
'0') && (text_5 <= L
'9'))
745 || ((text_5 >= L
'a') && (text_5 <= L
'f'))
746 || ((text_5 >= L
'A') && (text_5 <= L
'F')))
749 for (
int i = 0; i < 4; i++)
751 const ushort cur = text[input + 2 + i].unicode();
752 if ((cur >= L
'0') && (cur <= L
'9'))
754 digits[i] = 9 - (L
'9' - cur);
756 else if ((cur >= L
'a') && (cur <= L
'f'))
758 digits[i] = 15 - (L
'f' - cur);
762 digits[i] = 15 - (L
'F' - cur);
766 const int ch = 4096 * digits[0] + 256 * digits[1] + 16 * digits[2] + digits[3];
789 out << text[input + 1];
797 out << text[input + 1];
815 #ifdef FAST_DEBUG_ENABLE
816 # undef FAST_DEBUG_ENABLE
int lastIndexIn(const QString &str, int offset, int end) const
This function is a replacement for QRegExp.lastIndexIn that returns the last match that would have be...
static QString buildReplacement(const QString &text, const QStringList &capturedTexts, int replacementCounter)
Returns a modified version of text where.
int repairPattern(bool &stillMultiLine)
Repairs a regular Expression pattern.
virtual bool isValid() const
int matchedLength() const
static QString escapePlaintext(const QString &text)
Returns a modified version of text where escape sequences are resolved, e.g.
QString cap(int nth=0) const
QDebug operator<<(QDebug s, KDebugStreamFunction f)
KateRegExpSearch(KTextEditor::Document *document, Qt::CaseSensitivity caseSensitivity)
virtual QString line(int line) const =0
QVector< KTextEditor::Range > search(const QString &pattern, const KTextEditor::Range &inputRange, bool backwards=false)
Search for the regular expression regexp inside the range inputRange.
int indexIn(const QString &str, int offset, int end) const
virtual int lines() const =0