forked from qt-creator/qt-creator
Utils: move text replacement helper to Utils::Text
Change-Id: I82b3304f91d575369e74d5f7404c189e14ba4730 Reviewed-by: Christian Stenger <christian.stenger@qt.io>
This commit is contained in:
@@ -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,
|
||||||
|
@@ -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 ¤tBlock)
|
const QTextBlock ¤tBlock)
|
||||||
{
|
{
|
||||||
@@ -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)
|
||||||
|
@@ -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
|
||||||
|
@@ -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(),
|
||||||
[¤t](const Replacement &replacement) {
|
[¤t](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) {
|
||||||
|
@@ -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;
|
||||||
|
@@ -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; }
|
||||||
|
Reference in New Issue
Block a user