Utils: move text replacement helper to Utils::Text

Change-Id: I82b3304f91d575369e74d5f7404c189e14ba4730
Reviewed-by: Christian Stenger <christian.stenger@qt.io>
This commit is contained in:
David Schulz
2020-01-08 10:43:13 +01:00
parent 88edfdb1b2
commit c56e58fab4
6 changed files with 72 additions and 69 deletions

View File

@@ -36,6 +36,23 @@ QT_FORWARD_DECLARE_CLASS(QTextCursor)
namespace Utils { namespace Utils {
namespace Text { namespace Text {
struct Replacement
{
Replacement() = default;
Replacement(int offset, int length, const QString &text)
: offset(offset)
, length(length)
, text(text)
{}
int offset = -1;
int length = -1;
QString text;
bool isValid() const { return offset >= 0 && length >= 0; }
};
using Replacements = std::vector<Replacement>;
// line is 1-based, column is 1-based // line is 1-based, column is 1-based
QTCREATOR_UTILS_EXPORT bool convertPosition(const QTextDocument *document, QTCREATOR_UTILS_EXPORT bool convertPosition(const QTextDocument *document,
int pos, int pos,

View File

@@ -311,11 +311,11 @@ bool isInsideDummyTextInLine(const QString &originalLine, const QString &modifie
|| !modifiedLine.startsWith(originalLine)); || !modifiedLine.startsWith(originalLine));
} }
TextEditor::Replacements utf16Replacements(const QTextDocument *doc, Utils::Text::Replacements utf16Replacements(const QTextDocument *doc,
const QByteArray &utf8Buffer, const QByteArray &utf8Buffer,
const clang::tooling::Replacements &replacements) const clang::tooling::Replacements &replacements)
{ {
TextEditor::Replacements convertedReplacements; Utils::Text::Replacements convertedReplacements;
convertedReplacements.reserve(replacements.size()); convertedReplacements.reserve(replacements.size());
for (const clang::tooling::Replacement &replacement : replacements) { for (const clang::tooling::Replacement &replacement : replacements) {
@@ -349,14 +349,14 @@ TextEditor::Replacements utf16Replacements(const QTextDocument *doc,
return convertedReplacements; return convertedReplacements;
} }
void applyReplacements(QTextDocument *doc, const TextEditor::Replacements &replacements) void applyReplacements(QTextDocument *doc, const Utils::Text::Replacements &replacements)
{ {
if (replacements.empty()) if (replacements.empty())
return; return;
int fullOffsetShift = 0; int fullOffsetShift = 0;
QTextCursor editCursor(doc); QTextCursor editCursor(doc);
for (const TextEditor::Replacement &replacement : replacements) { for (const Utils::Text::Replacement &replacement : replacements) {
editCursor.setPosition(replacement.offset + fullOffsetShift); editCursor.setPosition(replacement.offset + fullOffsetShift);
editCursor.movePosition(QTextCursor::NextCharacter, editCursor.movePosition(QTextCursor::NextCharacter,
QTextCursor::KeepAnchor, QTextCursor::KeepAnchor,
@@ -376,7 +376,7 @@ QString selectedLines(QTextDocument *doc, const QTextBlock &startBlock, const QT
- startBlock.position() - 1)); - startBlock.position() - 1));
} }
int indentationForBlock(const TextEditor::Replacements &toReplace, int indentationForBlock(const Utils::Text::Replacements &toReplace,
const QByteArray &buffer, const QByteArray &buffer,
const QTextBlock &currentBlock) const QTextBlock &currentBlock)
{ {
@@ -385,7 +385,7 @@ int indentationForBlock(const TextEditor::Replacements &toReplace,
currentBlock.blockNumber() + 1); currentBlock.blockNumber() + 1);
auto replacementIt = std::find_if(toReplace.begin(), auto replacementIt = std::find_if(toReplace.begin(),
toReplace.end(), toReplace.end(),
[utf8Offset](const TextEditor::Replacement &replacement) { [utf8Offset](const Utils::Text::Replacement &replacement) {
return replacement.offset == utf8Offset - 1; return replacement.offset == utf8Offset - 1;
}); });
if (replacementIt == toReplace.end()) if (replacementIt == toReplace.end())
@@ -442,21 +442,21 @@ ClangFormatBaseIndenter::ClangFormatBaseIndenter(QTextDocument *doc)
: TextEditor::Indenter(doc) : TextEditor::Indenter(doc)
{} {}
TextEditor::Replacements ClangFormatBaseIndenter::replacements(QByteArray buffer, Utils::Text::Replacements ClangFormatBaseIndenter::replacements(QByteArray buffer,
const QTextBlock &startBlock, const QTextBlock &startBlock,
const QTextBlock &endBlock, const QTextBlock &endBlock,
int cursorPositionInEditor, int cursorPositionInEditor,
ReplacementsToKeep replacementsToKeep, ReplacementsToKeep replacementsToKeep,
const QChar &typedChar, const QChar &typedChar,
bool secondTry) const bool secondTry) const
{ {
QTC_ASSERT(replacementsToKeep != ReplacementsToKeep::All, return TextEditor::Replacements()); QTC_ASSERT(replacementsToKeep != ReplacementsToKeep::All, return Utils::Text::Replacements());
clang::format::FormatStyle style = styleForFile(); clang::format::FormatStyle style = styleForFile();
QByteArray originalBuffer = buffer; QByteArray originalBuffer = buffer;
int utf8Offset = Utils::Text::utf8NthLineOffset(m_doc, buffer, startBlock.blockNumber() + 1); int utf8Offset = Utils::Text::utf8NthLineOffset(m_doc, buffer, startBlock.blockNumber() + 1);
QTC_ASSERT(utf8Offset >= 0, return TextEditor::Replacements();); QTC_ASSERT(utf8Offset >= 0, return Utils::Text::Replacements(););
int utf8Length = selectedLines(m_doc, startBlock, endBlock).toUtf8().size(); int utf8Length = selectedLines(m_doc, startBlock, endBlock).toUtf8().size();
int rangeStart = 0; int rangeStart = 0;
@@ -511,11 +511,11 @@ TextEditor::Replacements ClangFormatBaseIndenter::replacements(QByteArray buffer
return utf16Replacements(m_doc, buffer, filtered); return utf16Replacements(m_doc, buffer, filtered);
} }
TextEditor::Replacements ClangFormatBaseIndenter::format( Utils::Text::Replacements ClangFormatBaseIndenter::format(
const TextEditor::RangesInLines &rangesInLines) const TextEditor::RangesInLines &rangesInLines)
{ {
if (rangesInLines.empty()) if (rangesInLines.empty())
return TextEditor::Replacements(); return Utils::Text::Replacements();
const QByteArray buffer = m_doc->toPlainText().toUtf8(); const QByteArray buffer = m_doc->toPlainText().toUtf8();
std::vector<clang::tooling::Range> ranges; std::vector<clang::tooling::Range> ranges;
@@ -541,7 +541,7 @@ TextEditor::Replacements ClangFormatBaseIndenter::format(
auto changedCode = clang::tooling::applyAllReplacements(buffer.data(), clangReplacements); auto changedCode = clang::tooling::applyAllReplacements(buffer.data(), clangReplacements);
QTC_ASSERT(changedCode, { QTC_ASSERT(changedCode, {
qDebug() << QString::fromStdString(llvm::toString(changedCode.takeError())); qDebug() << QString::fromStdString(llvm::toString(changedCode.takeError()));
return TextEditor::Replacements(); return Utils::Text::Replacements();
}); });
ranges = clang::tooling::calculateRangesAfterReplacements(clangReplacements, ranges); ranges = clang::tooling::calculateRangesAfterReplacements(clangReplacements, ranges);
@@ -553,21 +553,21 @@ TextEditor::Replacements ClangFormatBaseIndenter::format(
&status); &status);
clangReplacements = clangReplacements.merge(formatReplacements); clangReplacements = clangReplacements.merge(formatReplacements);
const TextEditor::Replacements toReplace = utf16Replacements(m_doc, buffer, clangReplacements); const Utils::Text::Replacements toReplace = utf16Replacements(m_doc, buffer, clangReplacements);
applyReplacements(m_doc, toReplace); applyReplacements(m_doc, toReplace);
return toReplace; return toReplace;
} }
TextEditor::Replacements ClangFormatBaseIndenter::indentsFor(QTextBlock startBlock, Utils::Text::Replacements ClangFormatBaseIndenter::indentsFor(QTextBlock startBlock,
const QTextBlock &endBlock, const QTextBlock &endBlock,
const QChar &typedChar, const QChar &typedChar,
int cursorPositionInEditor) int cursorPositionInEditor)
{ {
if (typedChar != QChar::Null && cursorPositionInEditor > 0 if (typedChar != QChar::Null && cursorPositionInEditor > 0
&& m_doc->characterAt(cursorPositionInEditor - 1) == typedChar && m_doc->characterAt(cursorPositionInEditor - 1) == typedChar
&& doNotIndentInContext(m_doc, cursorPositionInEditor - 1)) { && doNotIndentInContext(m_doc, cursorPositionInEditor - 1)) {
return TextEditor::Replacements(); return Utils::Text::Replacements();
} }
startBlock = reverseFindLastEmptyBlock(startBlock); startBlock = reverseFindLastEmptyBlock(startBlock);
@@ -650,10 +650,10 @@ int ClangFormatBaseIndenter::indentFor(const QTextBlock &block,
const TextEditor::TabSettings & /*tabSettings*/, const TextEditor::TabSettings & /*tabSettings*/,
int cursorPositionInEditor) int cursorPositionInEditor)
{ {
TextEditor::Replacements toReplace = indentsFor(block, Utils::Text::Replacements toReplace = indentsFor(block,
block, block,
QChar::Null, QChar::Null,
cursorPositionInEditor); cursorPositionInEditor);
if (toReplace.empty()) if (toReplace.empty())
return -1; return -1;
@@ -669,10 +669,10 @@ TextEditor::IndentationForBlock ClangFormatBaseIndenter::indentationForBlocks(
TextEditor::IndentationForBlock ret; TextEditor::IndentationForBlock ret;
if (blocks.isEmpty()) if (blocks.isEmpty())
return ret; return ret;
TextEditor::Replacements toReplace = indentsFor(blocks.front(), Utils::Text::Replacements toReplace = indentsFor(blocks.front(),
blocks.back(), blocks.back(),
QChar::Null, QChar::Null,
cursorPositionInEditor); cursorPositionInEditor);
const QByteArray buffer = m_doc->toPlainText().toUtf8(); const QByteArray buffer = m_doc->toPlainText().toUtf8();
for (const QTextBlock &block : blocks) for (const QTextBlock &block : blocks)

View File

@@ -53,7 +53,7 @@ public:
void autoIndent(const QTextCursor &cursor, void autoIndent(const QTextCursor &cursor,
const TextEditor::TabSettings &tabSettings, const TextEditor::TabSettings &tabSettings,
int cursorPositionInEditor = -1) override; int cursorPositionInEditor = -1) override;
TextEditor::Replacements format(const TextEditor::RangesInLines &rangesInLines) override; Utils::Text::Replacements format(const TextEditor::RangesInLines &rangesInLines) override;
void indentBlock(const QTextBlock &block, void indentBlock(const QTextBlock &block,
const QChar &typedChar, const QChar &typedChar,
@@ -78,17 +78,17 @@ private:
const QTextBlock &endBlock, const QTextBlock &endBlock,
const QChar &typedChar, const QChar &typedChar,
int cursorPositionInEditor); int cursorPositionInEditor);
TextEditor::Replacements indentsFor(QTextBlock startBlock, Utils::Text::Replacements indentsFor(QTextBlock startBlock,
const QTextBlock &endBlock, const QTextBlock &endBlock,
const QChar &typedChar, const QChar &typedChar,
int cursorPositionInEditor); int cursorPositionInEditor);
TextEditor::Replacements replacements(QByteArray buffer, Utils::Text::Replacements replacements(QByteArray buffer,
const QTextBlock &startBlock, const QTextBlock &startBlock,
const QTextBlock &endBlock, const QTextBlock &endBlock,
int cursorPositionInEditor, int cursorPositionInEditor,
ReplacementsToKeep replacementsToKeep, ReplacementsToKeep replacementsToKeep,
const QChar &typedChar = QChar::Null, const QChar &typedChar = QChar::Null,
bool secondTry = false) const; bool secondTry = false) const;
}; };
} // namespace ClangFormat } // namespace ClangFormat

View File

@@ -150,7 +150,7 @@ void FixitsRefactoringFile::format(TextEditor::Indenter &indenter,
const int end = doc->findBlock(op.pos + op.length).blockNumber() + 1; const int end = doc->findBlock(op.pos + op.length).blockNumber() + 1;
ranges.push_back({start, end}); ranges.push_back({start, end});
} }
const Replacements replacements = indenter.format(ranges); const Text::Replacements replacements = indenter.format(ranges);
if (replacements.empty()) if (replacements.empty())
return; return;
@@ -201,7 +201,7 @@ void FixitsRefactoringFile::shiftAffectedReplacements(const ReplacementOperation
} }
bool FixitsRefactoringFile::hasIntersection(const QString &fileName, bool FixitsRefactoringFile::hasIntersection(const QString &fileName,
const Replacements &replacements, const Text::Replacements &replacements,
int startIndex) const int startIndex) const
{ {
for (int i = startIndex; i < m_replacementOperations.size(); ++i) { for (int i = startIndex; i < m_replacementOperations.size(); ++i) {
@@ -212,7 +212,7 @@ bool FixitsRefactoringFile::hasIntersection(const QString &fileName,
// Usually the number of replacements is from 1 to 3. // Usually the number of replacements is from 1 to 3.
if (std::any_of(replacements.begin(), if (std::any_of(replacements.begin(),
replacements.end(), replacements.end(),
[&current](const Replacement &replacement) { [&current](const Text::Replacement &replacement) {
return replacement.offset + replacement.length > current.pos return replacement.offset + replacement.length > current.pos
&& replacement.offset < current.pos + current.length; && replacement.offset < current.pos + current.length;
})) { })) {
@@ -224,7 +224,7 @@ bool FixitsRefactoringFile::hasIntersection(const QString &fileName,
} }
void FixitsRefactoringFile::shiftAffectedReplacements(const QString &fileName, void FixitsRefactoringFile::shiftAffectedReplacements(const QString &fileName,
const Replacements &replacements, const Text::Replacements &replacements,
int startIndex) int startIndex)
{ {
for (int i = startIndex; i < m_replacementOperations.size(); ++i) { for (int i = startIndex; i < m_replacementOperations.size(); ++i) {

View File

@@ -72,10 +72,10 @@ private:
const ReplacementOperations &operationsForFile, const ReplacementOperations &operationsForFile,
int firstOperationIndex); int firstOperationIndex);
void shiftAffectedReplacements(const QString &fileName, void shiftAffectedReplacements(const QString &fileName,
const TextEditor::Replacements &replacements, const Utils::Text::Replacements &replacements,
int startIndex); int startIndex);
bool hasIntersection(const QString &fileName, bool hasIntersection(const QString &fileName,
const TextEditor::Replacements &replacements, const Utils::Text::Replacements &replacements,
int startIndex) const; int startIndex) const;
QString m_filePath; QString m_filePath;

View File

@@ -27,6 +27,7 @@
#include <utils/fileutils.h> #include <utils/fileutils.h>
#include <utils/optional.h> #include <utils/optional.h>
#include <utils/textutils.h>
#include <QMap> #include <QMap>
#include <QTextBlock> #include <QTextBlock>
@@ -43,21 +44,6 @@ class TabSettings;
using IndentationForBlock = QMap<int, int>; using IndentationForBlock = QMap<int, int>;
class Replacement
{
public:
Replacement(int offset, int length, const QString &text)
: offset(offset)
, length(length)
, text(text)
{}
int offset;
int length;
QString text;
};
using Replacements = std::vector<Replacement>;
class RangeInLines class RangeInLines
{ {
public: public:
@@ -100,9 +86,9 @@ public:
} }
// By default just calls indent with default settings. // By default just calls indent with default settings.
virtual Replacements format(const RangesInLines & /*rangesInLines*/) virtual Utils::Text::Replacements format(const RangesInLines & /*rangesInLines*/)
{ {
return Replacements(); return Utils::Text::Replacements();
} }
virtual bool formatOnSave() const { return false; } virtual bool formatOnSave() const { return false; }