[prev in list] [next in list] [prev in thread] [next in thread] 

List:       kwrite-devel
Subject:    Re: First byte for replace
From:       Sebastian Pipping <webmaster () hartwork ! org>
Date:       2007-07-19 2:05:40
Message-ID: 469EC6F4.5000201 () hartwork ! org
[Download RAW message or body]

More replace bytes:

   * support for capture references

   * bug in escape sequence resolution algorithm fixed
     (broken example: "\00\\n"->"00\\n")


Replacing empty lines and doing this like this
is now possible:

    SEARCH    (.+)\n(.+)

    REPLACE   first line: "\1"\nsecond line: "\2"\n
              illegal index: "\3"\nfull match: "\0"

(On a single line, wrapped to fit e-mail)



Sebastian



["katepart_replace_r689703.diff" (text/x-patch)]

Index: utils/katesearchbar.cpp
===================================================================
--- utils/katesearchbar.cpp	(revision 689703)
+++ utils/katesearchbar.cpp	(working copy)
@@ -30,6 +30,7 @@
 #include <QtGui/QCheckBox>
 #include <QtGui/QComboBox>
 #include <QtGui/QKeyEvent>
+#include <QtGui/QPushButton> // just for replace buttons, remove if class changes
 #include <QtCore/QList>
 
 #include <kdebug.h>
@@ -41,6 +42,7 @@
     KTextEditor::Range match;
     KTextEditor::Range lastMatch;
     KateSearchBarEdit *expressionEdit;
+    KLineEdit * replaceEdit;
 
     QCheckBox *caseSensitiveBox;
     //QCheckBox *wholeWordsBox;
@@ -56,6 +58,7 @@
     KTextEditor::SmartRange* topRange;
 
     QString lastExpression;
+    QVector<KTextEditor::Range> lastResultRanges; // TODO reset on document change \
so we don't get wrong data when asking for the ranges content?  };
 
 KateSearchBar::KateSearchBar(KateViewBar *viewBar)
@@ -74,6 +77,8 @@
     connect(d->expressionEdit, SIGNAL(findNext()), this, SLOT(findNext()));
     connect(d->expressionEdit, SIGNAL(findPrevious()), this, SLOT(findPrevious()));
 
+    d->replaceEdit = new KLineEdit();
+
     d->caseSensitiveBox = new QCheckBox(i18n("&Case sensitive"));
     connect(d->caseSensitiveBox, SIGNAL(stateChanged(int)), this, \
SLOT(slotSearch()));  
@@ -120,24 +125,43 @@
     prevButton->setText(i18n("Previous"));
     connect(prevButton, SIGNAL(clicked()), this, SLOT(findPrevious()));
 
+
+    QPushButton * const replaceOnceButton = new QPushButton();
+#warning TRANSLATE HERE
+    replaceOnceButton->setText("Once");
+    connect(replaceOnceButton, SIGNAL(clicked()), this, SLOT(replaceOnce()));
+
+    QPushButton * const replaceAllButton = new QPushButton();
+#warning TRANSLATE HERE
+    replaceAllButton->setText("All");
+    replaceAllButton->setDisabled(true);
+    connect(replaceAllButton, SIGNAL(clicked()), this, SLOT(replaceAll()));
+
+    // first line: lineedit + next + prev
     QHBoxLayout *layoutFirstLine = new QHBoxLayout;
     topLayout->addLayout (layoutFirstLine);
-
-    // first line: lineedit + next + prev
     layoutFirstLine->addWidget(d->expressionEdit);
     layoutFirstLine->addWidget(prevButton);
     layoutFirstLine->addWidget(nextButton);
 
+    // second line: lineedit
+    // TODO: better in grid with first line?
+    QHBoxLayout * layoutSecondLine = new QHBoxLayout;
+    layoutSecondLine->addWidget(d->replaceEdit);
+    layoutSecondLine->addWidget(replaceOnceButton);
+    layoutSecondLine->addWidget(replaceAllButton);
+    topLayout->addLayout(layoutSecondLine);
+
     QGridLayout *gridLayout = new QGridLayout;
     topLayout->addLayout (gridLayout);
 
