forked from qt-creator/qt-creator
ClangFormat: Pimpl ClangFormatBaseIndenter
This avoids the large-scale exposure of #include <clang/Format/Format.h> which otherwise confuses moc. Change-Id: I1d48174bd5f940e03986b58a7efa5e537cc99781 Reviewed-by: Jarek Kobus <jaroslaw.kobus@qt.io>
This commit is contained in:
@@ -23,10 +23,15 @@
|
|||||||
#include <QDebug>
|
#include <QDebug>
|
||||||
#include <QTextDocument>
|
#include <QTextDocument>
|
||||||
|
|
||||||
|
#include <clang/Format/Format.h>
|
||||||
#include <clang/Tooling/Core/Replacement.h>
|
#include <clang/Tooling/Core/Replacement.h>
|
||||||
|
|
||||||
|
using namespace Utils;
|
||||||
|
|
||||||
namespace ClangFormat {
|
namespace ClangFormat {
|
||||||
|
|
||||||
|
enum class ReplacementsToKeep { OnlyIndent, IndentAndBefore, All };
|
||||||
|
|
||||||
Internal::LlvmFileSystemAdapter llvmFileSystemAdapter = {};
|
Internal::LlvmFileSystemAdapter llvmFileSystemAdapter = {};
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
@@ -490,11 +495,63 @@ int formattingRangeStart(const QTextBlock ¤tBlock,
|
|||||||
}
|
}
|
||||||
} // namespace
|
} // namespace
|
||||||
|
|
||||||
|
class ClangFormatBaseIndenterPrivate final
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ClangFormatBaseIndenterPrivate(ClangFormatBaseIndenter *parent, QTextDocument *doc, FilePath *fileName)
|
||||||
|
: q(parent), m_doc(doc), m_fileName(fileName)
|
||||||
|
{}
|
||||||
|
|
||||||
|
void indent(const QTextCursor &cursor, const QChar &typedChar, int cursorPositionInEditor);
|
||||||
|
void indentBlocks(const QTextBlock &startBlock,
|
||||||
|
const QTextBlock &endBlock,
|
||||||
|
const QChar &typedChar,
|
||||||
|
int cursorPositionInEditor);
|
||||||
|
ChangeSet indentsFor(QTextBlock startBlock,
|
||||||
|
const QTextBlock &endBlock,
|
||||||
|
const QChar &typedChar,
|
||||||
|
int cursorPositionInEditor,
|
||||||
|
bool trimTrailingWhitespace = true);
|
||||||
|
ChangeSet replacements(QByteArray buffer,
|
||||||
|
const QTextBlock &startBlock,
|
||||||
|
const QTextBlock &endBlock,
|
||||||
|
int cursorPositionInEditor,
|
||||||
|
ReplacementsToKeep replacementsToKeep,
|
||||||
|
const QChar &typedChar = QChar::Null,
|
||||||
|
bool secondTry = false) const;
|
||||||
|
|
||||||
|
const clang::format::FormatStyle &styleForFile() const;
|
||||||
|
|
||||||
|
ClangFormatBaseIndenter *q;
|
||||||
|
QTextDocument *m_doc;
|
||||||
|
FilePath *m_fileName;
|
||||||
|
|
||||||
|
struct CachedStyle {
|
||||||
|
clang::format::FormatStyle style = clang::format::getNoStyle();
|
||||||
|
QDateTime expirationTime;
|
||||||
|
void setCache(clang::format::FormatStyle newStyle, std::chrono::milliseconds timeout)
|
||||||
|
{
|
||||||
|
style = newStyle;
|
||||||
|
expirationTime = QDateTime::currentDateTime().addMSecs(timeout.count());
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
mutable CachedStyle m_cachedStyle;
|
||||||
|
|
||||||
|
clang::format::FormatStyle customSettingsStyle(const FilePath &fileName) const;
|
||||||
|
TextEditor::ICodeStylePreferences *m_overriddenPreferences = nullptr;
|
||||||
|
};
|
||||||
|
|
||||||
ClangFormatBaseIndenter::ClangFormatBaseIndenter(QTextDocument *doc)
|
ClangFormatBaseIndenter::ClangFormatBaseIndenter(QTextDocument *doc)
|
||||||
: TextEditor::Indenter(doc)
|
: TextEditor::Indenter(doc), d(new ClangFormatBaseIndenterPrivate(this, doc, &m_fileName))
|
||||||
{}
|
{}
|
||||||
|
|
||||||
Utils::ChangeSet ClangFormatBaseIndenter::replacements(QByteArray buffer,
|
ClangFormatBaseIndenter::~ClangFormatBaseIndenter()
|
||||||
|
{
|
||||||
|
delete d;
|
||||||
|
}
|
||||||
|
|
||||||
|
ChangeSet ClangFormatBaseIndenterPrivate::replacements(QByteArray buffer,
|
||||||
const QTextBlock &startBlock,
|
const QTextBlock &startBlock,
|
||||||
const QTextBlock &endBlock,
|
const QTextBlock &endBlock,
|
||||||
int cursorPositionInEditor,
|
int cursorPositionInEditor,
|
||||||
@@ -503,7 +560,7 @@ Utils::ChangeSet ClangFormatBaseIndenter::replacements(QByteArray buffer,
|
|||||||
bool secondTry) const
|
bool secondTry) const
|
||||||
{
|
{
|
||||||
QTC_ASSERT(replacementsToKeep != ReplacementsToKeep::All, return Utils::ChangeSet());
|
QTC_ASSERT(replacementsToKeep != ReplacementsToKeep::All, return Utils::ChangeSet());
|
||||||
QTC_ASSERT(!m_fileName.isEmpty(), return {});
|
QTC_ASSERT(!m_fileName->isEmpty(), return {});
|
||||||
|
|
||||||
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);
|
||||||
@@ -512,7 +569,7 @@ Utils::ChangeSet ClangFormatBaseIndenter::replacements(QByteArray buffer,
|
|||||||
|
|
||||||
int rangeStart = 0;
|
int rangeStart = 0;
|
||||||
if (replacementsToKeep == ReplacementsToKeep::IndentAndBefore)
|
if (replacementsToKeep == ReplacementsToKeep::IndentAndBefore)
|
||||||
rangeStart = formattingRangeStart(startBlock, buffer, lastSaveRevision());
|
rangeStart = formattingRangeStart(startBlock, buffer, q->lastSaveRevision());
|
||||||
|
|
||||||
clang::format::FormatStyle style = styleForFile();
|
clang::format::FormatStyle style = styleForFile();
|
||||||
adjustFormatStyleForLineBreak(style, replacementsToKeep);
|
adjustFormatStyleForLineBreak(style, replacementsToKeep);
|
||||||
@@ -535,7 +592,7 @@ Utils::ChangeSet ClangFormatBaseIndenter::replacements(QByteArray buffer,
|
|||||||
|
|
||||||
clang::format::FormattingAttemptStatus status;
|
clang::format::FormattingAttemptStatus status;
|
||||||
clang::tooling::Replacements clangReplacements = clang::format::reformat(
|
clang::tooling::Replacements clangReplacements = clang::format::reformat(
|
||||||
style, buffer.data(), ranges, m_fileName.toFSPathString().toStdString(), &status);
|
style, buffer.data(), ranges, m_fileName->toFSPathString().toStdString(), &status);
|
||||||
|
|
||||||
clang::tooling::Replacements filtered;
|
clang::tooling::Replacements filtered;
|
||||||
if (status.FormatComplete) {
|
if (status.FormatComplete) {
|
||||||
@@ -611,7 +668,7 @@ Utils::EditOperations ClangFormatBaseIndenter::format(const TextEditor::RangesIn
|
|||||||
return editOperations;
|
return editOperations;
|
||||||
}
|
}
|
||||||
|
|
||||||
Utils::ChangeSet ClangFormatBaseIndenter::indentsFor(QTextBlock startBlock,
|
ChangeSet ClangFormatBaseIndenterPrivate::indentsFor(QTextBlock startBlock,
|
||||||
const QTextBlock &endBlock,
|
const QTextBlock &endBlock,
|
||||||
const QChar &typedChar,
|
const QChar &typedChar,
|
||||||
int cursorPositionInEditor,
|
int cursorPositionInEditor,
|
||||||
@@ -634,7 +691,7 @@ Utils::ChangeSet ClangFormatBaseIndenter::indentsFor(QTextBlock startBlock,
|
|||||||
const QByteArray buffer = m_doc->toPlainText().toUtf8();
|
const QByteArray buffer = m_doc->toPlainText().toUtf8();
|
||||||
|
|
||||||
ReplacementsToKeep replacementsToKeep = ReplacementsToKeep::OnlyIndent;
|
ReplacementsToKeep replacementsToKeep = ReplacementsToKeep::OnlyIndent;
|
||||||
if (formatWhileTyping()
|
if (q->formatWhileTyping()
|
||||||
&& (cursorPositionInEditor == -1 || cursorPositionInEditor >= startBlockPosition)
|
&& (cursorPositionInEditor == -1 || cursorPositionInEditor >= startBlockPosition)
|
||||||
&& (typedChar == ';' || typedChar == '}')) {
|
&& (typedChar == ';' || typedChar == '}')) {
|
||||||
// Format before current position only in case the cursor is inside the indented block.
|
// Format before current position only in case the cursor is inside the indented block.
|
||||||
@@ -654,7 +711,7 @@ Utils::ChangeSet ClangFormatBaseIndenter::indentsFor(QTextBlock startBlock,
|
|||||||
typedChar);
|
typedChar);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ClangFormatBaseIndenter::indentBlocks(const QTextBlock &startBlock,
|
void ClangFormatBaseIndenterPrivate::indentBlocks(const QTextBlock &startBlock,
|
||||||
const QTextBlock &endBlock,
|
const QTextBlock &endBlock,
|
||||||
const QChar &typedChar,
|
const QChar &typedChar,
|
||||||
int cursorPositionInEditor)
|
int cursorPositionInEditor)
|
||||||
@@ -663,7 +720,7 @@ void ClangFormatBaseIndenter::indentBlocks(const QTextBlock &startBlock,
|
|||||||
changeset.apply(m_doc);
|
changeset.apply(m_doc);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ClangFormatBaseIndenter::indent(const QTextCursor &cursor,
|
void ClangFormatBaseIndenterPrivate::indent(const QTextCursor &cursor,
|
||||||
const QChar &typedChar,
|
const QChar &typedChar,
|
||||||
int cursorPositionInEditor)
|
int cursorPositionInEditor)
|
||||||
{
|
{
|
||||||
@@ -682,14 +739,14 @@ void ClangFormatBaseIndenter::indent(const QTextCursor &cursor,
|
|||||||
const TextEditor::TabSettings & /*tabSettings*/,
|
const TextEditor::TabSettings & /*tabSettings*/,
|
||||||
int cursorPositionInEditor)
|
int cursorPositionInEditor)
|
||||||
{
|
{
|
||||||
indent(cursor, typedChar, cursorPositionInEditor);
|
d->indent(cursor, typedChar, cursorPositionInEditor);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ClangFormatBaseIndenter::reindent(const QTextCursor &cursor,
|
void ClangFormatBaseIndenter::reindent(const QTextCursor &cursor,
|
||||||
const TextEditor::TabSettings & /*tabSettings*/,
|
const TextEditor::TabSettings & /*tabSettings*/,
|
||||||
int cursorPositionInEditor)
|
int cursorPositionInEditor)
|
||||||
{
|
{
|
||||||
indent(cursor, QChar::Null, cursorPositionInEditor);
|
d->indent(cursor, QChar::Null, cursorPositionInEditor);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ClangFormatBaseIndenter::indentBlock(const QTextBlock &block,
|
void ClangFormatBaseIndenter::indentBlock(const QTextBlock &block,
|
||||||
@@ -697,7 +754,7 @@ void ClangFormatBaseIndenter::indentBlock(const QTextBlock &block,
|
|||||||
const TextEditor::TabSettings & /*tabSettings*/,
|
const TextEditor::TabSettings & /*tabSettings*/,
|
||||||
int cursorPositionInEditor)
|
int cursorPositionInEditor)
|
||||||
{
|
{
|
||||||
indentBlocks(block, block, typedChar, cursorPositionInEditor);
|
d->indentBlocks(block, block, typedChar, cursorPositionInEditor);
|
||||||
}
|
}
|
||||||
|
|
||||||
int ClangFormatBaseIndenter::indentFor(const QTextBlock &block,
|
int ClangFormatBaseIndenter::indentFor(const QTextBlock &block,
|
||||||
@@ -705,7 +762,7 @@ int ClangFormatBaseIndenter::indentFor(const QTextBlock &block,
|
|||||||
int cursorPositionInEditor)
|
int cursorPositionInEditor)
|
||||||
{
|
{
|
||||||
Utils::ChangeSet toReplace
|
Utils::ChangeSet toReplace
|
||||||
= indentsFor(block, block, QChar::Null, cursorPositionInEditor, false);
|
= d->indentsFor(block, block, QChar::Null, cursorPositionInEditor, false);
|
||||||
if (toReplace.isEmpty())
|
if (toReplace.isEmpty())
|
||||||
return -1;
|
return -1;
|
||||||
|
|
||||||
@@ -721,7 +778,7 @@ TextEditor::IndentationForBlock ClangFormatBaseIndenter::indentationForBlocks(
|
|||||||
TextEditor::IndentationForBlock ret;
|
TextEditor::IndentationForBlock ret;
|
||||||
if (blocks.isEmpty())
|
if (blocks.isEmpty())
|
||||||
return ret;
|
return ret;
|
||||||
Utils::ChangeSet toReplace = indentsFor(blocks.front(),
|
Utils::ChangeSet toReplace = d->indentsFor(blocks.front(),
|
||||||
blocks.back(),
|
blocks.back(),
|
||||||
QChar::Null,
|
QChar::Null,
|
||||||
cursorPositionInEditor);
|
cursorPositionInEditor);
|
||||||
@@ -769,11 +826,11 @@ void ClangFormatBaseIndenter::autoIndent(const QTextCursor &cursor,
|
|||||||
}
|
}
|
||||||
format({{start.blockNumber() + 1, end.blockNumber() + 1}});
|
format({{start.blockNumber() + 1, end.blockNumber() + 1}});
|
||||||
} else {
|
} else {
|
||||||
indent(cursor, QChar::Null, cursorPositionInEditor);
|
d->indent(cursor, QChar::Null, cursorPositionInEditor);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
clang::format::FormatStyle ClangFormatBaseIndenter::customSettingsStyle(
|
clang::format::FormatStyle ClangFormatBaseIndenterPrivate::customSettingsStyle(
|
||||||
const Utils::FilePath &fileName) const
|
const Utils::FilePath &fileName) const
|
||||||
{
|
{
|
||||||
const ProjectExplorer::Project *projectForFile
|
const ProjectExplorer::Project *projectForFile
|
||||||
@@ -808,6 +865,11 @@ static std::chrono::milliseconds getCacheTimeout()
|
|||||||
}
|
}
|
||||||
|
|
||||||
const clang::format::FormatStyle &ClangFormatBaseIndenter::styleForFile() const
|
const clang::format::FormatStyle &ClangFormatBaseIndenter::styleForFile() const
|
||||||
|
{
|
||||||
|
return d->styleForFile();
|
||||||
|
}
|
||||||
|
|
||||||
|
const clang::format::FormatStyle &ClangFormatBaseIndenterPrivate::styleForFile() const
|
||||||
{
|
{
|
||||||
using namespace std::chrono_literals;
|
using namespace std::chrono_literals;
|
||||||
static const std::chrono::milliseconds cacheTimeout = getCacheTimeout();
|
static const std::chrono::milliseconds cacheTimeout = getCacheTimeout();
|
||||||
@@ -816,15 +878,15 @@ const clang::format::FormatStyle &ClangFormatBaseIndenter::styleForFile() const
|
|||||||
if (m_cachedStyle.expirationTime > time && !(m_cachedStyle.style == clang::format::getNoStyle()))
|
if (m_cachedStyle.expirationTime > time && !(m_cachedStyle.style == clang::format::getNoStyle()))
|
||||||
return m_cachedStyle.style;
|
return m_cachedStyle.style;
|
||||||
|
|
||||||
if (getCurrentCustomSettings(m_fileName)) {
|
if (getCurrentCustomSettings(*m_fileName)) {
|
||||||
clang::format::FormatStyle style = customSettingsStyle(m_fileName);
|
clang::format::FormatStyle style = customSettingsStyle(*m_fileName);
|
||||||
m_cachedStyle.setCache(style, cacheTimeout);
|
m_cachedStyle.setCache(style, cacheTimeout);
|
||||||
return m_cachedStyle.style;
|
return m_cachedStyle.style;
|
||||||
}
|
}
|
||||||
|
|
||||||
llvm::Expected<clang::format::FormatStyle> styleFromProjectFolder
|
llvm::Expected<clang::format::FormatStyle> styleFromProjectFolder
|
||||||
= clang::format::getStyle("file",
|
= clang::format::getStyle("file",
|
||||||
m_fileName.toFSPathString().toStdString(),
|
m_fileName->toFSPathString().toStdString(),
|
||||||
"none",
|
"none",
|
||||||
"",
|
"",
|
||||||
&llvmFileSystemAdapter);
|
&llvmFileSystemAdapter);
|
||||||
@@ -846,7 +908,7 @@ const clang::format::FormatStyle &ClangFormatBaseIndenter::styleForFile() const
|
|||||||
|
|
||||||
void ClangFormatBaseIndenter::setOverriddenPreferences(TextEditor::ICodeStylePreferences *preferences)
|
void ClangFormatBaseIndenter::setOverriddenPreferences(TextEditor::ICodeStylePreferences *preferences)
|
||||||
{
|
{
|
||||||
m_overriddenPreferences = preferences;
|
d->m_overriddenPreferences = preferences;
|
||||||
}
|
}
|
||||||
|
|
||||||
} // namespace ClangFormat
|
} // namespace ClangFormat
|
||||||
|
@@ -5,16 +5,15 @@
|
|||||||
|
|
||||||
#include <texteditor/indenter.h>
|
#include <texteditor/indenter.h>
|
||||||
|
|
||||||
#include <clang/Format/Format.h>
|
namespace clang::format { struct FormatStyle; }
|
||||||
|
|
||||||
namespace ClangFormat {
|
namespace ClangFormat {
|
||||||
|
|
||||||
enum class ReplacementsToKeep { OnlyIndent, IndentAndBefore, All };
|
|
||||||
|
|
||||||
class ClangFormatBaseIndenter : public TextEditor::Indenter
|
class ClangFormatBaseIndenter : public TextEditor::Indenter
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
ClangFormatBaseIndenter(QTextDocument *doc);
|
ClangFormatBaseIndenter(QTextDocument *doc);
|
||||||
|
~ClangFormatBaseIndenter();
|
||||||
|
|
||||||
TextEditor::IndentationForBlock indentationForBlocks(const QVector<QTextBlock> &blocks,
|
TextEditor::IndentationForBlock indentationForBlocks(const QVector<QTextBlock> &blocks,
|
||||||
const TextEditor::TabSettings &tabSettings,
|
const TextEditor::TabSettings &tabSettings,
|
||||||
@@ -57,38 +56,8 @@ protected:
|
|||||||
virtual int lastSaveRevision() const { return 0; }
|
virtual int lastSaveRevision() const { return 0; }
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void indent(const QTextCursor &cursor, const QChar &typedChar, int cursorPositionInEditor);
|
friend class ClangFormatBaseIndenterPrivate;
|
||||||
void indentBlocks(const QTextBlock &startBlock,
|
class ClangFormatBaseIndenterPrivate *d = nullptr;
|
||||||
const QTextBlock &endBlock,
|
|
||||||
const QChar &typedChar,
|
|
||||||
int cursorPositionInEditor);
|
|
||||||
Utils::ChangeSet indentsFor(QTextBlock startBlock,
|
|
||||||
const QTextBlock &endBlock,
|
|
||||||
const QChar &typedChar,
|
|
||||||
int cursorPositionInEditor,
|
|
||||||
bool trimTrailingWhitespace = true);
|
|
||||||
Utils::ChangeSet replacements(QByteArray buffer,
|
|
||||||
const QTextBlock &startBlock,
|
|
||||||
const QTextBlock &endBlock,
|
|
||||||
int cursorPositionInEditor,
|
|
||||||
ReplacementsToKeep replacementsToKeep,
|
|
||||||
const QChar &typedChar = QChar::Null,
|
|
||||||
bool secondTry = false) const;
|
|
||||||
|
|
||||||
struct CachedStyle {
|
|
||||||
clang::format::FormatStyle style = clang::format::getNoStyle();
|
|
||||||
QDateTime expirationTime;
|
|
||||||
void setCache(clang::format::FormatStyle newStyle, std::chrono::milliseconds timeout)
|
|
||||||
{
|
|
||||||
style = newStyle;
|
|
||||||
expirationTime = QDateTime::currentDateTime().addMSecs(timeout.count());
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
mutable CachedStyle m_cachedStyle;
|
|
||||||
|
|
||||||
clang::format::FormatStyle customSettingsStyle(const Utils::FilePath &fileName) const;
|
|
||||||
TextEditor::ICodeStylePreferences *m_overriddenPreferences = nullptr;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace ClangFormat
|
} // namespace ClangFormat
|
||||||
|
Reference in New Issue
Block a user