ClangFormat: Synchronize ClangFormat settings with CppEditor codestyle

Added synchronization between ClangFormat codestyle settings and
CppEditors codestyle settings. All changes which will be done in
ClangFormat settings tab settings tabs will be automatically
retranslated to CppEditor codestyle settings tabs and vice versa.

Change-Id: I408d726c12552856e3c1b72d3ba09b77fff83321
Reviewed-by: Qt CI Bot <qt_ci_bot@qt-project.org>
Reviewed-by: Christian Kandeler <christian.kandeler@qt.io>
This commit is contained in:
Artem Sokolovskii
2021-11-01 16:20:08 +01:00
parent 85b5a887e8
commit a997161dd6
11 changed files with 262 additions and 32 deletions

View File

@@ -37,6 +37,7 @@
#include <coreplugin/icore.h>
#include <cppeditor/cpphighlighter.h>
#include <cppeditor/cppcodestylesettings.h>
#include <cppeditor/cppcodestylesnippets.h>
#include <extensionsystem/pluginmanager.h>
#include <extensionsystem/pluginspec.h>
@@ -115,7 +116,7 @@ void ClangFormatConfigWidget::showEvent(QShowEvent *event)
}
ClangFormatConfigWidget::ClangFormatConfigWidget(ProjectExplorer::Project *project, QWidget *parent)
: CodeStyleEditorWidget(parent)
: CppCodeStyleWidget(parent)
, m_project(project)
, m_checks(std::make_unique<Ui::ClangFormatChecksWidget>())
, m_ui(std::make_unique<Ui::ClangFormatConfigWidget>())
@@ -438,6 +439,29 @@ void ClangFormatConfigWidget::saveChanges(QObject *sender)
fillTable();
updatePreview();
synchronize();
}
void ClangFormatConfigWidget::setCodeStyleSettings(const CppEditor::CppCodeStyleSettings &settings)
{
m_config->fromCppCodeStyleSettings(settings);
fillTable();
updatePreview();
}
void ClangFormatConfigWidget::setTabSettings(const TextEditor::TabSettings &settings)
{
m_config->fromTabSettings(settings);
fillTable();
updatePreview();
}
void ClangFormatConfigWidget::synchronize()
{
emit codeStyleSettingsChanged(m_config->toCppCodeStyleSettings(m_project));
emit tabSettingsChanged(m_config->toTabSettings(m_project));
}
void ClangFormatConfigWidget::apply()

View File

@@ -25,18 +25,15 @@
#pragma once
#include <texteditor/icodestylepreferencesfactory.h>
#include <cppeditor/cppcodestylesettingspage.h>
#include <QScrollArea>
#include <memory>
namespace ProjectExplorer {
class Project;
}
namespace TextEditor {
class SnippetEditorWidget;
}
namespace ProjectExplorer { class Project; }
namespace TextEditor { class SnippetEditorWidget; }
namespace CppEditor { class CppCodeStyleSettings; }
namespace ClangFormat {
@@ -46,7 +43,7 @@ class ClangFormatChecksWidget;
}
class ClangFormatFile;
class ClangFormatConfigWidget : public TextEditor::CodeStyleEditorWidget
class ClangFormatConfigWidget : public CppEditor::CppCodeStyleWidget
{
Q_OBJECT
@@ -55,6 +52,9 @@ public:
QWidget *parent = nullptr);
~ClangFormatConfigWidget() override;
void apply() override;
void setCodeStyleSettings(const CppEditor::CppCodeStyleSettings &settings) override;
void setTabSettings(const TextEditor::TabSettings &settings) override;
void synchronize() override;
private:
void onTableChanged();

View File