-    // second line: casesensitive + whole words + regexp
+    // third line: casesensitive + whole words + regexp
     gridLayout->addWidget(d->regExpBox, 0, 0);
     gridLayout->addWidget(d->caseSensitiveBox, 0, 1);
     //gridLayout->addWidget(d->wholeWordsBox, 0, 1);
     gridLayout->addItem (new QSpacerItem(0,0), 0, 3);
 
-    // third line: from cursor + selection only + highlight all
+    // fourth line: from cursor + selection only + highlight all
     gridLayout->addWidget(d->fromCursorBox, 1, 0);
     gridLayout->addWidget(d->selectionOnlyBox, 1, 1);
     gridLayout->addWidget(d->highlightAllBox, 1, 2);
@@ -150,6 +174,9 @@
 
     d->topRange = m_view->doc()->newSmartRange( m_view->doc()->documentRange() );
     d->topRange->setInsertBehavior(KTextEditor::SmartRange::ExpandRight);
+
+    // result range vector must contain one element minimum
+    d->lastResultRanges.append(KTextEditor::Range::invalid());
 }
 
 KateSearchBar::~KateSearchBar()
@@ -421,6 +448,7 @@
     : KateSearchBarEdit::NotFound);
 
   d->lastExpression = expression;
+  d->lastResultRanges = resultRanges; // copy over whole vector
 }
 
 void KateSearchBar::slotSpecialOptionTogled()
@@ -499,6 +527,72 @@
     doSearch(d->expressionEdit->text(), false, true);
 }
 
+void KateSearchBar::replaceOnce()
+{
+    // replace current selection in document
+    // with text from <replaceEdit>
+
+    // text selected?
+    KTextEditor::Range selRange = m_view->selectionRange();
+    if (!selRange.isValid())
+    {
+      return;
+    }
+
+    // parse escape sequences in escape string if in
+    // regexp or escape sequence search mode
+    const uint comboData = \
d->regExpBox->itemData(d->regExpBox->currentIndex()).toUInt(); +    const bool \
processEscapeSequence = comboData & (KTextEditor::Search::Regex | \
KTextEditor::Search::EscapeSequences); +    QString replaceText = \
d->replaceEdit->text(); +    if (processEscapeSequence)
+    {
+      const int MIN_REF_INDEX = 0;
+      const int MAX_REF_INDEX = d->lastResultRanges.count() - 1;
+
+      QList<ReplacementPart> parts;
+      const bool zeroCaptureOnly = (MAX_REF_INDEX == 0);
+      KateDocument::escapePlaintext(replaceText, &parts, zeroCaptureOnly);
+
+      // build replacement text with filled in references
+      replaceText.clear();
+      for (QList<ReplacementPart>::iterator iter = parts.begin(); iter != \
parts.end(); iter++) +      {
+        ReplacementPart curPart = *iter;
+        if (curPart.isReference)
+        {
+          if ((curPart.index < MIN_REF_INDEX) || (curPart.index > MAX_REF_INDEX))
+          {
+            // insert just the number since "\c" becomes "c" in QRegExp
+            replaceText.append(QString::number(curPart.index));
+          }
+          else
+          {
+            const KTextEditor::Range & captureRange = \
d->lastResultRanges[curPart.index]; +            if (captureRange.isValid())
+            {
+              // copy capture content
+              const bool blockMode = m_view->blockSelection();
+              replaceText.append(m_view->doc()->text(captureRange, blockMode));
+            }
+          }
+        }
+        else
+        {
+          replaceText.append(curPart.text);
+        }
+      }
+    }
+
+    // replace
+    const bool blockMode = (m_view->blockSelection() && !selRange.onSingleLine());
+    m_view->doc()->replaceText(selRange, replaceText, blockMode);
+}
+
+void KateSearchBar::replaceAll()
+{
+    // TODO
+}
+
 void KateSearchBar::showEvent(QShowEvent *e)
 {
     if ( e->spontaneous() ) return;
Index: utils/katesearchbar.h
===================================================================
--- utils/katesearchbar.h	(revision 689703)
+++ utils/katesearchbar.h	(working copy)
@@ -36,6 +36,8 @@
 public Q_SLOTS:
     void findNext();
     void findPrevious();
+    void replaceOnce();
+    void replaceAll();
 
 private Q_SLOTS:
     void slotSearch();
Index: document/katedocument.cpp
===================================================================
--- document/katedocument.cpp	(revision 689703)
+++ document/katedocument.cpp	(working copy)
@@ -2423,7 +2423,9 @@
   return supported;
 }
 
