ClangFormat: Add export and import features for ClangFormat

Due to the removal of the widget where users could generate settings
using BasedOnStyle and see all available properties, users now need
to have the ability to load their files or generated files.

- Implemented functionality to export internal .clang-format to an
  external file
- Added import capability to load ClangFormat style from an external
  file
- Added to the ICodeStylePreferencesFactory function
  createSelectorWidget for the possibility of reimplementing the
  functionality of export and import buttons

Change-Id: Ib5f00a0fb58a983d0e7c6dc55128e93d0205d3ca
Reviewed-by: Christian Kandeler <christian.kandeler@qt.io>
This commit is contained in:
Artem Sokolovskii
2024-06-26 16:26:54 +02:00
parent b5094f7da3
commit d4776e6401
9 changed files with 117 additions and 7 deletions

View File

@@ -16,14 +16,32 @@
using namespace ClangFormat;
ClangFormatFile::ClangFormatFile(const TextEditor::ICodeStylePreferences *preferences)
ClangFormatFile::ClangFormatFile(
const TextEditor::ICodeStylePreferences *preferences, const Utils::FilePath &fromFilePath)
: m_filePath(filePathToCurrentSettings(preferences))
{
if (m_filePath.exists())
return;
// create file and folder
// create folder
m_filePath.parentDir().createDir();
if (fromFilePath.exists() && fromFilePath.copyFile(m_filePath)) {
auto fileContent = m_filePath.fileContents();
if (fileContent && !fileContent->contains("yaml-language-server")) {
fileContent->insert(
0,
"# yaml-language-server: "
"$schema=https://json.schemastore.org/clang-format.json\n");
m_filePath.writeFileContents(fileContent.value());
}
parseConfigurationFile(m_filePath, m_style);
return;
}
// It is done separately from folder because filePath.copyFile doesn't copy if file exists
// ToDo: when behavior of copyFile is changed, combine that block with folder creation block
// create file
std::fstream newStyleFile(m_filePath.path().toStdString(), std::fstream::out);
if (newStyleFile.is_open())
newStyleFile.close();

View File

@@ -19,7 +19,8 @@ namespace ClangFormat {
class ClangFormatFile
{
public:
explicit ClangFormatFile(const TextEditor::ICodeStylePreferences *preferences);
explicit ClangFormatFile(
const TextEditor::ICodeStylePreferences *preferences, const Utils::FilePath &filePath = {});
clang::format::FormatStyle style();
Utils::FilePath filePath();

View File

@@ -5,6 +5,7 @@
#include "clangformatconfigwidget.h"
#include "clangformatconstants.h"
#include "clangformatfile.h"
#include "clangformatindenter.h"
#include "clangformatsettings.h"
#include "clangformattr.h"
@@ -17,6 +18,8 @@
#include <projectexplorer/project.h>
#include <projectexplorer/projecttree.h>
#include <texteditor/codestylepool.h>
#include <texteditor/codestyleselectorwidget.h>
#include <texteditor/icodestylepreferences.h>
#include <texteditor/texteditorsettings.h>
@@ -27,7 +30,9 @@
#include <QCheckBox>
#include <QComboBox>
#include <QGroupBox>
#include <QInputDialog>
#include <QLabel>
#include <QMessageBox>
#include <QSpinBox>
using namespace CppEditor;
@@ -350,6 +355,59 @@ void ClangFormatGlobalConfigWidget::finish()
!ClangFormatSettings::instance().useCustomSettings());
}
class ClangFormatSelectorWidget final : public CodeStyleSelectorWidget
{
public:
ClangFormatSelectorWidget(
ICodeStylePreferencesFactory *factory,
ProjectExplorer::Project *project = nullptr,
QWidget *parent = nullptr)
: CodeStyleSelectorWidget(factory, project, parent)
{}
private:
void slotImportClicked() final
{
const FilePath filePath =
FileUtils::getOpenFilePath(this, Tr::tr("Import Code Format"), {},
Tr::tr("Clang Format (*clang-format*);;All files (*)"));
if (!filePath.isEmpty()) {
QString name = QInputDialog::getText(
this,
Tr::tr("Import Code Style"),
Tr::tr("Enter a name for the imported code style:"));
if (name.isEmpty())
return;
CodeStylePool *codeStylePool = m_codeStyle->delegatingPool();
ICodeStylePreferences *importedStyle = codeStylePool->createCodeStyle(name);
ClangFormatFile file(importedStyle, filePath);
if (importedStyle)
m_codeStyle->setCurrentDelegate(importedStyle);
else
QMessageBox::warning(this,
Tr::tr("Import Code Style"),
Tr::tr("Cannot import code style from \"%1\".")
.arg(filePath.toUserOutput()));
}
}
void slotExportClicked() final
{
ICodeStylePreferences *currentPreferences = m_codeStyle->currentPreferences();
const FilePath filePath = FileUtils::getSaveFilePath(
this,
Tr::tr("Export Code Format"),
FileUtils::homePath(),
Tr::tr("Clang Format (*clang-format*);;All files (*)"));
if (!filePath.isEmpty()) {
FilePath clangFormatFile = filePathToCurrentSettings(currentPreferences);
clangFormatFile.copyFile(filePath);
}
}
};
class ClangFormatStyleFactory final : public CppCodeStylePreferencesFactory
{
public:
@@ -369,6 +427,12 @@ public:
{
return new ClangFormatGlobalConfigWidget(codeStyle, project, parent);
}
CodeStyleSelectorWidget *createSelectorWidget(
ProjectExplorer::Project *project, QWidget *parent) final
{
return new ClangFormatSelectorWidget(this, project, parent);
}
};
void setupClangFormatStyleFactory(QObject *guard)

View File

@@ -30,7 +30,7 @@ CodeStyleEditor::CodeStyleEditor(ICodeStylePreferencesFactory *factory,
{
m_layout = new QVBoxLayout(this);
m_layout->setContentsMargins(0, 0, 0, 0);
auto selector = new CodeStyleSelectorWidget(factory, project, this);
auto selector = m_factory->createSelectorWidget(project, this);
selector->setCodeStyle(codeStyle);
m_additionalGlobalSettingsWidget = factory->createAdditionalGlobalSettings(codeStyle,
project,

View File

@@ -135,6 +135,20 @@ ICodeStylePreferences *CodeStylePool::createCodeStyle(const QByteArray &id, cons
return codeStyle;
}
ICodeStylePreferences *CodeStylePool::createCodeStyle(const QString &displayName)
{
if (!d->m_factory)
return nullptr;
ICodeStylePreferences *codeStyle = d->m_factory->createCodeStyle();
codeStyle->setDisplayName(displayName);
addCodeStyle(codeStyle);
saveCodeStyle(codeStyle);
return codeStyle;
}
void CodeStylePool::addCodeStyle(ICodeStylePreferences *codeStyle)
{
const QByteArray newId = d->generateUniqueId(codeStyle->id());

View File

@@ -30,6 +30,7 @@ public:
ICodeStylePreferences *cloneCodeStyle(ICodeStylePreferences *originalCodeStyle);
ICodeStylePreferences *createCodeStyle(const QByteArray &id, const TabSettings &tabSettings,
const QVariant &codeStyleData, const QString &displayName);
ICodeStylePreferences *createCodeStyle(const QString &displayName);
// ownership is passed to the pool
void addCodeStyle(ICodeStylePreferences *codeStyle);
// is removed and deleted

View File

@@ -32,20 +32,22 @@ public:
void setCodeStyle(ICodeStylePreferences *codeStyle);
protected:
ICodeStylePreferences *m_codeStyle = nullptr;
private:
void slotComboBoxActivated(int index);
void slotCurrentDelegateChanged(ICodeStylePreferences *delegate);
void slotCopyClicked();
void slotRemoveClicked();
void slotImportClicked();
void slotExportClicked();
virtual void slotImportClicked();
virtual void slotExportClicked();
void slotCodeStyleAdded(ICodeStylePreferences *codeStylePreferences);
void slotCodeStyleRemoved(ICodeStylePreferences *codeStylePreferences);
void slotUpdateName(ICodeStylePreferences *codeStylePreferences);
void updateName(ICodeStylePreferences *codeStyle);
ICodeStylePreferencesFactory *m_factory;
ICodeStylePreferences *m_codeStyle = nullptr;
ProjectExplorer::Project *m_project = nullptr;
QString displayName(ICodeStylePreferences *codeStyle) const;

View File

@@ -4,6 +4,7 @@
#include "icodestylepreferencesfactory.h"
#include "codestyleeditor.h"
#include "codestyleselectorwidget.h"
using namespace TextEditor;
@@ -22,3 +23,9 @@ CodeStyleEditorWidget *ICodeStylePreferencesFactory::createAdditionalGlobalSetti
{
return nullptr;
}
CodeStyleSelectorWidget *ICodeStylePreferencesFactory::createSelectorWidget(
ProjectExplorer::Project *project, QWidget *parent)
{
return new CodeStyleSelectorWidget(this, project, parent);
}

View File

@@ -16,6 +16,7 @@ namespace ProjectExplorer { class Project; }
namespace TextEditor {
class ICodeStylePreferences;
class CodeStyleSelectorWidget;
class TEXTEDITOR_EXPORT CodeStyleEditorWidget : public QWidget
{
@@ -50,6 +51,8 @@ public:
virtual CodeStyleEditorWidget *createEditor(ICodeStylePreferences *preferences,
ProjectExplorer::Project *project = nullptr,
QWidget *parent = nullptr) const = 0;
virtual CodeStyleSelectorWidget *createSelectorWidget(
ProjectExplorer::Project *project, QWidget *parent = nullptr);
virtual TextEditor::Indenter *createIndenter(QTextDocument *doc) const = 0;
virtual QString snippetProviderGroupId() const = 0;
virtual QString previewText() const = 0;