@@ -24,6 +24,12 @@
****************************************************************************/
#include "clangformatfile.h"
#include "clangformatsettings.h"
#include <cppeditor/cppcodestylesettings.h>
#include <projectexplorer/project.h>
#include <texteditor/tabsettings.h>
#include <utils/qtcassert.h>
#include <sstream>
using namespace ClangFormat;
@@ -105,7 +111,7 @@ void ClangFormatFile::saveNewFormat()
// workaround: configurationAsText() add comment "# " before BasedOnStyle line
const int pos = style.find("# BasedOnStyle");
if (pos < int(style.size()))
if (pos != int(std::string::npos))
style.erase(pos, 2);
m_filePath.writeFileContents(QByteArray::fromStdString(style));
}
@@ -114,3 +120,138 @@ void ClangFormatFile::saveNewFormat(QByteArray style)
{
m_filePath.writeFileContents(style);
}
CppEditor::CppCodeStyleSettings ClangFormatFile::toCppCodeStyleSettings(
ProjectExplorer::Project *project) const
{
using namespace clang::format;
auto settings = CppEditor::CppCodeStyleSettings::getProjectCodeStyle(project);
FormatStyle style;
style.Language = clang::format::FormatStyle::LK_Cpp;
const std::error_code error = parseConfiguration(m_filePath.fileContents().toStdString(),
&style);
QTC_ASSERT(error.value() == static_cast<int>(ParseError::Success), return settings);
// Modifier offset should be opposite to indent width in order indentAccessSpecifiers
// to be false
settings.indentAccessSpecifiers = (style.AccessModifierOffset != -1 * style.IndentWidth);
settings.indentNamespaceBody = style.NamespaceIndentation
== FormatStyle::NamespaceIndentationKind::NI_All;
settings.indentNamespaceBraces = settings.indentNamespaceBody;
settings.indentClassBraces = style.BreakBeforeBraces == FormatStyle::BS_Whitesmiths;
settings.indentEnumBraces = settings.indentClassBraces;
settings.indentBlockBraces = settings.indentClassBraces;
settings.indentFunctionBraces = settings.indentClassBraces;
settings.indentSwitchLabels = style.IndentCaseLabels;
settings.indentBlocksRelativeToSwitchLabels = style.IndentCaseBlocks;
settings.indentStatementsRelativeToSwitchLabels = style.IndentCaseBlocks;
settings.indentControlFlowRelativeToSwitchLabels = style.IndentCaseBlocks;
if (style.DerivePointerAlignment
&& ClangFormatSettings::instance().formatCodeInsteadOfIndent()) {
settings.bindStarToIdentifier = style.PointerAlignment == FormatStyle::PAS_Right;
settings.bindStarToTypeName = style.PointerAlignment == FormatStyle::PAS_Left;
settings.bindStarToLeftSpecifier = style.PointerAlignment == FormatStyle::PAS_Left;
settings.bindStarToRightSpecifier = style.PointerAlignment == FormatStyle::PAS_Right;
}
return settings;
}
void ClangFormatFile::fromCppCodeStyleSettings(const CppEditor::CppCodeStyleSettings &settings)
{
using namespace clang::format;
if (settings.indentAccessSpecifiers)
m_style.AccessModifierOffset = 0;
else
m_style.AccessModifierOffset = -1 * m_style.IndentWidth;
if (settings.indentNamespaceBody || settings.indentNamespaceBraces)
m_style.NamespaceIndentation = FormatStyle::NamespaceIndentationKind::NI_All;
if (settings.indentClassBraces || settings.indentEnumBraces || settings.indentBlockBraces
|| settings.indentFunctionBraces)
m_style.BreakBeforeBraces = FormatStyle::BS_Whitesmiths;
m_style.IndentCaseLabels = settings.indentSwitchLabels;
m_style.IndentCaseBlocks = settings.indentBlocksRelativeToSwitchLabels
|| settings.indentStatementsRelativeToSwitchLabels
|| settings.indentControlFlowRelativeToSwitchLabels;
if (settings.alignAssignments)
m_style.BreakBeforeBinaryOperators = FormatStyle::BOS_NonAssignment;
if (settings.extraPaddingForConditionsIfConfusingAlign)
m_style.BreakBeforeBinaryOperators = FormatStyle::BOS_All;
m_style.DerivePointerAlignment = settings.bindStarToIdentifier || settings.bindStarToTypeName
|| settings.bindStarToLeftSpecifier
|| settings.bindStarToRightSpecifier;
if ((settings.bindStarToIdentifier || settings.bindStarToRightSpecifier)
&& ClangFormatSettings::instance().formatCodeInsteadOfIndent())
m_style.PointerAlignment = FormatStyle::PAS_Right;
if ((settings.bindStarToTypeName || settings.bindStarToLeftSpecifier)
&& ClangFormatSettings::instance().formatCodeInsteadOfIndent())
m_style.PointerAlignment = FormatStyle::PAS_Left;
saveNewFormat();
}
TextEditor::TabSettings ClangFormatFile::toTabSettings(ProjectExplorer::Project *project) const
{
using namespace clang::format;
auto settings = CppEditor::CppCodeStyleSettings::getProjectTabSettings(project);
FormatStyle style;
style.Language = clang::format::FormatStyle::LK_Cpp;
const std::error_code error = parseConfiguration(m_filePath.fileContents().toStdString(),
&style);
QTC_ASSERT(error.value() == static_cast<int>(ParseError::Success), return settings);
settings.m_indentSize = style.IndentWidth;
settings.m_tabSize = style.TabWidth;
switch (style.UseTab) {
case FormatStyle::UT_AlignWithSpaces:
case FormatStyle::UT_ForIndentation:
case FormatStyle::UT_ForContinuationAndIndentation:
settings.m_tabPolicy = TextEditor::TabSettings::TabPolicy::MixedTabPolicy;
break;
case FormatStyle::UT_Never:
settings.m_tabPolicy = TextEditor::TabSettings::TabPolicy::SpacesOnlyTabPolicy;
break;
case FormatStyle::UT_Always:
settings.m_tabPolicy = TextEditor::TabSettings::TabPolicy::TabsOnlyTabPolicy;
break;
}
return settings;
}
void ClangFormatFile::fromTabSettings(const TextEditor::TabSettings &settings)
{
using namespace clang::format;
m_style.IndentWidth = settings.m_indentSize;
m_style.TabWidth = settings.m_tabSize;
switch (settings.m_tabPolicy) {
case TextEditor::TabSettings::TabPolicy::MixedTabPolicy:
m_style.UseTab = FormatStyle::UT_ForContinuationAndIndentation;
break;
case TextEditor::TabSettings::TabPolicy::SpacesOnlyTabPolicy:
m_style.UseTab = FormatStyle::UT_Never;
break;
case TextEditor::TabSettings::TabPolicy::TabsOnlyTabPolicy:
m_style.UseTab = FormatStyle::UT_Always;
break;
}
saveNewFormat();
}