-void KateDocument::escapePlaintext(QString & text) {
+void KateDocument::escapePlaintext(QString & text, QList<ReplacementPart> * parts,
+    bool zeroCaptureOnly)
+{
   // get input
   const int inputLen = text.length();
   int input = 0; // walker index
@@ -2453,26 +2455,37 @@
       switch (text[input + 1].unicode())
       {
       case L'0': // "\0000".."\0377"
-        if (input + 2 >= inputLen)
+        if (input + 4 >= inputLen)
         {
-          // strip backslash ("\0" -> "0")
-          output.append(text[input + 1]);
+          if (parts == NULL)
+          {
+            // strip backslash ("\0" -> "0")
+            output.append(text[input + 1]);
+          }
+          else
+          {
+            // handle reference
+            ReplacementPart part;
+
+            // append text before the reference
+            if (!output.isEmpty())
+            {
+              part.isReference = false;
+              part.text = output;
+              output.clear();
+              parts->append(part);
+            }
+
+            // append reference
+            part.isReference = true;
+            part.index = 0;
+            parts->append(part);
+          }
           input += 2;
         }
-        else if (input + 3 >= inputLen)
-        {
-          // strip backslash ("\0?" -> "0?")
-          output.append(text[input + 1]).append(text[input + 2]);
-          input += 3;
-        }
-        else if (input + 4 >= inputLen)
-        {
-          // strip backslash ("\0??" -> "0??")
-          output.append(text[input + 1]).append(text[input + 2]).append(text[input + \
                3]);
-          input += 4;
-        }
         else
         {
+          bool stripAndSkip = false;
           const ushort text_2 = text[input + 2].unicode();
           if ((text_2 >= L'0') && (text_2 <= L'3'))
           {
@@ -2493,27 +2506,86 @@
               }
               else
               {
-                // strip backslash ("\0??" -> "0??")
-                output.append(text[input + 1]).append(text[input + \
                2]).append(text[input + 3]);
-                input += 4;
+                stripAndSkip = true;
               }
             }
             else
             {
-              // strip backslash ("\0?" -> "0?")
-              output.append(text[input + 1]).append(text[input + 2]);
-              input += 3;
+              stripAndSkip = true;
             }
           }
           else
           {
-            // strip backslash ("\0" -> "0")
-            output.append(text[input + 1]);
+            stripAndSkip = true;
+          }
+
+          if (stripAndSkip)
+          {
+            if (parts == NULL)
+            {
+              // strip backslash ("\0" -> "0")
+              output.append(text[input + 1]);
+            }
+            else
+            {
+              // handle reference
+              ReplacementPart part;
+
+              // append text before the reference
+              if (!output.isEmpty())
+              {
+                part.isReference = false;
+                part.text = output;
+                output.clear();
+                parts->append(part);
+              }
+
+              // append reference
+              part.isReference = true;
+              part.index = 0;
+              parts->append(part);
+            }
             input += 2;
           }
         }
         break;
 
+      case L'1':
+      case L'2':
+      case L'3':
+      case L'4':
+      case L'5':
+      case L'6':
+      case L'7':
+      case L'8':
+      case L'9':
+        if ((parts == NULL) || zeroCaptureOnly)
+        {
+          // strip backslash ("\?" -> "?")
+          output.append(text[input + 1]);
+        }
+        else
+        {
+          // handle reference
+          ReplacementPart part;
+
+          // append text before the reference
+          if (!output.isEmpty())
+          {
+            part.isReference = false;
+            part.text = output;
+            output.clear();
+            parts->append(part);
+          }
+
+          // append reference
+          part.isReference = true;
+          part.index = 9 - (L'9' - text[input + 1].unicode());
+          parts->append(part);
+        }
+        input += 2;
+        break;
+
       case L'a':
         output.append(QChar(0x07));
         input += 2;
@@ -2545,32 +2617,15 @@
         break;
 
       case L'x': // "\x0000".."\xffff"
-        if (input + 2 >= inputLen)
+        if (input + 5 >= inputLen)
         {
           // strip backslash ("\x" -> "x")
           output.append(text[input + 1]);
           input += 2;
         }
-        else if (input + 3 >= inputLen)
-        {
-          // strip backslash ("\x?" -> "x?")
-          output.append(text[input + 1]).append(text[input + 2]);
-          input += 3;
-        }
-        else if (input + 4 >= inputLen)
-        {
-          // strip backslash ("\x??" -> "x??")
-          output.append(text[input + 1]).append(text[input + 2]).append(text[input + \
                3]);
-          input += 4;
-        }
-        else if (input + 5 >= inputLen)
-        {
-          // strip backslash ("\x???" -> "x???")
-          output.append(text[input + 1]).append(text[input + 2]).append(text[input + \
                3]).append(text[input + 4]);
-          input += 5;
-        }
         else
         {
+          bool stripAndSkip = false;
           const ushort text_2 = text[input + 2].unicode();
           if (((text_2 >= L'0') && (text_2 <= L'9'))
               || ((text_2 >= L'a') && (text_2 <= L'f'))
@@ -2615,28 +2670,23 @@
                 }
                 else
                 {
-                  // Strip backslash ("\x???" -> "x???")
-                  output.append(text[input + 1]).append(text[input + \
                2]).append(text[input + 3]).append(text[input + 4]);
-                  input += 5;
+                  stripAndSkip = true;
                 }
               }
               else
               {
-                // Strip backslash ("\x??" -> "x??")
-                output.append(text[input + 1]).append(text[input + \
                2]).append(text[input + 3]);
-                input += 4;
+                stripAndSkip = true;
               }
             }
             else
             {
-              // Strip backslash ("\x?" -> "x?")
-              output.append(text[input + 1]).append(text[input + 2]);
-              input += 3;
+              stripAndSkip = true;
             }
           }
