forked from qt-creator/qt-creator
Fixes: Multi-file regexp replace didn't replace placeholders e.g. \1
This commit is contained in:
@@ -170,7 +170,8 @@ void runFileSearch(QFutureInterface<FileSearchResult> &future,
|
|||||||
while (startOfLastLine[i] != '\n' && startOfLastLine[i] != '\r' && i < textLength && n++ < 256)
|
while (startOfLastLine[i] != '\n' && startOfLastLine[i] != '\r' && i < textLength && n++ < 256)
|
||||||
res.append(startOfLastLine[i++]);
|
res.append(startOfLastLine[i++]);
|
||||||
future.reportResult(FileSearchResult(s, lineNr, QString(res),
|
future.reportResult(FileSearchResult(s, lineNr, QString(res),
|
||||||
regionPtr - startOfLastLine, sa.length()));
|
regionPtr - startOfLastLine, sa.length(),
|
||||||
|
QStringList()));
|
||||||
++numMatches;
|
++numMatches;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -229,7 +230,8 @@ void runFileSearchRegExp(QFutureInterface<FileSearchResult> &future,
|
|||||||
int pos = 0;
|
int pos = 0;
|
||||||
while ((pos = expression.indexIn(line, pos)) != -1) {
|
while ((pos = expression.indexIn(line, pos)) != -1) {
|
||||||
future.reportResult(FileSearchResult(s, lineNr, line,
|
future.reportResult(FileSearchResult(s, lineNr, line,
|
||||||
pos, expression.matchedLength()));
|
pos, expression.matchedLength(),
|
||||||
|
expression.capturedTexts()));
|
||||||
pos += expression.matchedLength();
|
pos += expression.matchedLength();
|
||||||
}
|
}
|
||||||
++lineNr;
|
++lineNr;
|
||||||
@@ -259,3 +261,36 @@ QFuture<FileSearchResult> Utils::findInFilesRegExp(const QString &searchTerm, co
|
|||||||
return QtConcurrent::run<FileSearchResult, QString, QStringList, QTextDocument::FindFlags, QMap<QString, QString> >
|
return QtConcurrent::run<FileSearchResult, QString, QStringList, QTextDocument::FindFlags, QMap<QString, QString> >
|
||||||
(runFileSearchRegExp, searchTerm, files, flags, fileToContentsMap);
|
(runFileSearchRegExp, searchTerm, files, flags, fileToContentsMap);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
QString Utils::expandRegExpReplacement(const QString &replaceText, const QStringList &capturedTexts)
|
||||||
|
{
|
||||||
|
QString result;
|
||||||
|
int numCaptures = capturedTexts.size() - 1;
|
||||||
|
for (int i = 0; i < replaceText.length(); ++i) {
|
||||||
|
QChar c = replaceText.at(i);
|
||||||
|
if (c == QLatin1Char('\\') && i < replaceText.length() - 1) {
|
||||||
|
c = replaceText.at(++i);
|
||||||
|
if (c == QLatin1Char('\\')) {
|
||||||
|
result += QLatin1Char('\\');
|
||||||
|
} else if (c == QLatin1Char('&')) {
|
||||||
|
result += QLatin1Char('&');
|
||||||
|
} else if (c.isDigit()) {
|
||||||
|
int index = c.unicode()-'1';
|
||||||
|
if (index < numCaptures) {
|
||||||
|
result += capturedTexts.at(index+1);
|
||||||
|
} else {
|
||||||
|
result += QLatin1Char('\\');
|
||||||
|
result += c;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
result += QLatin1Char('\\');
|
||||||
|
result += c;
|
||||||
|
}
|
||||||
|
} else if (c == QLatin1Char('&')) {
|
||||||
|
result += capturedTexts.at(0);
|
||||||
|
} else {
|
||||||
|
result += c;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|||||||
@@ -43,8 +43,15 @@ class QTCREATOR_UTILS_EXPORT FileSearchResult
|
|||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
FileSearchResult() {}
|
FileSearchResult() {}
|
||||||
FileSearchResult(QString fileName, int lineNumber, QString matchingLine, int matchStart, int matchLength)
|
FileSearchResult(QString fileName, int lineNumber, QString matchingLine,
|
||||||
: fileName(fileName), lineNumber(lineNumber), matchingLine(matchingLine), matchStart(matchStart), matchLength(matchLength)
|
int matchStart, int matchLength,
|
||||||
|
QStringList regexpCapturedTexts)
|
||||||
|
: fileName(fileName),
|
||||||
|
lineNumber(lineNumber),
|
||||||
|
matchingLine(matchingLine),
|
||||||
|
matchStart(matchStart),
|
||||||
|
matchLength(matchLength),
|
||||||
|
regexpCapturedTexts(regexpCapturedTexts)
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
QString fileName;
|
QString fileName;
|
||||||
@@ -52,6 +59,7 @@ public:
|
|||||||
QString matchingLine;
|
QString matchingLine;
|
||||||
int matchStart;
|
int matchStart;
|
||||||
int matchLength;
|
int matchLength;
|
||||||
|
QStringList regexpCapturedTexts;
|
||||||
};
|
};
|
||||||
|
|
||||||
QTCREATOR_UTILS_EXPORT QFuture<FileSearchResult> findInFiles(const QString &searchTerm, const QStringList &files,
|
QTCREATOR_UTILS_EXPORT QFuture<FileSearchResult> findInFiles(const QString &searchTerm, const QStringList &files,
|
||||||
@@ -60,6 +68,8 @@ QTCREATOR_UTILS_EXPORT QFuture<FileSearchResult> findInFiles(const QString &sear
|
|||||||
QTCREATOR_UTILS_EXPORT QFuture<FileSearchResult> findInFilesRegExp(const QString &searchTerm, const QStringList &files,
|
QTCREATOR_UTILS_EXPORT QFuture<FileSearchResult> findInFilesRegExp(const QString &searchTerm, const QStringList &files,
|
||||||
QTextDocument::FindFlags flags, QMap<QString, QString> fileToContentsMap = QMap<QString, QString>());
|
QTextDocument::FindFlags flags, QMap<QString, QString> fileToContentsMap = QMap<QString, QString>());
|
||||||
|
|
||||||
|
QTCREATOR_UTILS_EXPORT QString expandRegExpReplacement(const QString &replaceText, const QStringList &capturedTexts);
|
||||||
|
|
||||||
} // namespace Utils
|
} // namespace Utils
|
||||||
|
|
||||||
#endif // FILESEARCH_H
|
#endif // FILESEARCH_H
|
||||||
|
|||||||
@@ -30,6 +30,7 @@
|
|||||||
#include "basetextfind.h"
|
#include "basetextfind.h"
|
||||||
|
|
||||||
#include <utils/qtcassert.h>
|
#include <utils/qtcassert.h>
|
||||||
|
#include <utils/filesearch.h>
|
||||||
|
|
||||||
#include <QtGui/QTextBlock>
|
#include <QtGui/QTextBlock>
|
||||||
#include <QtGui/QPlainTextEdit>
|
#include <QtGui/QPlainTextEdit>
|
||||||
@@ -152,40 +153,6 @@ IFindSupport::Result BaseTextFind::findStep(const QString &txt, IFindSupport::Fi
|
|||||||
return found ? Found : NotFound;
|
return found ? Found : NotFound;
|
||||||
}
|
}
|
||||||
|
|
||||||
namespace {
|
|
||||||
QString expandRegExpReplacement(const QString &replaceText, const QRegExp ®exp)
|
|
||||||
{
|
|
||||||
QString result;
|
|
||||||
for (int i = 0; i < replaceText.length(); ++i) {
|
|
||||||
QChar c = replaceText.at(i);
|
|
||||||
if (c == QLatin1Char('\\') && i < replaceText.length() - 1) {
|
|
||||||
c = replaceText.at(++i);
|
|
||||||
if (c == QLatin1Char('\\')) {
|
|
||||||
result += QLatin1Char('\\');
|
|
||||||
} else if (c == QLatin1Char('&')) {
|
|
||||||
result += QLatin1Char('&');
|
|
||||||
} else if (c.isDigit()) {
|
|
||||||
int index = c.unicode()-'1';
|
|
||||||
if (index < regexp.numCaptures()) {
|
|
||||||
result += regexp.cap(index+1);
|
|
||||||
} else {
|
|
||||||
result += QLatin1Char('\\');
|
|
||||||
result += c;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
result += QLatin1Char('\\');
|
|
||||||
result += c;
|
|
||||||
}
|
|
||||||
} else if (c == QLatin1Char('&')) {
|
|
||||||
result += regexp.cap(0);
|
|
||||||
} else {
|
|
||||||
result += c;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool BaseTextFind::replaceStep(const QString &before, const QString &after,
|
bool BaseTextFind::replaceStep(const QString &before, const QString &after,
|
||||||
IFindSupport::FindFlags findFlags)
|
IFindSupport::FindFlags findFlags)
|
||||||
{
|
{
|
||||||
@@ -196,7 +163,7 @@ bool BaseTextFind::replaceStep(const QString &before, const QString &after,
|
|||||||
usesRegExp ? QRegExp::RegExp : QRegExp::FixedString);
|
usesRegExp ? QRegExp::RegExp : QRegExp::FixedString);
|
||||||
|
|
||||||
if (regexp.exactMatch(cursor.selectedText())) {
|
if (regexp.exactMatch(cursor.selectedText())) {
|
||||||
QString realAfter = usesRegExp ? expandRegExpReplacement(after, regexp) : after;
|
QString realAfter = usesRegExp ? Utils::expandRegExpReplacement(after, regexp.capturedTexts()) : after;
|
||||||
int start = cursor.selectionStart();
|
int start = cursor.selectionStart();
|
||||||
cursor.insertText(realAfter);
|
cursor.insertText(realAfter);
|
||||||
if ((findFlags&IFindSupport::FindBackward) != 0)
|
if ((findFlags&IFindSupport::FindBackward) != 0)
|
||||||
@@ -226,7 +193,7 @@ int BaseTextFind::replaceAll(const QString &before, const QString &after,
|
|||||||
editCursor.setPosition(found.selectionStart());
|
editCursor.setPosition(found.selectionStart());
|
||||||
editCursor.setPosition(found.selectionEnd(), QTextCursor::KeepAnchor);
|
editCursor.setPosition(found.selectionEnd(), QTextCursor::KeepAnchor);
|
||||||
regexp.exactMatch(found.selectedText());
|
regexp.exactMatch(found.selectedText());
|
||||||
QString realAfter = usesRegExp ? expandRegExpReplacement(after, regexp) : after;
|
QString realAfter = usesRegExp ? Utils::expandRegExpReplacement(after, regexp.capturedTexts()) : after;
|
||||||
editCursor.insertText(realAfter);
|
editCursor.insertText(realAfter);
|
||||||
found = findOne(regexp, editCursor, IFindSupport::textDocumentFlagsForFindFlags(findFlags));
|
found = findOne(regexp, editCursor, IFindSupport::textDocumentFlagsForFindFlags(findFlags));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -150,7 +150,8 @@ void BaseFileFind::displayResult(int index) {
|
|||||||
result.lineNumber,
|
result.lineNumber,
|
||||||
result.matchingLine,
|
result.matchingLine,
|
||||||
result.matchStart,
|
result.matchStart,
|
||||||
result.matchLength);
|
result.matchLength,
|
||||||
|
result.regexpCapturedTexts);
|
||||||
if (m_resultLabel)
|
if (m_resultLabel)
|
||||||
m_resultLabel->setText(tr("%1 found").arg(m_resultWindow->numberOfResults()));
|
m_resultLabel->setText(tr("%1 found").arg(m_resultWindow->numberOfResults()));
|
||||||
}
|
}
|
||||||
@@ -280,7 +281,7 @@ void BaseFileFind::openEditor(const Find::SearchResultItem &item)
|
|||||||
|
|
||||||
static void applyChanges(QTextDocument *doc, const QString &text, const QList<Find::SearchResultItem> &items)
|
static void applyChanges(QTextDocument *doc, const QString &text, const QList<Find::SearchResultItem> &items)
|
||||||
{
|
{
|
||||||
QList<QTextCursor> cursors;
|
QList<QPair<QTextCursor, QString> > changes;
|
||||||
|
|
||||||
foreach (const Find::SearchResultItem &item, items) {
|
foreach (const Find::SearchResultItem &item, items) {
|
||||||
const int blockNumber = item.lineNumber - 1;
|
const int blockNumber = item.lineNumber - 1;
|
||||||
@@ -289,24 +290,31 @@ static void applyChanges(QTextDocument *doc, const QString &text, const QList<Fi
|
|||||||
const int cursorPosition = tc.position() + item.searchTermStart;
|
const int cursorPosition = tc.position() + item.searchTermStart;
|
||||||
|
|
||||||
int cursorIndex = 0;
|
int cursorIndex = 0;
|
||||||
for (; cursorIndex < cursors.size(); ++cursorIndex) {
|
for (; cursorIndex < changes.size(); ++cursorIndex) {
|
||||||
const QTextCursor &tc = cursors.at(cursorIndex);
|
const QTextCursor &otherTc = changes.at(cursorIndex).first;
|
||||||
|
|
||||||
if (tc.position() == cursorPosition)
|
if (otherTc.position() == cursorPosition)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (cursorIndex != cursors.size())
|
if (cursorIndex != changes.size())
|
||||||
continue; // skip this change.
|
continue; // skip this change.
|
||||||
|
|
||||||
tc.setPosition(cursorPosition);
|
tc.setPosition(cursorPosition);
|
||||||
tc.setPosition(tc.position() + item.searchTermLength,
|
tc.setPosition(tc.position() + item.searchTermLength,
|
||||||
QTextCursor::KeepAnchor);
|
QTextCursor::KeepAnchor);
|
||||||
cursors.append(tc);
|
QString substitutionText;
|
||||||
|
if (item.userData.canConvert<QStringList>() && !item.userData.toStringList().isEmpty())
|
||||||
|
substitutionText = Utils::expandRegExpReplacement(text, item.userData.toStringList());
|
||||||
|
else
|
||||||
|
substitutionText = text;
|
||||||
|
changes.append(QPair<QTextCursor, QString>(tc, substitutionText));
|
||||||
}
|
}
|
||||||
|
|
||||||
foreach (QTextCursor tc, cursors)
|
for (int i = 0; i < changes.size(); ++i) {
|
||||||
tc.insertText(text);
|
QPair<QTextCursor, QString> &cursor = changes[i];
|
||||||
|
cursor.first.insertText(cursor.second);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
QStringList BaseFileFind::replaceAll(const QString &text,
|
QStringList BaseFileFind::replaceAll(const QString &text,
|
||||||
|
|||||||
Reference in New Issue
Block a user