View File

@@ -28,6 +28,10 @@
#include "utils/filepath.h"
#include <clang/Format/Format.h>
namespace CppEditor { class CppCodeStyleSettings; }
namespace ProjectExplorer { class Project; }
namespace TextEditor { class TabSettings; }
namespace ClangFormat {
class ClangFormatFile
@@ -46,6 +50,10 @@ public:
using Field = std::pair<QString, QString>;
QString changeFields(QList<Field> fields);
QString changeField(Field field);
CppEditor::CppCodeStyleSettings toCppCodeStyleSettings(ProjectExplorer::Project *project) const;
TextEditor::TabSettings toTabSettings(ProjectExplorer::Project *project) const;
void fromCppCodeStyleSettings(const CppEditor::CppCodeStyleSettings &settings);
void fromTabSettings(const TextEditor::TabSettings &settings);
private:
void saveNewFormat();
@@ -56,5 +64,4 @@ private:
clang::format::FormatStyle m_style;
};
} // namespace ClangFormat

View File

@@ -45,6 +45,7 @@
#include <cppeditor/cppeditorconstants.h>
#include <cppeditor/cppcodestylepreferencesfactory.h>
#include <cppeditor/cppcodestylesettingspage.h>
#include <cppeditor/cppeditorconstants.h>
#include <cppeditor/cppmodelmanager.h>
@@ -82,7 +83,7 @@ public:
return new ClangFormatIndenter(doc);
}
std::pair<QWidget *, QString> additionalTab(QWidget *parent) const override
std::pair<CppEditor::CppCodeStyleWidget *, QString> additionalTab(QWidget *parent) const override
{
if (!parent)
return {new ClangFormatConfigWidget(), tr("ClangFormat")};