-          else
+
+          if (stripAndSkip)
           {
-            // Strip backslash ("\x" -> "x")
+            // strip backslash ("\x" -> "x")
             output.append(text[input + 1]);
             input += 2;
           }
@@ -2644,7 +2694,7 @@
         break;
 
       default:
-        // Strip backslash ("\?" -> "?")
+        // strip backslash ("\?" -> "?")
         output.append(text[input + 1]);
         input += 2;
 
@@ -2658,8 +2708,22 @@
     }
   }
 
-  // Overwrite with escaped edition
-  text = output;
+  if (parts == NULL)
+  {
+    // overwrite with escaped edition
+    text = output;
+  }
+  else
+  {
+    // append text after the last reference if any
+    if (!output.isEmpty())
+    {
+      ReplacementPart part;
+      part.isReference = false;
+      part.text = output;
+      parts->append(part);
+    }
+  }
 }
 
 
Index: document/katedocument.h
===================================================================
--- document/katedocument.h	(revision 689703)
+++ document/katedocument.h	(working copy)
@@ -66,6 +66,14 @@
 
 class KateKeyInterceptorFunctor;
 
+// needed for parsing replacement text like "\1:\2"
+struct ReplacementPart
+{
+  bool isReference; // otherwise text
+  int index; // [0..9] 0=full match, 1=first capture, ..
+  QString text; // if not a reference
+};
+
 //
 // Kate KTextEditor::Document class (and even KTextEditor::Editor ;)
 //
@@ -415,12 +423,22 @@
     QVector<KTextEditor::Range> searchText (const KTextEditor::Range & inputRange,
         QRegExp & regexp, bool backwards = false);
 
+  /*
+   * Public string processing helpers
+   */
+  public:
     /**
-     * Resolves escape sequences, e.g. "\\n" to "\n".
+     * Resolves escape sequences (e.g. "\\n" to "\n") in <code>text</code>
+     * if <code>parts</code> is NULL. Otherwise it leaves code>text</code>
+     * unmodified and creates a list of text and capture references out of it.
+     * These two modes are fused into one function to avoid code duplication.
      *
-     * \param text  Text to process
+     * \param text             Text to process
+     * \param parts            List of text and references
+     * \param zeroCaptureOnly  Only accept \0 as a reference, discard \1 to \9
      */
-    static void escapePlaintext(QString & text);
+    static void escapePlaintext(QString & text, QList<ReplacementPart> * parts = \
NULL, +        bool zeroCaptureOnly = false);
 
     /**
      * Repairs a regular Expression pattern.



_______________________________________________
KWrite-Devel mailing list
KWrite-Devel@kde.org
https://mail.kde.org/mailman/listinfo/kwrite-devel


[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic