From 2b72ba66ceb3b9968ae2a4aad982f29ed30862ef Mon Sep 17 00:00:00 2001 From: David Schulz Date: Tue, 22 Aug 2023 15:28:19 +0200 Subject: [PATCH] LanguageClient: add workspace configuration project settings Change-Id: I9876773550f3dc566dec05b78f818ca49c930da1 Reviewed-by: Christian Stenger --- .../languageclient/languageclientmanager.cpp | 17 ++++++ .../languageclient/languageclientmanager.h | 3 + .../languageclient/languageclientplugin.cpp | 10 +++ .../languageclient/languageclientsettings.cpp | 61 ++++++++++++++++++- .../languageclient/languageclientsettings.h | 26 ++++++++ 5 files changed, 116 insertions(+), 1 deletion(-) diff --git a/src/plugins/languageclient/languageclientmanager.cpp b/src/plugins/languageclient/languageclientmanager.cpp index dd369cfd4dc..fcfc7c49fa7 100644 --- a/src/plugins/languageclient/languageclientmanager.cpp +++ b/src/plugins/languageclient/languageclientmanager.cpp @@ -116,6 +116,13 @@ void LanguageClient::LanguageClientManager::addClient(Client *client) for (QList &clients : managerInstance->m_clientsForSetting) QTC_CHECK(clients.removeAll(client) == 0); }); + + ProjectExplorer::Project *project = client->project(); + if (!project) + project = ProjectExplorer::ProjectManager::startupProject(); + if (project) + client->updateConfiguration(ProjectSettings(project).workspaceConfiguration()); + emit managerInstance->clientAdded(client); } @@ -390,6 +397,16 @@ const BaseSettings *LanguageClientManager::settingForClient(Client *client) return nullptr; } +void LanguageClientManager::updateWorkspaceConfiguration(const ProjectExplorer::Project *project, + const QJsonValue &json) +{ + for (Client *client : managerInstance->m_clients) { + ProjectExplorer::Project *clientProject = client->project(); + if (!clientProject || clientProject == project) + client->updateConfiguration(json); + } +} + Client *LanguageClientManager::clientForDocument(TextEditor::TextDocument *document) { QTC_ASSERT(managerInstance, return nullptr); diff --git a/src/plugins/languageclient/languageclientmanager.h b/src/plugins/languageclient/languageclientmanager.h index 301cb4c5264..e47548b8741 100644 --- a/src/plugins/languageclient/languageclientmanager.h +++ b/src/plugins/languageclient/languageclientmanager.h @@ -60,6 +60,9 @@ public: static void enableClientSettings(const QString &settingsId, bool enable = true); static QList clientsForSetting(const BaseSettings *setting); static const BaseSettings *settingForClient(Client *setting); + static void updateWorkspaceConfiguration(const ProjectExplorer::Project *project, + const QJsonValue &json); + static Client *clientForDocument(TextEditor::TextDocument *document); static Client *clientForFilePath(const Utils::FilePath &filePath); static const QList clientsForProject(const ProjectExplorer::Project *project); diff --git a/src/plugins/languageclient/languageclientplugin.cpp b/src/plugins/languageclient/languageclientplugin.cpp index b6b411f8cb4..235ea9b5593 100644 --- a/src/plugins/languageclient/languageclientplugin.cpp +++ b/src/plugins/languageclient/languageclientplugin.cpp @@ -5,11 +5,14 @@ #include "client.h" #include "languageclientmanager.h" +#include "languageclientsettings.h" #include "languageclienttr.h" #include #include +#include + #include #include @@ -37,6 +40,13 @@ void LanguageClientPlugin::initialize() { using namespace Core; + auto panelFactory = new ProjectExplorer::ProjectPanelFactory; + panelFactory->setPriority(35); + panelFactory->setDisplayName(Tr::tr("Language Server")); + panelFactory->setCreateWidgetFunction( + [](ProjectExplorer::Project *project) { return new ProjectSettingsWidget(project); }); + ProjectExplorer::ProjectPanelFactory::registerFactory(panelFactory); + LanguageClientManager::init(); LanguageClientSettings::registerClientType({Constants::LANGUAGECLIENT_STDIO_SETTINGS_ID, Tr::tr("Generic StdIO Language Server"), diff --git a/src/plugins/languageclient/languageclientsettings.cpp b/src/plugins/languageclient/languageclientsettings.cpp index f322709eba8..d14ca1d816a 100644 --- a/src/plugins/languageclient/languageclientsettings.cpp +++ b/src/plugins/languageclient/languageclientsettings.cpp @@ -36,6 +36,7 @@ #include #include #include +#include #include #include #include @@ -1042,7 +1043,6 @@ TextEditor::BaseTextEditor *jsonEditor() TextEditorWidget *widget = textEditor->editorWidget(); widget->configureGenericHighlighter(Utils::mimeTypeForName("application/json")); widget->setLineNumbersVisible(false); - widget->setMarksVisible(false); widget->setRevisionsVisible(false); widget->setCodeFoldingSupported(false); QObject::connect(document, &TextDocument::contentsChanged, widget, [document](){ @@ -1073,4 +1073,63 @@ TextEditor::BaseTextEditor *jsonEditor() return textEditor; } +constexpr const char projectSettingsId[] = "LanguageClient.ProjectSettings"; + +ProjectSettings::ProjectSettings(ProjectExplorer::Project *project) + : m_project(project) +{ + m_json = m_project->namedSettings(projectSettingsId).toByteArray(); +} + +QJsonValue ProjectSettings::workspaceConfiguration() const +{ + const auto doc = QJsonDocument::fromJson(m_json); + if (doc.isObject()) + return doc.object(); + if (doc.isArray()) + return doc.array(); + return {}; +} + +QByteArray ProjectSettings::json() const +{ + return m_json; +} + +void ProjectSettings::setJson(const QByteArray &json) +{ + const QJsonValue oldConfig = workspaceConfiguration(); + m_json = json; + m_project->setNamedSettings(projectSettingsId, m_json); + const QJsonValue newConfig = workspaceConfiguration(); + if (oldConfig != newConfig) + LanguageClientManager::updateWorkspaceConfiguration(m_project, newConfig); +} + +ProjectSettingsWidget::ProjectSettingsWidget(ProjectExplorer::Project *project) + : m_settings(project) +{ + setUseGlobalSettingsCheckBoxVisible(false); + setGlobalSettingsId(Constants::LANGUAGECLIENT_SETTINGS_PAGE); + setExpanding(true); + + TextEditor::BaseTextEditor *editor = jsonEditor(); + editor->document()->setContents(m_settings.json()); + + auto layout = new QVBoxLayout; + setLayout(layout); + auto group = new QGroupBox(Tr::tr("Language Server Workspace Configuration")); + group->setLayout(new QVBoxLayout); + group->layout()->addWidget(new QLabel(Tr::tr( + "Additional json configuration sent to all running language servers for this project.\n" + "See the documentation of the specific language server for valid settings."))); + group->layout()->addWidget(editor->widget()); + layout->addWidget(group); + + connect(editor->editorWidget()->textDocument(), + &TextEditor::TextDocument::contentsChanged, + this, + [=]() { m_settings.setJson(editor->document()->contents()); }); +} + } // namespace LanguageClient diff --git a/src/plugins/languageclient/languageclientsettings.h b/src/plugins/languageclient/languageclientsettings.h index a19219d21d5..903edcba80f 100644 --- a/src/plugins/languageclient/languageclientsettings.h +++ b/src/plugins/languageclient/languageclientsettings.h @@ -7,6 +7,8 @@ #include +#include + #include #include #include @@ -191,6 +193,30 @@ private: QLineEdit *m_arguments = nullptr; }; +class ProjectSettings +{ +public: + explicit ProjectSettings(ProjectExplorer::Project *project); + + QJsonValue workspaceConfiguration() const; + + QByteArray json() const; + void setJson(const QByteArray &json); + +private: + ProjectExplorer::Project *m_project = nullptr; + QByteArray m_json; +}; + +class ProjectSettingsWidget : public ProjectExplorer::ProjectSettingsWidget +{ +public: + explicit ProjectSettingsWidget(ProjectExplorer::Project *project); + +private: + ProjectSettings m_settings; +}; + LANGUAGECLIENT_EXPORT TextEditor::BaseTextEditor *jsonEditor(); } // namespace LanguageClient