aboutsummaryrefslogtreecommitdiffstats
path: root/src/plugins/cppeditor
diff options
context:
space:
mode:
authorChristian Kandeler <christian.kandeler@qt.io>2024-04-10 16:22:48 +0200
committerChristian Kandeler <christian.kandeler@qt.io>2024-04-11 08:48:19 +0000
commit4b29ad78e3f8f8917767818d97e29c7b9f8c4686 (patch)
tree236136175f2ba69157715b1a67e631274fcdcf70 /src/plugins/cppeditor
parent459cb8274407ea6d5d52a0ad27e969a542d3b664 (diff)
CppEditor: Move ClangdSettingsPage alongside ClangdSettings
Change-Id: Ib22438817ff3a14904decbb23f3c2288f355e378 Reviewed-by: David Schulz <david.schulz@qt.io> Reviewed-by: <github-actions-qt-creator@cristianadam.eu>
Diffstat (limited to 'src/plugins/cppeditor')
-rw-r--r--src/plugins/cppeditor/clangdsettings.cpp540
-rw-r--r--src/plugins/cppeditor/clangdsettings.h5
-rw-r--r--src/plugins/cppeditor/cppcodemodelsettingspage.cpp527
-rw-r--r--src/plugins/cppeditor/cppcodemodelsettingspage.h2
-rw-r--r--src/plugins/cppeditor/cppeditorplugin.cpp1
5 files changed, 546 insertions, 529 deletions
diff --git a/src/plugins/cppeditor/clangdsettings.cpp b/src/plugins/cppeditor/clangdsettings.cpp
index b5352af6d8..253914704a 100644
--- a/src/plugins/cppeditor/clangdsettings.cpp
+++ b/src/plugins/cppeditor/clangdsettings.cpp
@@ -4,19 +4,41 @@
#include "clangdsettings.h"
#include "clangdiagnosticconfigsmodel.h"
+#include "clangdiagnosticconfigsselectionwidget.h"
+#include "clangdiagnosticconfigswidget.h"
#include "cppeditorconstants.h"
#include "cppeditortr.h"
#include "cpptoolsreuse.h"
+#include <coreplugin/dialogs/ioptionspage.h>
#include <coreplugin/icore.h>
#include <coreplugin/session.h>
#include <projectexplorer/project.h>
+#include <projectexplorer/projectpanelfactory.h>
+#include <projectexplorer/projectsettingswidget.h>
#include <utils/clangutils.h>
+#include <utils/itemviews.h>
+#include <utils/layoutbuilder.h>
#include <utils/qtcprocess.h>
+#include <utils/variablechooser.h>
+#include <QCheckBox>
+#include <QDesktopServices>
+#include <QFormLayout>
+#include <QGroupBox>
+#include <QGuiApplication>
+#include <QInputDialog>
+#include <QPushButton>
+#include <QSpinBox>
#include <QStandardPaths>
+#include <QStringListModel>
+#include <QTimer>
+#include <QVBoxLayout>
#include <QVersionNumber>
+#include <limits>
+
+using namespace ProjectExplorer;
using namespace Utils;
namespace CppEditor {
@@ -338,7 +360,7 @@ void ClangdSettings::setClangdFilePath(const FilePath &filePath)
}
#endif
-ClangdProjectSettings::ClangdProjectSettings(ProjectExplorer::Project *project) : m_project(project)
+ClangdProjectSettings::ClangdProjectSettings(Project *project) : m_project(project)
{
loadSettings();
}
@@ -488,4 +510,520 @@ int ClangdSettings::Data::defaultCompletionResults()
return ok ? userValue : 100;
}
+namespace Internal {
+class ClangdSettingsWidget final : public QWidget
+{
+ Q_OBJECT
+
+public:
+ ClangdSettingsWidget(const ClangdSettings::Data &settingsData, bool isForProject);
+
+ ClangdSettings::Data settingsData() const;
+
+signals:
+ void settingsDataChanged();
+
+private:
+ QCheckBox m_useClangdCheckBox;
+ QComboBox m_indexingComboBox;
+ Utils::FancyLineEdit m_projectIndexPathTemplateLineEdit;
+ Utils::FancyLineEdit m_sessionIndexPathTemplateLineEdit;
+ QComboBox m_headerSourceSwitchComboBox;
+ QComboBox m_completionRankingModelComboBox;
+ QCheckBox m_autoIncludeHeadersCheckBox;
+ QCheckBox m_sizeThresholdCheckBox;
+ QSpinBox m_threadLimitSpinBox;
+ QSpinBox m_documentUpdateThreshold;
+ QSpinBox m_sizeThresholdSpinBox;
+ QSpinBox m_completionResults;
+ Utils::PathChooser m_clangdChooser;
+ Utils::InfoLabel m_versionWarningLabel;
+ ClangDiagnosticConfigsSelectionWidget *m_configSelectionWidget = nullptr;
+ QGroupBox *m_sessionsGroupBox = nullptr;
+ QStringListModel m_sessionsModel;
+};
+
+ClangdSettingsWidget::ClangdSettingsWidget(const ClangdSettings::Data &settingsData,
+ bool isForProject)
+{
+ const ClangdSettings settings(settingsData);
+ const QString indexingToolTip = Tr::tr(
+ "<p>If background indexing is enabled, global symbol searches will yield more accurate "
+ "results, at the cost of additional CPU load when the project is first opened. The "
+ "indexing result is persisted in the project's build directory. If you disable background "
+ "indexing, a faster, but less accurate, built-in indexer is used instead. The thread "
+ "priority for building the background index can be adjusted since clangd 15.</p>"
+ "<p>Background Priority: Minimum priority, runs on idle CPUs. May leave 'performance' "
+ "cores unused.</p>"
+ "<p>Normal Priority: Reduced priority compared to interactive work.</p>"
+ "<p>Low Priority: Same priority as other clangd work.</p>");
+ const QString projectIndexPathToolTip = Tr::tr(
+ "The location of the per-project clangd index.<p>"
+ "This is also where the compile_commands.json file will go.");
+ const QString sessionIndexPathToolTip = Tr::tr(
+ "The location of the per-session clangd index.<p>"
+ "This is also where the compile_commands.json file will go.");
+ const QString headerSourceSwitchToolTip = Tr::tr(
+ "<p>The C/C++ backend to use for switching between header and source files.</p>"
+ "<p>While the clangd implementation has more capabilities than the built-in "
+ "code model, it tends to find false positives.</p>"
+ "<p>When \"Try Both\" is selected, clangd is used only if the built-in variant "
+ "does not find anything.</p>");
+ using RankingModel = ClangdSettings::CompletionRankingModel;
+ const QString completionRankingModelToolTip = Tr::tr(
+ "<p>Which model clangd should use to rank possible completions.</p>"
+ "<p>This determines the order of candidates in the combo box when doing code completion.</p>"
+ "<p>The \"%1\" model used by default results from (pre-trained) machine learning and "
+ "provides superior results on average.</p>"
+ "<p>If you feel that its suggestions stray too much from your expectations for your "
+ "code base, you can try switching to the hand-crafted \"%2\" model.</p>").arg(
+ ClangdSettings::rankingModelToDisplayString(RankingModel::DecisionForest),
+ ClangdSettings::rankingModelToDisplayString(RankingModel::Heuristics));
+ const QString workerThreadsToolTip = Tr::tr(
+ "Number of worker threads used by clangd. Background indexing also uses this many "
+ "worker threads.");
+ const QString autoIncludeToolTip = Tr::tr(
+ "Controls whether clangd may insert header files as part of symbol completion.");
+ const QString documentUpdateToolTip
+ //: %1 is the application name (Qt Creator)
+ = Tr::tr("Defines the amount of time %1 waits before sending document changes to the "
+ "server.\n"
+ "If the document changes again while waiting, this timeout resets.")
+ .arg(QGuiApplication::applicationDisplayName());
+ const QString sizeThresholdToolTip = Tr::tr(
+ "Files greater than this will not be opened as documents in clangd.\n"
+ "The built-in code model will handle highlighting, completion and so on.");
+ const QString completionResultToolTip = Tr::tr(
+ "The maximum number of completion results returned by clangd.");
+
+ m_useClangdCheckBox.setText(Tr::tr("Use clangd"));
+ m_useClangdCheckBox.setChecked(settings.useClangd());
+ m_clangdChooser.setExpectedKind(Utils::PathChooser::ExistingCommand);
+ m_clangdChooser.setFilePath(settings.clangdFilePath());
+ m_clangdChooser.setAllowPathFromDevice(true);
+ m_clangdChooser.setEnabled(m_useClangdCheckBox.isChecked());
+ m_clangdChooser.setCommandVersionArguments({"--version"});
+ using Priority = ClangdSettings::IndexingPriority;
+ for (Priority prio : {Priority::Off, Priority::Background, Priority::Low, Priority::Normal}) {
+ m_indexingComboBox.addItem(ClangdSettings::priorityToDisplayString(prio), int(prio));
+ if (prio == settings.indexingPriority())
+ m_indexingComboBox.setCurrentIndex(m_indexingComboBox.count() - 1);
+ }
+ m_indexingComboBox.setToolTip(indexingToolTip);
+ m_projectIndexPathTemplateLineEdit.setText(settings.data().projectIndexPathTemplate);
+ m_sessionIndexPathTemplateLineEdit.setText(settings.data().sessionIndexPathTemplate);
+ using SwitchMode = ClangdSettings::HeaderSourceSwitchMode;
+ for (SwitchMode mode : {SwitchMode::BuiltinOnly, SwitchMode::ClangdOnly, SwitchMode::Both}) {
+ m_headerSourceSwitchComboBox.addItem(
+ ClangdSettings::headerSourceSwitchModeToDisplayString(mode), int(mode));
+ if (mode == settings.headerSourceSwitchMode())
+ m_headerSourceSwitchComboBox.setCurrentIndex(
+ m_headerSourceSwitchComboBox.count() - 1);
+ }
+ m_headerSourceSwitchComboBox.setToolTip(headerSourceSwitchToolTip);
+ for (RankingModel model : {RankingModel::Default, RankingModel::DecisionForest,
+ RankingModel::Heuristics}) {
+ m_completionRankingModelComboBox.addItem(
+ ClangdSettings::rankingModelToDisplayString(model), int(model));
+ if (model == settings.completionRankingModel())
+ m_completionRankingModelComboBox.setCurrentIndex(
+ m_completionRankingModelComboBox.count() - 1);
+ }
+ m_completionRankingModelComboBox.setToolTip(completionRankingModelToolTip);
+
+ m_autoIncludeHeadersCheckBox.setText(Tr::tr("Insert header files on completion"));
+ m_autoIncludeHeadersCheckBox.setChecked(settings.autoIncludeHeaders());
+ m_autoIncludeHeadersCheckBox.setToolTip(autoIncludeToolTip);
+ m_threadLimitSpinBox.setValue(settings.workerThreadLimit());
+ m_threadLimitSpinBox.setSpecialValueText(Tr::tr("Automatic"));
+ m_threadLimitSpinBox.setToolTip(workerThreadsToolTip);
+ m_documentUpdateThreshold.setMinimum(50);
+ m_documentUpdateThreshold.setMaximum(10000);
+ m_documentUpdateThreshold.setValue(settings.documentUpdateThreshold());
+ m_documentUpdateThreshold.setSingleStep(100);
+ m_documentUpdateThreshold.setSuffix(" ms");
+ m_documentUpdateThreshold.setToolTip(documentUpdateToolTip);
+ m_sizeThresholdCheckBox.setText(Tr::tr("Ignore files greater than"));
+ m_sizeThresholdCheckBox.setChecked(settings.sizeThresholdEnabled());
+ m_sizeThresholdCheckBox.setToolTip(sizeThresholdToolTip);
+ m_sizeThresholdSpinBox.setMinimum(1);
+ m_sizeThresholdSpinBox.setMaximum(std::numeric_limits<int>::max());
+ m_sizeThresholdSpinBox.setSuffix(" KB");
+ m_sizeThresholdSpinBox.setValue(settings.sizeThresholdInKb());
+ m_sizeThresholdSpinBox.setToolTip(sizeThresholdToolTip);
+
+ const auto completionResultsLabel = new QLabel(Tr::tr("Completion results:"));
+ completionResultsLabel->setToolTip(completionResultToolTip);
+ m_completionResults.setMinimum(0);
+ m_completionResults.setMaximum(std::numeric_limits<int>::max());
+ m_completionResults.setValue(settings.completionResults());
+ m_completionResults.setToolTip(completionResultToolTip);
+ m_completionResults.setSpecialValueText(Tr::tr("No limit"));
+
+ const auto layout = new QVBoxLayout(this);
+ layout->setContentsMargins(0, 0, 0, 0);
+ layout->addWidget(&m_useClangdCheckBox);
+
+ const auto formLayout = new QFormLayout;
+ const auto chooserLabel = new QLabel(Tr::tr("Path to executable:"));
+ formLayout->addRow(chooserLabel, &m_clangdChooser);
+ formLayout->addRow(QString(), &m_versionWarningLabel);
+
+ const auto indexingPriorityLayout = new QHBoxLayout;
+ indexingPriorityLayout->addWidget(&m_indexingComboBox);
+ indexingPriorityLayout->addStretch(1);
+ const auto indexingPriorityLabel = new QLabel(Tr::tr("Background indexing:"));
+ indexingPriorityLabel->setToolTip(indexingToolTip);
+ formLayout->addRow(indexingPriorityLabel, indexingPriorityLayout);
+
+ for (const auto &[text, edit, toolTip, defaultValue] :
+ {std::make_tuple(Tr::tr("Per-project index location:"),
+ &m_projectIndexPathTemplateLineEdit,
+ projectIndexPathToolTip,
+ ClangdSettings::defaultProjectIndexPathTemplate()),
+ std::make_tuple(Tr::tr("Per-session index location:"),
+ &m_sessionIndexPathTemplateLineEdit,
+ sessionIndexPathToolTip,
+ ClangdSettings::defaultSessionIndexPathTemplate())}) {
+ if (isForProject && edit == &m_sessionIndexPathTemplateLineEdit)
+ continue;
+
+ const auto chooser = new Utils::VariableChooser(edit);
+ chooser->addSupportedWidget(edit);
+ chooser->addMacroExpanderProvider([] { return Utils::globalMacroExpander(); });
+
+ const auto resetButton = new QPushButton(Tr::tr("Reset"));
+ connect(resetButton, &QPushButton::clicked, [e = edit, v = defaultValue] { e->setText(v); });
+ const auto layout = new QHBoxLayout;
+ const auto label = new QLabel(text);
+ label->setToolTip(toolTip);
+ edit->setToolTip(toolTip);
+ layout->addWidget(edit);
+ layout->addWidget(resetButton);
+ formLayout->addRow(label, layout);
+ }
+
+ const auto headerSourceSwitchLayout = new QHBoxLayout;
+ headerSourceSwitchLayout->addWidget(&m_headerSourceSwitchComboBox);
+ headerSourceSwitchLayout->addStretch(1);
+ const auto headerSourceSwitchLabel = new QLabel(Tr::tr("Header/source switch mode:"));
+ headerSourceSwitchLabel->setToolTip(headerSourceSwitchToolTip);
+ formLayout->addRow(headerSourceSwitchLabel, headerSourceSwitchLayout);
+
+ const auto threadLimitLayout = new QHBoxLayout;
+ threadLimitLayout->addWidget(&m_threadLimitSpinBox);
+ threadLimitLayout->addStretch(1);
+ const auto threadLimitLabel = new QLabel(Tr::tr("Worker thread count:"));
+ threadLimitLabel->setToolTip(workerThreadsToolTip);
+ formLayout->addRow(threadLimitLabel, threadLimitLayout);
+
+ formLayout->addRow(QString(), &m_autoIncludeHeadersCheckBox);
+ const auto limitResultsLayout = new QHBoxLayout;
+ limitResultsLayout->addWidget(&m_completionResults);
+ limitResultsLayout->addStretch(1);
+ formLayout->addRow(completionResultsLabel, limitResultsLayout);
+
+ const auto completionRankingModelLayout = new QHBoxLayout;
+ completionRankingModelLayout->addWidget(&m_completionRankingModelComboBox);
+ completionRankingModelLayout->addStretch(1);
+ const auto completionRankingModelLabel = new QLabel(Tr::tr("Completion ranking model:"));
+ completionRankingModelLabel->setToolTip(completionRankingModelToolTip);
+ formLayout->addRow(completionRankingModelLabel, completionRankingModelLayout);
+
+ const auto documentUpdateThresholdLayout = new QHBoxLayout;
+ documentUpdateThresholdLayout->addWidget(&m_documentUpdateThreshold);
+ documentUpdateThresholdLayout->addStretch(1);
+ const auto documentUpdateThresholdLabel = new QLabel(Tr::tr("Document update threshold:"));
+ documentUpdateThresholdLabel->setToolTip(documentUpdateToolTip);
+ formLayout->addRow(documentUpdateThresholdLabel, documentUpdateThresholdLayout);
+ const auto sizeThresholdLayout = new QHBoxLayout;
+ sizeThresholdLayout->addWidget(&m_sizeThresholdSpinBox);
+ sizeThresholdLayout->addStretch(1);
+ formLayout->addRow(&m_sizeThresholdCheckBox, sizeThresholdLayout);
+
+ m_configSelectionWidget = new ClangDiagnosticConfigsSelectionWidget(formLayout);
+ m_configSelectionWidget->refresh(
+ diagnosticConfigsModel(settings.customDiagnosticConfigs()),
+ settings.diagnosticConfigId(),
+ [](const ClangDiagnosticConfigs &configs, const Utils::Id &configToSelect) {
+ return new CppEditor::ClangDiagnosticConfigsWidget(configs, configToSelect);
+ });
+
+ layout->addLayout(formLayout);
+ if (!isForProject) {
+ m_sessionsModel.setStringList(settingsData.sessionsWithOneClangd);
+ m_sessionsModel.sort(0);
+ m_sessionsGroupBox = new QGroupBox(Tr::tr("Sessions with a single clangd instance"));
+ const auto sessionsView = new Utils::ListView;
+ sessionsView->setModel(&m_sessionsModel);
+ sessionsView->setToolTip(
+ Tr::tr("By default, Qt Creator runs one clangd process per project.\n"
+ "If you have sessions with tightly coupled projects that should be\n"
+ "managed by the same clangd process, add them here."));
+ const auto outerSessionsLayout = new QHBoxLayout;
+ const auto innerSessionsLayout = new QHBoxLayout(m_sessionsGroupBox);
+ const auto buttonsLayout = new QVBoxLayout;
+ const auto addButton = new QPushButton(Tr::tr("Add ..."));
+ const auto removeButton = new QPushButton(Tr::tr("Remove"));
+ buttonsLayout->addWidget(addButton);
+ buttonsLayout->addWidget(removeButton);
+ buttonsLayout->addStretch(1);
+ innerSessionsLayout->addWidget(sessionsView);
+ innerSessionsLayout->addLayout(buttonsLayout);
+ outerSessionsLayout->addWidget(m_sessionsGroupBox);
+ outerSessionsLayout->addStretch(1);
+
+ const auto separator = new QFrame;
+ separator->setFrameShape(QFrame::HLine);
+ layout->addWidget(separator);
+ layout->addLayout(outerSessionsLayout);
+
+ const auto updateRemoveButtonState = [removeButton, sessionsView] {
+ removeButton->setEnabled(sessionsView->selectionModel()->hasSelection());
+ };
+ connect(sessionsView->selectionModel(), &QItemSelectionModel::selectionChanged,
+ this, updateRemoveButtonState);
+ updateRemoveButtonState();
+ connect(removeButton, &QPushButton::clicked, this, [this, sessionsView] {
+ const QItemSelection selection = sessionsView->selectionModel()->selection();
+ QTC_ASSERT(!selection.isEmpty(), return);
+ m_sessionsModel.removeRow(selection.indexes().first().row());
+ });
+
+ connect(addButton, &QPushButton::clicked, this, [this, sessionsView] {
+ QInputDialog dlg(sessionsView);
+ QStringList sessions = Core::SessionManager::sessions();
+ QStringList currentSessions = m_sessionsModel.stringList();
+ for (const QString &s : std::as_const(currentSessions))
+ sessions.removeOne(s);
+ if (sessions.isEmpty())
+ return;
+ sessions.sort();
+ dlg.setLabelText(Tr::tr("Choose a session:"));
+ dlg.setComboBoxItems(sessions);
+ if (dlg.exec() == QDialog::Accepted) {
+ currentSessions << dlg.textValue();
+ m_sessionsModel.setStringList(currentSessions);
+ m_sessionsModel.sort(0);
+ }
+ });
+ }
+
+ const auto configFilesHelpLabel = new QLabel;
+ configFilesHelpLabel->setText(Tr::tr("Additional settings are available via "
+ "<a href=\"https://clangd.llvm.org/config\"> clangd configuration files</a>.<br>"
+ "User-specific settings go <a href=\"%1\">here</a>, "
+ "project-specific settings can be configured by putting a .clangd file into "
+ "the project source tree.")
+ .arg(ClangdSettings::clangdUserConfigFilePath().toUserOutput()));
+ configFilesHelpLabel->setWordWrap(true);
+ connect(configFilesHelpLabel, &QLabel::linkHovered, configFilesHelpLabel, &QLabel::setToolTip);
+ connect(configFilesHelpLabel, &QLabel::linkActivated, [](const QString &link) {
+ if (link.startsWith("https"))
+ QDesktopServices::openUrl(link);
+ else
+ Core::EditorManager::openEditor(Utils::FilePath::fromString(link));
+ });
+ layout->addWidget(Layouting::createHr());
+ layout->addWidget(configFilesHelpLabel);
+
+ layout->addStretch(1);
+
+ static const auto setWidgetsEnabled = [](QLayout *layout, bool enabled, const auto &f) -> void {
+ for (int i = 0; i < layout->count(); ++i) {
+ if (QWidget * const w = layout->itemAt(i)->widget())
+ w->setEnabled(enabled);
+ else if (QLayout * const l = layout->itemAt(i)->layout())
+ f(l, enabled, f);
+ }
+ };
+ const auto toggleEnabled = [this, formLayout](const bool checked) {
+ setWidgetsEnabled(formLayout, checked, setWidgetsEnabled);
+ if (m_sessionsGroupBox)
+ m_sessionsGroupBox->setEnabled(checked);
+ };
+ connect(&m_useClangdCheckBox, &QCheckBox::toggled, toggleEnabled);
+ toggleEnabled(m_useClangdCheckBox.isChecked());
+ m_threadLimitSpinBox.setEnabled(m_useClangdCheckBox.isChecked());
+
+ m_versionWarningLabel.setType(Utils::InfoLabel::Warning);
+ const auto updateWarningLabel = [this] {
+ class WarningLabelSetter {
+ public:
+ WarningLabelSetter(QLabel &label) : m_label(label) { m_label.clear(); }
+ ~WarningLabelSetter() { m_label.setVisible(!m_label.text().isEmpty()); }
+ void setWarning(const QString &text) { m_label.setText(text); }
+ private:
+ QLabel &m_label;
+ };
+ WarningLabelSetter labelSetter(m_versionWarningLabel);
+
+ if (!m_clangdChooser.isValid())
+ return;
+ const Utils::FilePath clangdPath = m_clangdChooser.filePath();
+ QString errorMessage;
+ if (!Utils::checkClangdVersion(clangdPath, &errorMessage))
+ labelSetter.setWarning(errorMessage);
+ };
+ connect(&m_clangdChooser, &Utils::PathChooser::textChanged, this, updateWarningLabel);
+ connect(&m_clangdChooser, &Utils::PathChooser::validChanged, this, updateWarningLabel);
+ updateWarningLabel();
+
+ connect(&m_useClangdCheckBox, &QCheckBox::toggled,
+ this, &ClangdSettingsWidget::settingsDataChanged);
+ connect(&m_indexingComboBox, &QComboBox::currentIndexChanged,
+ this, &ClangdSettingsWidget::settingsDataChanged);
+ connect(&m_projectIndexPathTemplateLineEdit, &QLineEdit::textChanged,
+ this, &ClangdSettingsWidget::settingsDataChanged);
+ connect(&m_sessionIndexPathTemplateLineEdit, &QLineEdit::textChanged,
+ this, &ClangdSettingsWidget::settingsDataChanged);
+ connect(&m_headerSourceSwitchComboBox, &QComboBox::currentIndexChanged,
+ this, &ClangdSettingsWidget::settingsDataChanged);
+ connect(&m_completionRankingModelComboBox, &QComboBox::currentIndexChanged,
+ this, &ClangdSettingsWidget::settingsDataChanged);
+ connect(&m_autoIncludeHeadersCheckBox, &QCheckBox::toggled,
+ this, &ClangdSettingsWidget::settingsDataChanged);
+ connect(&m_threadLimitSpinBox, &QSpinBox::valueChanged,
+ this, &ClangdSettingsWidget::settingsDataChanged);
+ connect(&m_sizeThresholdCheckBox, &QCheckBox::toggled,
+ this, &ClangdSettingsWidget::settingsDataChanged);
+ connect(&m_sizeThresholdSpinBox, &QSpinBox::valueChanged,
+ this, &ClangdSettingsWidget::settingsDataChanged);
+ connect(&m_documentUpdateThreshold, &QSpinBox::valueChanged,
+ this, &ClangdSettingsWidget::settingsDataChanged);
+ connect(&m_clangdChooser, &Utils::PathChooser::textChanged,
+ this, &ClangdSettingsWidget::settingsDataChanged);
+ connect(m_configSelectionWidget, &ClangDiagnosticConfigsSelectionWidget::changed,
+ this, &ClangdSettingsWidget::settingsDataChanged);
+ connect(&m_completionResults, &QSpinBox::valueChanged,
+ this, &ClangdSettingsWidget::settingsDataChanged);
+}
+
+ClangdSettings::Data ClangdSettingsWidget::settingsData() const
+{
+ ClangdSettings::Data data;
+ data.useClangd = m_useClangdCheckBox.isChecked();
+ data.executableFilePath = m_clangdChooser.filePath();
+ data.indexingPriority = ClangdSettings::IndexingPriority(
+ m_indexingComboBox.currentData().toInt());
+ data.projectIndexPathTemplate = m_projectIndexPathTemplateLineEdit.text();
+ data.sessionIndexPathTemplate = m_sessionIndexPathTemplateLineEdit.text();
+ data.headerSourceSwitchMode = ClangdSettings::HeaderSourceSwitchMode(
+ m_headerSourceSwitchComboBox.currentData().toInt());
+ data.completionRankingModel = ClangdSettings::CompletionRankingModel(
+ m_completionRankingModelComboBox.currentData().toInt());
+ data.autoIncludeHeaders = m_autoIncludeHeadersCheckBox.isChecked();
+ data.workerThreadLimit = m_threadLimitSpinBox.value();
+ data.documentUpdateThreshold = m_documentUpdateThreshold.value();
+ data.sizeThresholdEnabled = m_sizeThresholdCheckBox.isChecked();
+ data.sizeThresholdInKb = m_sizeThresholdSpinBox.value();
+ data.sessionsWithOneClangd = m_sessionsModel.stringList();
+ data.customDiagnosticConfigs = m_configSelectionWidget->customConfigs();
+ data.diagnosticConfigId = m_configSelectionWidget->currentConfigId();
+ data.completionResults = m_completionResults.value();
+ return data;
+}
+
+class ClangdSettingsPageWidget final : public Core::IOptionsPageWidget
+{
+public:
+ ClangdSettingsPageWidget() : m_widget(ClangdSettings::instance().data(), false)
+ {
+ const auto layout = new QVBoxLayout(this);
+ layout->addWidget(&m_widget);
+ }
+
+private:
+ void apply() final { ClangdSettings::instance().setData(m_widget.settingsData()); }
+
+ ClangdSettingsWidget m_widget;
+};
+
+class ClangdSettingsPage final : public Core::IOptionsPage
+{
+public:
+ ClangdSettingsPage()
+ {
+ setId(Constants::CPP_CLANGD_SETTINGS_ID);
+ setDisplayName(Tr::tr("Clangd"));
+ setCategory(Constants::CPP_SETTINGS_CATEGORY);
+ setWidgetCreator([] { return new ClangdSettingsPageWidget; });
+ }
+};
+
+void setupClangdSettingsPage()
+{
+ static ClangdSettingsPage theClangdSettingsPage;
+}
+
+class ClangdProjectSettingsWidget : public ProjectSettingsWidget
+{
+public:
+ ClangdProjectSettingsWidget(const ClangdProjectSettings &settings)
+ : m_settings(settings), m_widget(settings.settings(), true)
+ {
+ setGlobalSettingsId(Constants::CPP_CLANGD_SETTINGS_ID);
+ const auto layout = new QVBoxLayout(this);
+ layout->setContentsMargins(0, 0, 0, 0);
+ layout->addWidget(&m_widget);
+
+ const auto updateGlobalSettingsCheckBox = [this] {
+ if (ClangdSettings::instance().granularity() == ClangdSettings::Granularity::Session) {
+ setUseGlobalSettingsCheckBoxEnabled(false);
+ setUseGlobalSettings(true);
+ } else {
+ setUseGlobalSettingsCheckBoxEnabled(true);
+ setUseGlobalSettings(m_settings.useGlobalSettings());
+ }
+ m_widget.setEnabled(!useGlobalSettings());
+ };
+
+ updateGlobalSettingsCheckBox();
+ connect(&ClangdSettings::instance(), &ClangdSettings::changed,
+ this, updateGlobalSettingsCheckBox);
+
+ connect(this, &ProjectSettingsWidget::useGlobalSettingsChanged, this,
+ [this](bool checked) {
+ m_widget.setEnabled(!checked);
+ m_settings.setUseGlobalSettings(checked);
+ if (!checked)
+ m_settings.setSettings(m_widget.settingsData());
+ });
+
+ const auto timer = new QTimer(this);
+ timer->setSingleShot(true);
+ timer->setInterval(5000);
+ connect(timer, &QTimer::timeout, this, [this] {
+ m_settings.setSettings(m_widget.settingsData());
+ });
+ connect(&m_widget, &ClangdSettingsWidget::settingsDataChanged,
+ timer, qOverload<>(&QTimer::start));
+ }
+
+private:
+ ClangdProjectSettings m_settings;
+ ClangdSettingsWidget m_widget;
+};
+
+class ClangdProjectSettingsPanelFactory final : public ProjectPanelFactory
+{
+public:
+ ClangdProjectSettingsPanelFactory()
+ {
+ setPriority(100);
+ setDisplayName(Tr::tr("Clangd"));
+ setCreateWidgetFunction([](Project *project) {
+ return new ClangdProjectSettingsWidget(project);
+ });
+ }
+};
+
+void setupClangdProjectSettingsPanel()
+{
+ static ClangdProjectSettingsPanelFactory theClangdProjectSettingsPanelFactory;
+}
+
+} // namespace Internal
} // namespace CppEditor
+
+#include <clangdsettings.moc>
diff --git a/src/plugins/cppeditor/clangdsettings.h b/src/plugins/cppeditor/clangdsettings.h
index c1fb3b6ae8..f3e66fb9f6 100644
--- a/src/plugins/cppeditor/clangdsettings.h
+++ b/src/plugins/cppeditor/clangdsettings.h
@@ -159,4 +159,9 @@ private:
bool m_blockIndexing = false;
};
+namespace Internal {
+void setupClangdProjectSettingsPanel();
+void setupClangdSettingsPage();
+}
+
} // namespace CppEditor
diff --git a/src/plugins/cppeditor/cppcodemodelsettingspage.cpp b/src/plugins/cppeditor/cppcodemodelsettingspage.cpp
index 0e880fcb55..1b5872c7a3 100644
--- a/src/plugins/cppeditor/cppcodemodelsettingspage.cpp
+++ b/src/plugins/cppeditor/cppcodemodelsettingspage.cpp
@@ -3,13 +3,10 @@
#include "cppcodemodelsettingspage.h"
-#include "clangdiagnosticconfigsselectionwidget.h"
-#include "clangdiagnosticconfigswidget.h"
#include "clangdsettings.h"
#include "cppcodemodelsettings.h"
#include "cppeditorconstants.h"
#include "cppeditortr.h"
-#include "cpptoolsreuse.h"
#include <coreplugin/dialogs/ioptionspage.h>
#include <coreplugin/icore.h>
@@ -22,30 +19,20 @@
#include <utils/clangutils.h>
#include <utils/fancylineedit.h>
#include <utils/infolabel.h>
-#include <utils/itemviews.h>
#include <utils/layoutbuilder.h>
#include <utils/pathchooser.h>
#include <utils/qtcassert.h>
-#include <utils/variablechooser.h>
#include <QCheckBox>
#include <QComboBox>
-#include <QDesktopServices>
-#include <QFormLayout>
-#include <QGroupBox>
-#include <QGuiApplication>
-#include <QInputDialog>
-#include <QPushButton>
+#include <QPlainTextEdit>
#include <QSpinBox>
-#include <QStringListModel>
#include <QTextBlock>
#include <QTextStream>
#include <QTimer>
#include <QVBoxLayout>
#include <QVersionNumber>
-#include <limits>
-
using namespace ProjectExplorer;
namespace CppEditor::Internal {
@@ -232,518 +219,6 @@ void setupCppCodeModelProjectSettingsPanel()
static CppCodeModelProjectSettingsPanelFactory factory;
}
-class ClangdSettingsWidget final : public QWidget
-{
- Q_OBJECT
-
-public:
- ClangdSettingsWidget(const ClangdSettings::Data &settingsData, bool isForProject);
-
- ClangdSettings::Data settingsData() const;
-
-signals:
- void settingsDataChanged();
-
-private:
- QCheckBox m_useClangdCheckBox;
- QComboBox m_indexingComboBox;
- Utils::FancyLineEdit m_projectIndexPathTemplateLineEdit;
- Utils::FancyLineEdit m_sessionIndexPathTemplateLineEdit;
- QComboBox m_headerSourceSwitchComboBox;
- QComboBox m_completionRankingModelComboBox;
- QCheckBox m_autoIncludeHeadersCheckBox;
- QCheckBox m_sizeThresholdCheckBox;
- QSpinBox m_threadLimitSpinBox;
- QSpinBox m_documentUpdateThreshold;
- QSpinBox m_sizeThresholdSpinBox;
- QSpinBox m_completionResults;
- Utils::PathChooser m_clangdChooser;
- Utils::InfoLabel m_versionWarningLabel;
- ClangDiagnosticConfigsSelectionWidget *m_configSelectionWidget = nullptr;
- QGroupBox *m_sessionsGroupBox = nullptr;
- QStringListModel m_sessionsModel;
-};
-
-ClangdSettingsWidget::ClangdSettingsWidget(const ClangdSettings::Data &settingsData,
- bool isForProject)
-{
- const ClangdSettings settings(settingsData);
- const QString indexingToolTip = Tr::tr(
- "<p>If background indexing is enabled, global symbol searches will yield more accurate "
- "results, at the cost of additional CPU load when the project is first opened. The "
- "indexing result is persisted in the project's build directory. If you disable background "
- "indexing, a faster, but less accurate, built-in indexer is used instead. The thread "
- "priority for building the background index can be adjusted since clangd 15.</p>"
- "<p>Background Priority: Minimum priority, runs on idle CPUs. May leave 'performance' "
- "cores unused.</p>"
- "<p>Normal Priority: Reduced priority compared to interactive work.</p>"
- "<p>Low Priority: Same priority as other clangd work.</p>");
- const QString projectIndexPathToolTip = Tr::tr(
- "The location of the per-project clangd index.<p>"
- "This is also where the compile_commands.json file will go.");
- const QString sessionIndexPathToolTip = Tr::tr(
- "The location of the per-session clangd index.<p>"
- "This is also where the compile_commands.json file will go.");
- const QString headerSourceSwitchToolTip = Tr::tr(
- "<p>The C/C++ backend to use for switching between header and source files.</p>"
- "<p>While the clangd implementation has more capabilities than the built-in "
- "code model, it tends to find false positives.</p>"
- "<p>When \"Try Both\" is selected, clangd is used only if the built-in variant "
- "does not find anything.</p>");
- using RankingModel = ClangdSettings::CompletionRankingModel;
- const QString completionRankingModelToolTip = Tr::tr(
- "<p>Which model clangd should use to rank possible completions.</p>"
- "<p>This determines the order of candidates in the combo box when doing code completion.</p>"
- "<p>The \"%1\" model used by default results from (pre-trained) machine learning and "
- "provides superior results on average.</p>"
- "<p>If you feel that its suggestions stray too much from your expectations for your "
- "code base, you can try switching to the hand-crafted \"%2\" model.</p>").arg(
- ClangdSettings::rankingModelToDisplayString(RankingModel::DecisionForest),
- ClangdSettings::rankingModelToDisplayString(RankingModel::Heuristics));
- const QString workerThreadsToolTip = Tr::tr(
- "Number of worker threads used by clangd. Background indexing also uses this many "
- "worker threads.");
- const QString autoIncludeToolTip = Tr::tr(
- "Controls whether clangd may insert header files as part of symbol completion.");
- const QString documentUpdateToolTip
- //: %1 is the application name (Qt Creator)
- = Tr::tr("Defines the amount of time %1 waits before sending document changes to the "
- "server.\n"
- "If the document changes again while waiting, this timeout resets.")
- .arg(QGuiApplication::applicationDisplayName());
- const QString sizeThresholdToolTip = Tr::tr(
- "Files greater than this will not be opened as documents in clangd.\n"
- "The built-in code model will handle highlighting, completion and so on.");
- const QString completionResultToolTip = Tr::tr(
- "The maximum number of completion results returned by clangd.");
-
- m_useClangdCheckBox.setText(Tr::tr("Use clangd"));
- m_useClangdCheckBox.setChecked(settings.useClangd());
- m_clangdChooser.setExpectedKind(Utils::PathChooser::ExistingCommand);
- m_clangdChooser.setFilePath(settings.clangdFilePath());
- m_clangdChooser.setAllowPathFromDevice(true);
- m_clangdChooser.setEnabled(m_useClangdCheckBox.isChecked());
- m_clangdChooser.setCommandVersionArguments({"--version"});
- using Priority = ClangdSettings::IndexingPriority;
- for (Priority prio : {Priority::Off, Priority::Background, Priority::Low, Priority::Normal}) {
- m_indexingComboBox.addItem(ClangdSettings::priorityToDisplayString(prio), int(prio));
- if (prio == settings.indexingPriority())
- m_indexingComboBox.setCurrentIndex(m_indexingComboBox.count() - 1);
- }
- m_indexingComboBox.setToolTip(indexingToolTip);
- m_projectIndexPathTemplateLineEdit.setText(settings.data().projectIndexPathTemplate);
- m_sessionIndexPathTemplateLineEdit.setText(settings.data().sessionIndexPathTemplate);
- using SwitchMode = ClangdSettings::HeaderSourceSwitchMode;
- for (SwitchMode mode : {SwitchMode::BuiltinOnly, SwitchMode::ClangdOnly, SwitchMode::Both}) {
- m_headerSourceSwitchComboBox.addItem(
- ClangdSettings::headerSourceSwitchModeToDisplayString(mode), int(mode));
- if (mode == settings.headerSourceSwitchMode())
- m_headerSourceSwitchComboBox.setCurrentIndex(
- m_headerSourceSwitchComboBox.count() - 1);
- }
- m_headerSourceSwitchComboBox.setToolTip(headerSourceSwitchToolTip);
- for (RankingModel model : {RankingModel::Default, RankingModel::DecisionForest,
- RankingModel::Heuristics}) {
- m_completionRankingModelComboBox.addItem(
- ClangdSettings::rankingModelToDisplayString(model), int(model));
- if (model == settings.completionRankingModel())
- m_completionRankingModelComboBox.setCurrentIndex(
- m_completionRankingModelComboBox.count() - 1);
- }
- m_completionRankingModelComboBox.setToolTip(completionRankingModelToolTip);
-
- m_autoIncludeHeadersCheckBox.setText(Tr::tr("Insert header files on completion"));
- m_autoIncludeHeadersCheckBox.setChecked(settings.autoIncludeHeaders());
- m_autoIncludeHeadersCheckBox.setToolTip(autoIncludeToolTip);
- m_threadLimitSpinBox.setValue(settings.workerThreadLimit());
- m_threadLimitSpinBox.setSpecialValueText(Tr::tr("Automatic"));
- m_threadLimitSpinBox.setToolTip(workerThreadsToolTip);
- m_documentUpdateThreshold.setMinimum(50);
- m_documentUpdateThreshold.setMaximum(10000);
- m_documentUpdateThreshold.setValue(settings.documentUpdateThreshold());
- m_documentUpdateThreshold.setSingleStep(100);
- m_documentUpdateThreshold.setSuffix(" ms");
- m_documentUpdateThreshold.setToolTip(documentUpdateToolTip);
- m_sizeThresholdCheckBox.setText(Tr::tr("Ignore files greater than"));
- m_sizeThresholdCheckBox.setChecked(settings.sizeThresholdEnabled());
- m_sizeThresholdCheckBox.setToolTip(sizeThresholdToolTip);
- m_sizeThresholdSpinBox.setMinimum(1);
- m_sizeThresholdSpinBox.setMaximum(std::numeric_limits<int>::max());
- m_sizeThresholdSpinBox.setSuffix(" KB");
- m_sizeThresholdSpinBox.setValue(settings.sizeThresholdInKb());
- m_sizeThresholdSpinBox.setToolTip(sizeThresholdToolTip);
-
- const auto completionResultsLabel = new QLabel(Tr::tr("Completion results:"));
- completionResultsLabel->setToolTip(completionResultToolTip);
- m_completionResults.setMinimum(0);
- m_completionResults.setMaximum(std::numeric_limits<int>::max());
- m_completionResults.setValue(settings.completionResults());
- m_completionResults.setToolTip(completionResultToolTip);
- m_completionResults.setSpecialValueText(Tr::tr("No limit"));
-
- const auto layout = new QVBoxLayout(this);
- layout->setContentsMargins(0, 0, 0, 0);
- layout->addWidget(&m_useClangdCheckBox);
-
- const auto formLayout = new QFormLayout;
- const auto chooserLabel = new QLabel(Tr::tr("Path to executable:"));
- formLayout->addRow(chooserLabel, &m_clangdChooser);
- formLayout->addRow(QString(), &m_versionWarningLabel);
-
- const auto indexingPriorityLayout = new QHBoxLayout;
- indexingPriorityLayout->addWidget(&m_indexingComboBox);
- indexingPriorityLayout->addStretch(1);
- const auto indexingPriorityLabel = new QLabel(Tr::tr("Background indexing:"));
- indexingPriorityLabel->setToolTip(indexingToolTip);
- formLayout->addRow(indexingPriorityLabel, indexingPriorityLayout);
-
- for (const auto &[text, edit, toolTip, defaultValue] :
- {std::make_tuple(Tr::tr("Per-project index location:"),
- &m_projectIndexPathTemplateLineEdit,
- projectIndexPathToolTip,
- ClangdSettings::defaultProjectIndexPathTemplate()),
- std::make_tuple(Tr::tr("Per-session index location:"),
- &m_sessionIndexPathTemplateLineEdit,
- sessionIndexPathToolTip,
- ClangdSettings::defaultSessionIndexPathTemplate())}) {
- if (isForProject && edit == &m_sessionIndexPathTemplateLineEdit)
- continue;
-
- const auto chooser = new Utils::VariableChooser(edit);
- chooser->addSupportedWidget(edit);
- chooser->addMacroExpanderProvider([] { return Utils::globalMacroExpander(); });
-
- const auto resetButton = new QPushButton(Tr::tr("Reset"));
- connect(resetButton, &QPushButton::clicked, [e = edit, v = defaultValue] { e->setText(v); });
- const auto layout = new QHBoxLayout;
- const auto label = new QLabel(text);
- label->setToolTip(toolTip);
- edit->setToolTip(toolTip);
- layout->addWidget(edit);
- layout->addWidget(resetButton);
- formLayout->addRow(label, layout);
- }
-
- const auto headerSourceSwitchLayout = new QHBoxLayout;
- headerSourceSwitchLayout->addWidget(&m_headerSourceSwitchComboBox);
- headerSourceSwitchLayout->addStretch(1);
- const auto headerSourceSwitchLabel = new QLabel(Tr::tr("Header/source switch mode:"));
- headerSourceSwitchLabel->setToolTip(headerSourceSwitchToolTip);
- formLayout->addRow(headerSourceSwitchLabel, headerSourceSwitchLayout);
-
- const auto threadLimitLayout = new QHBoxLayout;
- threadLimitLayout->addWidget(&m_threadLimitSpinBox);
- threadLimitLayout->addStretch(1);
- const auto threadLimitLabel = new QLabel(Tr::tr("Worker thread count:"));
- threadLimitLabel->setToolTip(workerThreadsToolTip);
- formLayout->addRow(threadLimitLabel, threadLimitLayout);
-
- formLayout->addRow(QString(), &m_autoIncludeHeadersCheckBox);
- const auto limitResultsLayout = new QHBoxLayout;
- limitResultsLayout->addWidget(&m_completionResults);
- limitResultsLayout->addStretch(1);
- formLayout->addRow(completionResultsLabel, limitResultsLayout);
-
- const auto completionRankingModelLayout = new QHBoxLayout;
- completionRankingModelLayout->addWidget(&m_completionRankingModelComboBox);
- completionRankingModelLayout->addStretch(1);
- const auto completionRankingModelLabel = new QLabel(Tr::tr("Completion ranking model:"));
- completionRankingModelLabel->setToolTip(completionRankingModelToolTip);
- formLayout->addRow(completionRankingModelLabel, completionRankingModelLayout);
-
- const auto documentUpdateThresholdLayout = new QHBoxLayout;
- documentUpdateThresholdLayout->addWidget(&m_documentUpdateThreshold);
- documentUpdateThresholdLayout->addStretch(1);
- const auto documentUpdateThresholdLabel = new QLabel(Tr::tr("Document update threshold:"));
- documentUpdateThresholdLabel->setToolTip(documentUpdateToolTip);
- formLayout->addRow(documentUpdateThresholdLabel, documentUpdateThresholdLayout);
- const auto sizeThresholdLayout = new QHBoxLayout;
- sizeThresholdLayout->addWidget(&m_sizeThresholdSpinBox);
- sizeThresholdLayout->addStretch(1);
- formLayout->addRow(&m_sizeThresholdCheckBox, sizeThresholdLayout);
-
- m_configSelectionWidget = new ClangDiagnosticConfigsSelectionWidget(formLayout);
- m_configSelectionWidget->refresh(
- diagnosticConfigsModel(settings.customDiagnosticConfigs()),
- settings.diagnosticConfigId(),
- [](const ClangDiagnosticConfigs &configs, const Utils::Id &configToSelect) {
- return new CppEditor::ClangDiagnosticConfigsWidget(configs, configToSelect);
- });
-
- layout->addLayout(formLayout);
- if (!isForProject) {
- m_sessionsModel.setStringList(settingsData.sessionsWithOneClangd);
- m_sessionsModel.sort(0);
- m_sessionsGroupBox = new QGroupBox(Tr::tr("Sessions with a single clangd instance"));
- const auto sessionsView = new Utils::ListView;
- sessionsView->setModel(&m_sessionsModel);
- sessionsView->setToolTip(
- Tr::tr("By default, Qt Creator runs one clangd process per project.\n"
- "If you have sessions with tightly coupled projects that should be\n"
- "managed by the same clangd process, add them here."));
- const auto outerSessionsLayout = new QHBoxLayout;
- const auto innerSessionsLayout = new QHBoxLayout(m_sessionsGroupBox);
- const auto buttonsLayout = new QVBoxLayout;
- const auto addButton = new QPushButton(Tr::tr("Add ..."));
- const auto removeButton = new QPushButton(Tr::tr("Remove"));
- buttonsLayout->addWidget(addButton);
- buttonsLayout->addWidget(removeButton);
- buttonsLayout->addStretch(1);
- innerSessionsLayout->addWidget(sessionsView);
- innerSessionsLayout->addLayout(buttonsLayout);
- outerSessionsLayout->addWidget(m_sessionsGroupBox);
- outerSessionsLayout->addStretch(1);
-
- const auto separator = new QFrame;
- separator->setFrameShape(QFrame::HLine);
- layout->addWidget(separator);
- layout->addLayout(outerSessionsLayout);
-
- const auto updateRemoveButtonState = [removeButton, sessionsView] {
- removeButton->setEnabled(sessionsView->selectionModel()->hasSelection());
- };
- connect(sessionsView->selectionModel(), &QItemSelectionModel::selectionChanged,
- this, updateRemoveButtonState);
- updateRemoveButtonState();
- connect(removeButton, &QPushButton::clicked, this, [this, sessionsView] {
- const QItemSelection selection = sessionsView->selectionModel()->selection();
- QTC_ASSERT(!selection.isEmpty(), return);
- m_sessionsModel.removeRow(selection.indexes().first().row());
- });
-
- connect(addButton, &QPushButton::clicked, this, [this, sessionsView] {
- QInputDialog dlg(sessionsView);
- QStringList sessions = Core::SessionManager::sessions();
- QStringList currentSessions = m_sessionsModel.stringList();
- for (const QString &s : std::as_const(currentSessions))
- sessions.removeOne(s);
- if (sessions.isEmpty())
- return;
- sessions.sort();
- dlg.setLabelText(Tr::tr("Choose a session:"));
- dlg.setComboBoxItems(sessions);
- if (dlg.exec() == QDialog::Accepted) {
- currentSessions << dlg.textValue();
- m_sessionsModel.setStringList(currentSessions);
- m_sessionsModel.sort(0);
- }
- });
- }
-
- const auto configFilesHelpLabel = new QLabel;
- configFilesHelpLabel->setText(Tr::tr("Additional settings are available via "
- "<a href=\"https://clangd.llvm.org/config\"> clangd configuration files</a>.<br>"
- "User-specific settings go <a href=\"%1\">here</a>, "
- "project-specific settings can be configured by putting a .clangd file into "
- "the project source tree.")
- .arg(ClangdSettings::clangdUserConfigFilePath().toUserOutput()));
- configFilesHelpLabel->setWordWrap(true);
- connect(configFilesHelpLabel, &QLabel::linkHovered, configFilesHelpLabel, &QLabel::setToolTip);
- connect(configFilesHelpLabel, &QLabel::linkActivated, [](const QString &link) {
- if (link.startsWith("https"))
- QDesktopServices::openUrl(link);
- else
- Core::EditorManager::openEditor(Utils::FilePath::fromString(link));
- });
- layout->addWidget(Layouting::createHr());
- layout->addWidget(configFilesHelpLabel);
-
- layout->addStretch(1);
-
- static const auto setWidgetsEnabled = [](QLayout *layout, bool enabled, const auto &f) -> void {
- for (int i = 0; i < layout->count(); ++i) {
- if (QWidget * const w = layout->itemAt(i)->widget())
- w->setEnabled(enabled);
- else if (QLayout * const l = layout->itemAt(i)->layout())
- f(l, enabled, f);
- }
- };
- const auto toggleEnabled = [this, formLayout](const bool checked) {
- setWidgetsEnabled(formLayout, checked, setWidgetsEnabled);
- if (m_sessionsGroupBox)
- m_sessionsGroupBox->setEnabled(checked);
- };
- connect(&m_useClangdCheckBox, &QCheckBox::toggled, toggleEnabled);
- toggleEnabled(m_useClangdCheckBox.isChecked());
- m_threadLimitSpinBox.setEnabled(m_useClangdCheckBox.isChecked());
-
- m_versionWarningLabel.setType(Utils::InfoLabel::Warning);
- const auto updateWarningLabel = [this] {
- class WarningLabelSetter {
- public:
- WarningLabelSetter(QLabel &label) : m_label(label) { m_label.clear(); }
- ~WarningLabelSetter() { m_label.setVisible(!m_label.text().isEmpty()); }
- void setWarning(const QString &text) { m_label.setText(text); }
- private:
- QLabel &m_label;
- };
- WarningLabelSetter labelSetter(m_versionWarningLabel);
-
- if (!m_clangdChooser.isValid())
- return;
- const Utils::FilePath clangdPath = m_clangdChooser.filePath();
- QString errorMessage;
- if (!Utils::checkClangdVersion(clangdPath, &errorMessage))
- labelSetter.setWarning(errorMessage);
- };
- connect(&m_clangdChooser, &Utils::PathChooser::textChanged, this, updateWarningLabel);
- connect(&m_clangdChooser, &Utils::PathChooser::validChanged, this, updateWarningLabel);
- updateWarningLabel();
-
- connect(&m_useClangdCheckBox, &QCheckBox::toggled,
- this, &ClangdSettingsWidget::settingsDataChanged);
- connect(&m_indexingComboBox, &QComboBox::currentIndexChanged,
- this, &ClangdSettingsWidget::settingsDataChanged);
- connect(&m_projectIndexPathTemplateLineEdit, &QLineEdit::textChanged,
- this, &ClangdSettingsWidget::settingsDataChanged);
- connect(&m_sessionIndexPathTemplateLineEdit, &QLineEdit::textChanged,
- this, &ClangdSettingsWidget::settingsDataChanged);
- connect(&m_headerSourceSwitchComboBox, &QComboBox::currentIndexChanged,
- this, &ClangdSettingsWidget::settingsDataChanged);
- connect(&m_completionRankingModelComboBox, &QComboBox::currentIndexChanged,
- this, &ClangdSettingsWidget::settingsDataChanged);
- connect(&m_autoIncludeHeadersCheckBox, &QCheckBox::toggled,
- this, &ClangdSettingsWidget::settingsDataChanged);
- connect(&m_threadLimitSpinBox, &QSpinBox::valueChanged,
- this, &ClangdSettingsWidget::settingsDataChanged);
- connect(&m_sizeThresholdCheckBox, &QCheckBox::toggled,
- this, &ClangdSettingsWidget::settingsDataChanged);
- connect(&m_sizeThresholdSpinBox, &QSpinBox::valueChanged,
- this, &ClangdSettingsWidget::settingsDataChanged);
- connect(&m_documentUpdateThreshold, &QSpinBox::valueChanged,
- this, &ClangdSettingsWidget::settingsDataChanged);
- connect(&m_clangdChooser, &Utils::PathChooser::textChanged,
- this, &ClangdSettingsWidget::settingsDataChanged);
- connect(m_configSelectionWidget, &ClangDiagnosticConfigsSelectionWidget::changed,
- this, &ClangdSettingsWidget::settingsDataChanged);
- connect(&m_completionResults, &QSpinBox::valueChanged,
- this, &ClangdSettingsWidget::settingsDataChanged);
-}
-
-ClangdSettings::Data ClangdSettingsWidget::settingsData() const
-{
- ClangdSettings::Data data;
- data.useClangd = m_useClangdCheckBox.isChecked();
- data.executableFilePath = m_clangdChooser.filePath();
- data.indexingPriority = ClangdSettings::IndexingPriority(
- m_indexingComboBox.currentData().toInt());
- data.projectIndexPathTemplate = m_projectIndexPathTemplateLineEdit.text();
- data.sessionIndexPathTemplate = m_sessionIndexPathTemplateLineEdit.text();
- data.headerSourceSwitchMode = ClangdSettings::HeaderSourceSwitchMode(
- m_headerSourceSwitchComboBox.currentData().toInt());
- data.completionRankingModel = ClangdSettings::CompletionRankingModel(
- m_completionRankingModelComboBox.currentData().toInt());
- data.autoIncludeHeaders = m_autoIncludeHeadersCheckBox.isChecked();
- data.workerThreadLimit = m_threadLimitSpinBox.value();
- data.documentUpdateThreshold = m_documentUpdateThreshold.value();
- data.sizeThresholdEnabled = m_sizeThresholdCheckBox.isChecked();
- data.sizeThresholdInKb = m_sizeThresholdSpinBox.value();
- data.sessionsWithOneClangd = m_sessionsModel.stringList();
- data.customDiagnosticConfigs = m_configSelectionWidget->customConfigs();
- data.diagnosticConfigId = m_configSelectionWidget->currentConfigId();
- data.completionResults = m_completionResults.value();
- return data;
-}
-
-class ClangdSettingsPageWidget final : public Core::IOptionsPageWidget
-{
-public:
- ClangdSettingsPageWidget() : m_widget(ClangdSettings::instance().data(), false)
- {
- const auto layout = new QVBoxLayout(this);
- layout->addWidget(&m_widget);
- }
-
-private:
- void apply() final { ClangdSettings::instance().setData(m_widget.settingsData()); }
-
- ClangdSettingsWidget m_widget;
-};
-
-class ClangdSettingsPage final : public Core::IOptionsPage
-{
-public:
- ClangdSettingsPage()
- {
- setId(Constants::CPP_CLANGD_SETTINGS_ID);
- setDisplayName(Tr::tr("Clangd"));
- setCategory(Constants::CPP_SETTINGS_CATEGORY);
- setWidgetCreator([] { return new ClangdSettingsPageWidget; });
- }
-};
-
-void setupClangdSettingsPage()
-{
- static ClangdSettingsPage theClangdSettingsPage;
-}
-
-class ClangdProjectSettingsWidget : public ProjectSettingsWidget
-{
-public:
- ClangdProjectSettingsWidget(const ClangdProjectSettings &settings)
- : m_settings(settings), m_widget(settings.settings(), true)
- {
- setGlobalSettingsId(Constants::CPP_CLANGD_SETTINGS_ID);
- const auto layout = new QVBoxLayout(this);
- layout->setContentsMargins(0, 0, 0, 0);
- layout->addWidget(&m_widget);
-
- const auto updateGlobalSettingsCheckBox = [this] {
- if (ClangdSettings::instance().granularity() == ClangdSettings::Granularity::Session) {
- setUseGlobalSettingsCheckBoxEnabled(false);
- setUseGlobalSettings(true);
- } else {
- setUseGlobalSettingsCheckBoxEnabled(true);
- setUseGlobalSettings(m_settings.useGlobalSettings());
- }
- m_widget.setEnabled(!useGlobalSettings());
- };
-
- updateGlobalSettingsCheckBox();
- connect(&ClangdSettings::instance(), &ClangdSettings::changed,
- this, updateGlobalSettingsCheckBox);
-
- connect(this, &ProjectSettingsWidget::useGlobalSettingsChanged, this,
- [this](bool checked) {
- m_widget.setEnabled(!checked);
- m_settings.setUseGlobalSettings(checked);
- if (!checked)
- m_settings.setSettings(m_widget.settingsData());
- });
-
- const auto timer = new QTimer(this);
- timer->setSingleShot(true);
- timer->setInterval(5000);
- connect(timer, &QTimer::timeout, this, [this] {
- m_settings.setSettings(m_widget.settingsData());
- });
- connect(&m_widget, &ClangdSettingsWidget::settingsDataChanged,
- timer, qOverload<>(&QTimer::start));
- }
-
-private:
- ClangdProjectSettings m_settings;
- ClangdSettingsWidget m_widget;
-};
-
-class ClangdProjectSettingsPanelFactory final : public ProjectPanelFactory
-{
-public:
- ClangdProjectSettingsPanelFactory()
- {
- setPriority(100);
- setDisplayName(Tr::tr("Clangd"));
- setCreateWidgetFunction([](Project *project) {
- return new ClangdProjectSettingsWidget(project);
- });
- }
-};
-
-void setupClangdProjectSettingsPanel()
-{
- static ClangdProjectSettingsPanelFactory theClangdProjectSettingsPanelFactory;
-}
-
} // CppEditor::Internal
#include "cppcodemodelsettingspage.moc"
diff --git a/src/plugins/cppeditor/cppcodemodelsettingspage.h b/src/plugins/cppeditor/cppcodemodelsettingspage.h
index 4c11b6251e..36d47ff875 100644
--- a/src/plugins/cppeditor/cppcodemodelsettingspage.h
+++ b/src/plugins/cppeditor/cppcodemodelsettingspage.h
@@ -7,7 +7,5 @@ namespace CppEditor::Internal {
void setupCppCodeModelSettingsPage();
void setupCppCodeModelProjectSettingsPanel();
-void setupClangdProjectSettingsPanel();
-void setupClangdSettingsPage();
} // CppEditor::Internal
diff --git a/src/plugins/cppeditor/cppeditorplugin.cpp b/src/plugins/cppeditor/cppeditorplugin.cpp
index 9a11039876..77a9997244 100644
--- a/src/plugins/cppeditor/cppeditorplugin.cpp
+++ b/src/plugins/cppeditor/cppeditorplugin.cpp
@@ -1,6 +1,7 @@
// Copyright (C) 2016 The Qt Company Ltd.
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
+#include "clangdsettings.h"
#include "cppautocompleter.h"
#include "cppcodemodelinspectordialog.h"
#include "cppcodemodelsettings.h"