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