forked from qt-creator/qt-creator
ClangFormat: Format edited chunks of file on save
The similar implementation to the one in Beautifier plugin with the difference that the clangformat indenter logic is used and only modified chunks are formatted. That means that all code which was not touched will stay in the initial condition. Change-Id: I47b11eb99852454ed0031ef6cfc6dbed1ecd390d Reviewed-by: Leena Miettinen <riitta-leena.miettinen@qt.io> Reviewed-by: Marco Bubke <marco.bubke@qt.io>
This commit is contained in:
@@ -131,6 +131,7 @@ void ClangFormatConfigWidget::hideGlobalCheckboxes()
|
|||||||
{
|
{
|
||||||
m_ui->formatAlways->hide();
|
m_ui->formatAlways->hide();
|
||||||
m_ui->formatWhileTyping->hide();
|
m_ui->formatWhileTyping->hide();
|
||||||
|
m_ui->formatOnSave->hide();
|
||||||
}
|
}
|
||||||
|
|
||||||
void ClangFormatConfigWidget::showGlobalCheckboxes()
|
void ClangFormatConfigWidget::showGlobalCheckboxes()
|
||||||
@@ -140,6 +141,9 @@ void ClangFormatConfigWidget::showGlobalCheckboxes()
|
|||||||
|
|
||||||
m_ui->formatWhileTyping->setChecked(ClangFormatSettings::instance().formatWhileTyping());
|
m_ui->formatWhileTyping->setChecked(ClangFormatSettings::instance().formatWhileTyping());
|
||||||
m_ui->formatWhileTyping->show();
|
m_ui->formatWhileTyping->show();
|
||||||
|
|
||||||
|
m_ui->formatOnSave->setChecked(ClangFormatSettings::instance().formatOnSave());
|
||||||
|
m_ui->formatOnSave->show();
|
||||||
}
|
}
|
||||||
|
|
||||||
void ClangFormatConfigWidget::initialize()
|
void ClangFormatConfigWidget::initialize()
|
||||||
@@ -200,7 +204,6 @@ void ClangFormatConfigWidget::fillTable()
|
|||||||
std::string configText = clang::format::configurationAsText(style);
|
std::string configText = clang::format::configurationAsText(style);
|
||||||
std::istringstream stream(configText);
|
std::istringstream stream(configText);
|
||||||
readTable(m_ui->clangFormatOptionsTable, stream);
|
readTable(m_ui->clangFormatOptionsTable, stream);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ClangFormatConfigWidget::~ClangFormatConfigWidget() = default;
|
ClangFormatConfigWidget::~ClangFormatConfigWidget() = default;
|
||||||
@@ -211,6 +214,7 @@ void ClangFormatConfigWidget::apply()
|
|||||||
ClangFormatSettings &settings = ClangFormatSettings::instance();
|
ClangFormatSettings &settings = ClangFormatSettings::instance();
|
||||||
settings.setFormatCodeInsteadOfIndent(m_ui->formatAlways->isChecked());
|
settings.setFormatCodeInsteadOfIndent(m_ui->formatAlways->isChecked());
|
||||||
settings.setFormatWhileTyping(m_ui->formatWhileTyping->isChecked());
|
settings.setFormatWhileTyping(m_ui->formatWhileTyping->isChecked());
|
||||||
|
settings.setFormatOnSave(m_ui->formatOnSave->isChecked());
|
||||||
settings.write();
|
settings.write();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@@ -40,6 +40,13 @@
|
|||||||
</property>
|
</property>
|
||||||
</widget>
|
</widget>
|
||||||
</item>
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QCheckBox" name="formatOnSave">
|
||||||
|
<property name="text">
|
||||||
|
<string>Format edited code on file save</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<widget class="QLabel" name="projectHasClangFormat">
|
<widget class="QLabel" name="projectHasClangFormat">
|
||||||
<property name="text">
|
<property name="text">
|
||||||
|
@@ -33,5 +33,6 @@ static const char SAMPLE_FILE_NAME[] = "test.cpp";
|
|||||||
static const char SETTINGS_ID[] = "ClangFormat";
|
static const char SETTINGS_ID[] = "ClangFormat";
|
||||||
static const char FORMAT_CODE_INSTEAD_OF_INDENT_ID[] = "ClangFormat.FormatCodeInsteadOfIndent";
|
static const char FORMAT_CODE_INSTEAD_OF_INDENT_ID[] = "ClangFormat.FormatCodeInsteadOfIndent";
|
||||||
static const char FORMAT_WHILE_TYPING_ID[] = "ClangFormat.FormatWhileTyping";
|
static const char FORMAT_WHILE_TYPING_ID[] = "ClangFormat.FormatWhileTyping";
|
||||||
|
static const char FORMAT_CODE_ON_SAVE_ID[] = "ClangFormat.FormatCodeOnSave";
|
||||||
} // namespace Constants
|
} // namespace Constants
|
||||||
} // namespace ClangFormat
|
} // namespace ClangFormat
|
||||||
|
@@ -87,4 +87,9 @@ int ClangFormatIndenter::lastSaveRevision() const
|
|||||||
return qobject_cast<TextEditor::TextDocumentLayout *>(m_doc->documentLayout())->lastSaveRevision;
|
return qobject_cast<TextEditor::TextDocumentLayout *>(m_doc->documentLayout())->lastSaveRevision;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool ClangFormatIndenter::formatOnSave() const
|
||||||
|
{
|
||||||
|
return ClangFormatSettings::instance().formatOnSave();
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace ClangFormat
|
} // namespace ClangFormat
|
||||||
|
@@ -36,6 +36,7 @@ class ClangFormatIndenter final : public ClangFormatBaseIndenter
|
|||||||
public:
|
public:
|
||||||
ClangFormatIndenter(QTextDocument *doc);
|
ClangFormatIndenter(QTextDocument *doc);
|
||||||
Utils::optional<TextEditor::TabSettings> tabSettings() const override;
|
Utils::optional<TextEditor::TabSettings> tabSettings() const override;
|
||||||
|
bool formatOnSave() const override;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
bool formatCodeInsteadOfIndent() const override;
|
bool formatCodeInsteadOfIndent() const override;
|
||||||
|
@@ -44,6 +44,8 @@ ClangFormatSettings::ClangFormatSettings()
|
|||||||
= settings->value(QLatin1String(Constants::FORMAT_CODE_INSTEAD_OF_INDENT_ID), false).toBool();
|
= settings->value(QLatin1String(Constants::FORMAT_CODE_INSTEAD_OF_INDENT_ID), false).toBool();
|
||||||
m_formatWhileTyping = settings->value(QLatin1String(Constants::FORMAT_WHILE_TYPING_ID), false)
|
m_formatWhileTyping = settings->value(QLatin1String(Constants::FORMAT_WHILE_TYPING_ID), false)
|
||||||
.toBool();
|
.toBool();
|
||||||
|
m_formatOnSave = settings->value(QLatin1String(Constants::FORMAT_CODE_ON_SAVE_ID), false)
|
||||||
|
.toBool();
|
||||||
settings->endGroup();
|
settings->endGroup();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -54,6 +56,7 @@ void ClangFormatSettings::write() const
|
|||||||
settings->setValue(QLatin1String(Constants::FORMAT_CODE_INSTEAD_OF_INDENT_ID),
|
settings->setValue(QLatin1String(Constants::FORMAT_CODE_INSTEAD_OF_INDENT_ID),
|
||||||
m_formatCodeInsteadOfIndent);
|
m_formatCodeInsteadOfIndent);
|
||||||
settings->setValue(QLatin1String(Constants::FORMAT_WHILE_TYPING_ID), m_formatWhileTyping);
|
settings->setValue(QLatin1String(Constants::FORMAT_WHILE_TYPING_ID), m_formatWhileTyping);
|
||||||
|
settings->setValue(QLatin1String(Constants::FORMAT_CODE_ON_SAVE_ID), m_formatOnSave);
|
||||||
settings->endGroup();
|
settings->endGroup();
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -77,4 +80,14 @@ bool ClangFormatSettings::formatWhileTyping() const
|
|||||||
return m_formatWhileTyping;
|
return m_formatWhileTyping;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ClangFormatSettings::setFormatOnSave(bool enable)
|
||||||
|
{
|
||||||
|
m_formatOnSave = enable;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ClangFormatSettings::formatOnSave() const
|
||||||
|
{
|
||||||
|
return m_formatOnSave;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace ClangFormat
|
} // namespace ClangFormat
|
||||||
|
@@ -40,9 +40,13 @@ public:
|
|||||||
|
|
||||||
void setFormatWhileTyping(bool enable);
|
void setFormatWhileTyping(bool enable);
|
||||||
bool formatWhileTyping() const;
|
bool formatWhileTyping() const;
|
||||||
|
|
||||||
|
void setFormatOnSave(bool enable);
|
||||||
|
bool formatOnSave() const;
|
||||||
private:
|
private:
|
||||||
bool m_formatCodeInsteadOfIndent = false;
|
bool m_formatCodeInsteadOfIndent = false;
|
||||||
bool m_formatWhileTyping = false;
|
bool m_formatWhileTyping = false;
|
||||||
|
bool m_formatOnSave = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace ClangFormat
|
} // namespace ClangFormat
|
||||||
|
@@ -44,6 +44,7 @@
|
|||||||
#include <projectexplorer/session.h>
|
#include <projectexplorer/session.h>
|
||||||
|
|
||||||
#include <texteditor/icodestylepreferencesfactory.h>
|
#include <texteditor/icodestylepreferencesfactory.h>
|
||||||
|
#include <texteditor/textdocumentlayout.h>
|
||||||
#include <texteditor/texteditorsettings.h>
|
#include <texteditor/texteditorsettings.h>
|
||||||
|
|
||||||
#include <coreplugin/editormanager/editormanager.h>
|
#include <coreplugin/editormanager/editormanager.h>
|
||||||
@@ -447,5 +448,47 @@ TextEditor::TabSettings CppEditorDocument::tabSettings() const
|
|||||||
return indenter()->tabSettings().value_or(TextEditor::TextDocument::tabSettings());
|
return indenter()->tabSettings().value_or(TextEditor::TextDocument::tabSettings());
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int formatRange(QTextDocument *doc,
|
||||||
|
TextEditor::Indenter *indenter,
|
||||||
|
std::pair<int, int> editedRange,
|
||||||
|
const TextEditor::TabSettings &tabSettings)
|
||||||
|
{
|
||||||
|
QTextCursor cursor(doc);
|
||||||
|
cursor.setPosition(editedRange.first);
|
||||||
|
cursor.setPosition(editedRange.second, QTextCursor::KeepAnchor);
|
||||||
|
const int oldBlockCount = doc->blockCount();
|
||||||
|
indenter->format(cursor, tabSettings);
|
||||||
|
return doc->blockCount() - oldBlockCount;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CppEditorDocument::save(QString *errorString, const QString &fileName, bool autoSave)
|
||||||
|
{
|
||||||
|
if (indenter()->formatOnSave()) {
|
||||||
|
auto *layout = qobject_cast<TextEditor::TextDocumentLayout *>(document()->documentLayout());
|
||||||
|
const int documentRevision = layout->lastSaveRevision;
|
||||||
|
|
||||||
|
std::pair<int, int> editedRange;
|
||||||
|
for (int i = 0; i < document()->blockCount(); ++i) {
|
||||||
|
const QTextBlock block = document()->findBlockByNumber(i);
|
||||||
|
if (block.revision() == documentRevision) {
|
||||||
|
if (editedRange.first != -1)
|
||||||
|
i += formatRange(document(), indenter(), editedRange, tabSettings());
|
||||||
|
|
||||||
|
editedRange = std::make_pair(-1, -1);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// block.revision() != documentRevision
|
||||||
|
if (editedRange.first == -1)
|
||||||
|
editedRange.first = block.position();
|
||||||
|
editedRange.second = block.position() + block.length();
|
||||||
|
}
|
||||||
|
if (editedRange.first != -1)
|
||||||
|
formatRange(document(), indenter(), editedRange, tabSettings());
|
||||||
|
}
|
||||||
|
|
||||||
|
return TextEditor::TextDocument::save(errorString, fileName, autoSave);
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace Internal
|
} // namespace Internal
|
||||||
} // namespace CppEditor
|
} // namespace CppEditor
|
||||||
|
@@ -69,6 +69,10 @@ public:
|
|||||||
QFuture<CppTools::CursorInfo> cursorInfo(const CppTools::CursorInfoParams ¶ms);
|
QFuture<CppTools::CursorInfo> cursorInfo(const CppTools::CursorInfoParams ¶ms);
|
||||||
TextEditor::TabSettings tabSettings() const override;
|
TextEditor::TabSettings tabSettings() const override;
|
||||||
|
|
||||||
|
bool save(QString *errorString,
|
||||||
|
const QString &fileName = QString(),
|
||||||
|
bool autoSave = false) override;
|
||||||
|
|
||||||
signals:
|
signals:
|
||||||
void codeWarningsUpdated(unsigned contentsRevision,
|
void codeWarningsUpdated(unsigned contentsRevision,
|
||||||
const QList<QTextEdit::ExtraSelection> selections,
|
const QList<QTextEdit::ExtraSelection> selections,
|
||||||
|
@@ -99,6 +99,8 @@ public:
|
|||||||
return Replacements();
|
return Replacements();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
virtual bool formatOnSave() const { return false; }
|
||||||
|
|
||||||
// Expects a list of blocks in order of occurrence in the document.
|
// Expects a list of blocks in order of occurrence in the document.
|
||||||
virtual IndentationForBlock indentationForBlocks(const QVector<QTextBlock> &blocks,
|
virtual IndentationForBlock indentationForBlocks(const QVector<QTextBlock> &blocks,
|
||||||
const TabSettings &tabSettings,
|
const TabSettings &tabSettings,
|
||||||
|
Reference in New Issue
Block a user