[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