diff --git a/src/plugins/clangformat/clangformatconfigwidget.cpp b/src/plugins/clangformat/clangformatconfigwidget.cpp index bcede8c0101..f0d4808cf5c 100644 --- a/src/plugins/clangformat/clangformatconfigwidget.cpp +++ b/src/plugins/clangformat/clangformatconfigwidget.cpp @@ -131,6 +131,7 @@ void ClangFormatConfigWidget::hideGlobalCheckboxes() { m_ui->formatAlways->hide(); m_ui->formatWhileTyping->hide(); + m_ui->formatOnSave->hide(); } void ClangFormatConfigWidget::showGlobalCheckboxes() @@ -140,6 +141,9 @@ void ClangFormatConfigWidget::showGlobalCheckboxes() m_ui->formatWhileTyping->setChecked(ClangFormatSettings::instance().formatWhileTyping()); m_ui->formatWhileTyping->show(); + + m_ui->formatOnSave->setChecked(ClangFormatSettings::instance().formatOnSave()); + m_ui->formatOnSave->show(); } void ClangFormatConfigWidget::initialize() @@ -200,7 +204,6 @@ void ClangFormatConfigWidget::fillTable() std::string configText = clang::format::configurationAsText(style); std::istringstream stream(configText); readTable(m_ui->clangFormatOptionsTable, stream); - } ClangFormatConfigWidget::~ClangFormatConfigWidget() = default; @@ -211,6 +214,7 @@ void ClangFormatConfigWidget::apply() ClangFormatSettings &settings = ClangFormatSettings::instance(); settings.setFormatCodeInsteadOfIndent(m_ui->formatAlways->isChecked()); settings.setFormatWhileTyping(m_ui->formatWhileTyping->isChecked()); + settings.setFormatOnSave(m_ui->formatOnSave->isChecked()); settings.write(); } diff --git a/src/plugins/clangformat/clangformatconfigwidget.ui b/src/plugins/clangformat/clangformatconfigwidget.ui index 37f228e97cc..2094bca1090 100644 --- a/src/plugins/clangformat/clangformatconfigwidget.ui +++ b/src/plugins/clangformat/clangformatconfigwidget.ui @@ -40,6 +40,13 @@ + + + + Format edited code on file save + + + diff --git a/src/plugins/clangformat/clangformatconstants.h b/src/plugins/clangformat/clangformatconstants.h index 40b43e56407..8b7cbcf9bd2 100644 --- a/src/plugins/clangformat/clangformatconstants.h +++ b/src/plugins/clangformat/clangformatconstants.h @@ -33,5 +33,6 @@ static const char SAMPLE_FILE_NAME[] = "test.cpp"; static const char SETTINGS_ID[] = "ClangFormat"; static const char FORMAT_CODE_INSTEAD_OF_INDENT_ID[] = "ClangFormat.FormatCodeInsteadOfIndent"; static const char FORMAT_WHILE_TYPING_ID[] = "ClangFormat.FormatWhileTyping"; +static const char FORMAT_CODE_ON_SAVE_ID[] = "ClangFormat.FormatCodeOnSave"; } // namespace Constants } // namespace ClangFormat diff --git a/src/plugins/clangformat/clangformatindenter.cpp b/src/plugins/clangformat/clangformatindenter.cpp index f1ece90164a..ef9dbf5d1ca 100644 --- a/src/plugins/clangformat/clangformatindenter.cpp +++ b/src/plugins/clangformat/clangformatindenter.cpp @@ -87,4 +87,9 @@ int ClangFormatIndenter::lastSaveRevision() const return qobject_cast(m_doc->documentLayout())->lastSaveRevision; } +bool ClangFormatIndenter::formatOnSave() const +{ + return ClangFormatSettings::instance().formatOnSave(); +} + } // namespace ClangFormat diff --git a/src/plugins/clangformat/clangformatindenter.h b/src/plugins/clangformat/clangformatindenter.h index dca5f583a64..6d605eb5c91 100644 --- a/src/plugins/clangformat/clangformatindenter.h +++ b/src/plugins/clangformat/clangformatindenter.h @@ -36,6 +36,7 @@ class ClangFormatIndenter final : public ClangFormatBaseIndenter public: ClangFormatIndenter(QTextDocument *doc); Utils::optional tabSettings() const override; + bool formatOnSave() const override; private: bool formatCodeInsteadOfIndent() const override; diff --git a/src/plugins/clangformat/clangformatsettings.cpp b/src/plugins/clangformat/clangformatsettings.cpp index d8369bf5efd..8be2b3cefee 100644 --- a/src/plugins/clangformat/clangformatsettings.cpp +++ b/src/plugins/clangformat/clangformatsettings.cpp @@ -44,6 +44,8 @@ ClangFormatSettings::ClangFormatSettings() = settings->value(QLatin1String(Constants::FORMAT_CODE_INSTEAD_OF_INDENT_ID), false).toBool(); m_formatWhileTyping = settings->value(QLatin1String(Constants::FORMAT_WHILE_TYPING_ID), false) .toBool(); + m_formatOnSave = settings->value(QLatin1String(Constants::FORMAT_CODE_ON_SAVE_ID), false) + .toBool(); settings->endGroup(); } @@ -54,6 +56,7 @@ void ClangFormatSettings::write() const settings->setValue(QLatin1String(Constants::FORMAT_CODE_INSTEAD_OF_INDENT_ID), m_formatCodeInsteadOfIndent); settings->setValue(QLatin1String(Constants::FORMAT_WHILE_TYPING_ID), m_formatWhileTyping); + settings->setValue(QLatin1String(Constants::FORMAT_CODE_ON_SAVE_ID), m_formatOnSave); settings->endGroup(); } @@ -77,4 +80,14 @@ bool ClangFormatSettings::formatWhileTyping() const return m_formatWhileTyping; } +void ClangFormatSettings::setFormatOnSave(bool enable) +{ + m_formatOnSave = enable; +} + +bool ClangFormatSettings::formatOnSave() const +{ + return m_formatOnSave; +} + } // namespace ClangFormat diff --git a/src/plugins/clangformat/clangformatsettings.h b/src/plugins/clangformat/clangformatsettings.h index 4a62eb83035..0ea9ed9747e 100644 --- a/src/plugins/clangformat/clangformatsettings.h +++ b/src/plugins/clangformat/clangformatsettings.h @@ -40,9 +40,13 @@ public: void setFormatWhileTyping(bool enable); bool formatWhileTyping() const; + + void setFormatOnSave(bool enable); + bool formatOnSave() const; private: bool m_formatCodeInsteadOfIndent = false; bool m_formatWhileTyping = false; + bool m_formatOnSave = false; }; } // namespace ClangFormat diff --git a/src/plugins/cppeditor/cppeditordocument.cpp b/src/plugins/cppeditor/cppeditordocument.cpp index c8951c12ebc..d18735c7501 100644 --- a/src/plugins/cppeditor/cppeditordocument.cpp +++ b/src/plugins/cppeditor/cppeditordocument.cpp @@ -44,6 +44,7 @@ #include #include +#include #include #include @@ -447,5 +448,47 @@ TextEditor::TabSettings CppEditorDocument::tabSettings() const return indenter()->tabSettings().value_or(TextEditor::TextDocument::tabSettings()); } +static int formatRange(QTextDocument *doc, + TextEditor::Indenter *indenter, + std::pair 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(document()->documentLayout()); + const int documentRevision = layout->lastSaveRevision; + + std::pair 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 CppEditor diff --git a/src/plugins/cppeditor/cppeditordocument.h b/src/plugins/cppeditor/cppeditordocument.h index 44fe04becb7..26cff2043aa 100644 --- a/src/plugins/cppeditor/cppeditordocument.h +++ b/src/plugins/cppeditor/cppeditordocument.h @@ -69,6 +69,10 @@ public: QFuture cursorInfo(const CppTools::CursorInfoParams ¶ms); TextEditor::TabSettings tabSettings() const override; + bool save(QString *errorString, + const QString &fileName = QString(), + bool autoSave = false) override; + signals: void codeWarningsUpdated(unsigned contentsRevision, const QList selections, diff --git a/src/plugins/texteditor/indenter.h b/src/plugins/texteditor/indenter.h index bb23c9d7ac2..2907ea783ce 100644 --- a/src/plugins/texteditor/indenter.h +++ b/src/plugins/texteditor/indenter.h @@ -99,6 +99,8 @@ public: return Replacements(); } + virtual bool formatOnSave() const { return false; } + // Expects a list of blocks in order of occurrence in the document. virtual IndentationForBlock indentationForBlocks(const QVector &blocks, const TabSettings &tabSettings,