From c37bedfb0297b631e033c92ccf02e29a58b5914e Mon Sep 17 00:00:00 2001 From: David Schulz Date: Tue, 18 Sep 2018 10:43:17 +0200 Subject: [PATCH] LSP: split out settings specific for std io clients Change-Id: I25eebfc15a9d0d5665e57137f016e54a069ca849 Reviewed-by: Christian Stenger --- src/plugins/languageclient/baseclient.cpp | 15 +- src/plugins/languageclient/baseclient.h | 7 +- .../languageclient/languageclientmanager.cpp | 1 + .../languageclient/languageclientsettings.cpp | 169 +++++++++++------- .../languageclient/languageclientsettings.h | 58 ++++-- 5 files changed, 165 insertions(+), 85 deletions(-) diff --git a/src/plugins/languageclient/baseclient.cpp b/src/plugins/languageclient/baseclient.cpp index e885454a4b1..260275e2369 100644 --- a/src/plugins/languageclient/baseclient.cpp +++ b/src/plugins/languageclient/baseclient.cpp @@ -499,6 +499,11 @@ bool BaseClient::isSupportedMimeType(const QString &mimeType) const return m_supportedMimeTypes.isEmpty() || m_supportedMimeTypes.contains(mimeType); } +bool BaseClient::needsRestart(const BaseSettings *) const +{ + return false; +} + bool BaseClient::reset() { if (!m_restartsLeft) @@ -756,6 +761,11 @@ StdIOClient::~StdIOClient() Utils::SynchronousProcess::stopProcess(m_process); } +bool StdIOClient::needsRestart(const StdIOSettings *settings) +{ + return m_executable != settings->m_executable || m_arguments != settings->m_arguments; +} + bool StdIOClient::start() { m_process.start(); @@ -771,11 +781,6 @@ void StdIOClient::setWorkingDirectory(const QString &workingDirectory) m_process.setWorkingDirectory(workingDirectory); } -bool StdIOClient::matches(const BaseSettings *setting) -{ - return setting->m_executable == m_executable && setting->m_arguments == m_arguments; -} - void StdIOClient::sendData(const QByteArray &data) { if (m_process.state() != QProcess::Running) { diff --git a/src/plugins/languageclient/baseclient.h b/src/plugins/languageclient/baseclient.h index 08077f37ab9..3ecefcd584a 100644 --- a/src/plugins/languageclient/baseclient.h +++ b/src/plugins/languageclient/baseclient.h @@ -112,8 +112,9 @@ public: Core::Id id() const { return m_id; } + bool needsRestart(const BaseSettings *) const; + virtual bool start() { return true; } - virtual bool matches(const BaseSettings * /*setting*/) { return false; } virtual bool reset(); void log(const QString &message, @@ -175,12 +176,12 @@ public: StdIOClient &operator=(const StdIOClient &) = delete; StdIOClient &operator=(StdIOClient &&) = delete; + bool needsRestart(const StdIOSettings *settings); + bool start() override; void setWorkingDirectory(const QString &workingDirectory); - bool matches(const BaseSettings *setting) override; - protected: void sendData(const QByteArray &data) final; QProcess m_process; diff --git a/src/plugins/languageclient/languageclientmanager.cpp b/src/plugins/languageclient/languageclientmanager.cpp index 325f6e62241..d609596c367 100644 --- a/src/plugins/languageclient/languageclientmanager.cpp +++ b/src/plugins/languageclient/languageclientmanager.cpp @@ -167,6 +167,7 @@ void LanguageClientManager::removeMarks(const Core::Id &id) void LanguageClientManager::startClient(BaseClient *client) { + QTC_ASSERT(client, return); if (managerInstance->m_shuttingDown) { managerInstance->clientFinished(client); return; diff --git a/src/plugins/languageclient/languageclientsettings.cpp b/src/plugins/languageclient/languageclientsettings.cpp index b2c6adc8ca0..f139456aef1 100644 --- a/src/plugins/languageclient/languageclientsettings.cpp +++ b/src/plugins/languageclient/languageclientsettings.cpp @@ -23,8 +23,10 @@ ** ****************************************************************************/ -#include "languageclientmanager.h" #include "languageclientsettings.h" + +#include "baseclient.h" +#include "languageclientmanager.h" #include "languageclient_global.h" #include @@ -71,8 +73,9 @@ public: bool setData(const QModelIndex &index, const QVariant &value, int role) override; Qt::ItemFlags flags(const QModelIndex &index) const override; - void reset(const QList &settings); - QList settings() const { return m_settings; } + void reset(const QList &settings); + QList settings() const { return m_settings; } + QList removed() const { return m_removed; } enum Columns { DisplayNameColumn = 0, @@ -84,7 +87,8 @@ public: }; private: - QList m_settings; // owned + QList m_settings; // owned + QList m_removed; }; class LanguageClientSettingsPageWidget : public QWidget @@ -115,7 +119,7 @@ public: private: LanguageClientSettingsModel m_model; - QList m_settings; // owned + QList m_settings; // owned QPointer m_widget; }; @@ -229,43 +233,33 @@ QWidget *LanguageClientSettingsPage::widget() void LanguageClientSettingsPage::apply() { qDeleteAll(m_settings); - m_settings = Utils::transform(m_model.settings(), [](const BaseSettings *other){ - return new BaseSettings(*other); + m_settings = Utils::transform(m_model.settings(), [](const StdIOSettings *other){ + return dynamic_cast(other->copy()); }); LanguageClientSettings::toSettings(Core::ICore::settings(), m_settings); - const QVector interfaces(LanguageClientManager::clients()); - QVector toShutdown; - QList toStart = m_settings; - // check currently registered interfaces - for (auto interface : interfaces) { - auto setting = Utils::findOr(m_settings, nullptr, - [interface](const BaseSettings *setting){ - return interface->matches(setting); - }); - if (setting && setting->isValid() && setting->m_enabled) { - toStart.removeAll(setting); - if (!interface->isSupportedMimeType(setting->m_mimeType)) - interface->setSupportedMimeType({setting->m_mimeType}); - } else { - toShutdown << interface; + QList restarts = Utils::filtered(m_settings, &StdIOSettings::needsRestart); + for (auto setting : restarts + m_model.removed()) { + if (auto client = setting->m_client) { + if (client->reachable()) + client->shutdown(); + else + LanguageClientManager::deleteClient(client); } } - for (auto interface : toShutdown) { - if (interface->reachable()) - interface->shutdown(); - else - LanguageClientManager::deleteClient(interface); - } - for (auto setting : toStart) { - if (setting && setting->isValid() && setting->m_enabled) - LanguageClientManager::startClient(setting->createClient()); + for (StdIOSettings *setting : restarts) { + if (setting && setting->isValid() && setting->m_enabled) { + if (auto client = setting->createClient()) { + setting->m_client = client; + LanguageClientManager::startClient(client); + } + } } + m_model.reset(m_settings); } void LanguageClientSettingsPage::finish() { - m_model.reset(m_settings); } LanguageClientSettingsModel::~LanguageClientSettingsModel() @@ -277,7 +271,7 @@ QVariant LanguageClientSettingsModel::data(const QModelIndex &index, int role) c { if (!index.isValid()) return QVariant(); - BaseSettings *setting = m_settings[index.row()]; + StdIOSettings *setting = m_settings[index.row()]; QTC_ASSERT(setting, return false); if (role == Qt::DisplayRole || role == Qt::EditRole) { switch (index.column()) { @@ -314,7 +308,7 @@ bool LanguageClientSettingsModel::removeRows(int row, int count, const QModelInd const int end = qMin(row + count - 1, int(m_settings.size()) - 1); beginRemoveRows(parent, row, end); for (auto i = end; i >= row; --i) - delete m_settings.takeAt(i); + m_removed << m_settings.takeAt(i); endRemoveRows(); return true; } @@ -325,7 +319,7 @@ bool LanguageClientSettingsModel::insertRows(int row, int count, const QModelInd return false; beginInsertRows(parent, row, row + count - 1); for (int i = 0; i < count; ++i) - m_settings.insert(row + i, new BaseSettings()); + m_settings.insert(row + i, new StdIOSettings()); endInsertRows(); return true; } @@ -334,23 +328,31 @@ bool LanguageClientSettingsModel::setData(const QModelIndex &index, const QVaria { if (!index.isValid()) return false; - BaseSettings *setting = m_settings[index.row()]; + StdIOSettings *setting = m_settings[index.row()]; QTC_ASSERT(setting, return false); if (role == Qt::DisplayRole || role == Qt::EditRole) { + const QString strVal(value.toString()); + QString *settingsValue = nullptr; switch (index.column()) { - case DisplayNameColumn: setting->m_name = value.toString(); break; - case MimeTypeColumn: setting->m_mimeType = value.toString(); break; - case ExecutableColumn: setting->m_executable = value.toString(); break; - case ArgumentsColumn: setting->m_arguments = value.toString(); break; - default: - return false; + case DisplayNameColumn: settingsValue = &setting->m_name; break; + case MimeTypeColumn: settingsValue = &setting->m_mimeType; break; + case ExecutableColumn: settingsValue = &setting->m_executable; break; + case ArgumentsColumn: settingsValue = &setting->m_arguments; break; + } + if (settingsValue) { + if (strVal != *settingsValue) { + *settingsValue = value.toString(); + emit dataChanged(index, index, { Qt::EditRole, Qt::DisplayRole }); + } + return true; } - emit dataChanged(index, index, { Qt::EditRole, Qt::DisplayRole }); - return true; } + if (role == Qt::CheckStateRole && index.column() == EnabledColumn) { - setting->m_enabled = value.toBool(); - emit dataChanged(index, index, { Qt::CheckStateRole }); + if (setting->m_enabled != value.toBool()) { + setting->m_enabled = !setting->m_enabled; + emit dataChanged(index, index, { Qt::CheckStateRole }); + } return true; } return false; @@ -364,28 +366,31 @@ Qt::ItemFlags LanguageClientSettingsModel::flags(const QModelIndex &index) const return defaultFlags; } -void LanguageClientSettingsModel::reset(const QList &settings) +void LanguageClientSettingsModel::reset(const QList &settings) { beginResetModel(); qDeleteAll(m_settings); - m_settings = Utils::transform(settings, [](const BaseSettings *setting){ - return new BaseSettings(*setting); + qDeleteAll(m_removed); + m_removed.clear(); + m_settings = Utils::transform(settings, [](const StdIOSettings *other){ + return dynamic_cast(other->copy()); }); endResetModel(); } -bool BaseSettings::isValid() +bool BaseSettings::needsRestart() const { - return !m_name.isEmpty() && !m_executable.isEmpty() && QFile::exists(m_executable); + return m_client ? !m_enabled || m_client->needsRestart(this) : m_enabled; } -BaseClient *BaseSettings::createClient() +bool BaseSettings::isValid() const { - auto client = new StdIOClient(m_executable, m_arguments); - client->setName(m_name); - if (m_mimeType != noLanguageFilter) - client->setSupportedMimeType({m_mimeType}); - return client; + return !m_name.isEmpty(); +} + +BaseClient *BaseSettings::createClient() const +{ + return nullptr; } QVariantMap BaseSettings::toMap() const @@ -394,8 +399,6 @@ QVariantMap BaseSettings::toMap() const map.insert(nameKey, m_name); map.insert(enabledKey, m_enabled); map.insert(mimeTypeKey, m_mimeType); - map.insert(executableKey, m_executable); - map.insert(argumentsKey, m_arguments); return map; } @@ -404,8 +407,6 @@ void BaseSettings::fromMap(const QVariantMap &map) m_name = map[nameKey].toString(); m_enabled = map[enabledKey].toBool(); m_mimeType = map[mimeTypeKey].toString(); - m_executable = map[executableKey].toString(); - m_arguments = map[argumentsKey].toString(); } void LanguageClientSettings::init() @@ -414,12 +415,12 @@ void LanguageClientSettings::init() settingsPage.init(); } -QList LanguageClientSettings::fromSettings(QSettings *settingsIn) +QList LanguageClientSettings::fromSettings(QSettings *settingsIn) { settingsIn->beginGroup(settingsGroupKey); auto variants = settingsIn->value(clientsKey).toList(); auto settings = Utils::transform(variants, [](const QVariant& var){ - auto settings = new BaseSettings(); + auto settings = new StdIOSettings(); settings->fromMap(var.toMap()); return settings; }); @@ -427,14 +428,52 @@ QList LanguageClientSettings::fromSettings(QSettings *settingsIn return settings; } -void LanguageClientSettings::toSettings(QSettings *settings, const QList &languageClientSettings) +void LanguageClientSettings::toSettings(QSettings *settings, const QList &languageClientSettings) { settings->beginGroup(settingsGroupKey); settings->setValue(clientsKey, Utils::transform(languageClientSettings, - [](const BaseSettings *setting){ + [](const StdIOSettings *setting){ return QVariant(setting->toMap()); })); settings->endGroup(); } +bool StdIOSettings::needsRestart() const +{ + if (BaseSettings::needsRestart()) + return true; + if (auto stdIOClient = qobject_cast(m_client)) + return stdIOClient->needsRestart(this); + return false; +} + +bool StdIOSettings::isValid() const +{ + return BaseSettings::isValid() && !m_executable.isEmpty(); +} + +BaseClient *StdIOSettings::createClient() const +{ + auto client = new StdIOClient(m_executable, m_arguments); + client->setName(m_name); + if (m_mimeType != noLanguageFilter) + client->setSupportedMimeType({m_mimeType}); + return client; +} + +QVariantMap StdIOSettings::toMap() const +{ + QVariantMap map = BaseSettings::toMap(); + map.insert(executableKey, m_executable); + map.insert(argumentsKey, m_arguments); + return map; +} + +void StdIOSettings::fromMap(const QVariantMap &map) +{ + BaseSettings::fromMap(map); + m_executable = map[executableKey].toString(); + m_arguments = map[argumentsKey].toString(); +} + } // namespace LanguageClient diff --git a/src/plugins/languageclient/languageclientsettings.h b/src/plugins/languageclient/languageclientsettings.h index 00cc3d68f0c..9f03d7d6ab8 100644 --- a/src/plugins/languageclient/languageclientsettings.h +++ b/src/plugins/languageclient/languageclientsettings.h @@ -41,35 +41,69 @@ class BaseSettings { public: BaseSettings() = default; - BaseSettings(const QString &name, bool enabled, const QString &mimeTypeName, - const QString &executable, const QString &arguments) + BaseSettings(const QString &name, bool enabled, const QString &mimeTypeName) : m_name(name) , m_enabled(enabled) , m_mimeType(mimeTypeName) - , m_executable(executable) - , m_arguments(arguments) {} + + virtual ~BaseSettings() = default; + QString m_name = QString("New Language Server"); bool m_enabled = true; QString m_mimeType = QLatin1String(noLanguageFilter); + QPointer m_client; // not owned + + virtual BaseSettings *copy() const { return new BaseSettings(*this); } + virtual bool needsRestart() const; + virtual bool isValid() const ; + virtual BaseClient *createClient() const; + virtual QVariantMap toMap() const; + virtual void fromMap(const QVariantMap &map); + +protected: + BaseSettings(const BaseSettings &other) = default; + BaseSettings(BaseSettings &&other) = default; + BaseSettings &operator=(const BaseSettings &other) = default; + BaseSettings &operator=(BaseSettings &&other) = default; +}; + +class StdIOSettings : public BaseSettings +{ +public: + StdIOSettings() = default; + StdIOSettings(const QString &name, bool enabled, const QString &mimeTypeName, + const QString &executable, const QString &arguments) + : BaseSettings(name, enabled, mimeTypeName) + , m_executable(executable) + , m_arguments(arguments) + {} + + ~StdIOSettings() override = default; + QString m_executable; QString m_arguments; - bool isValid(); + BaseSettings *copy() const override { return new StdIOSettings(*this); } + bool needsRestart() const override; + bool isValid() const override; + BaseClient *createClient() const override; + QVariantMap toMap() const override; + void fromMap(const QVariantMap &map) override; - BaseClient *createClient(); - - QVariantMap toMap() const; - void fromMap(const QVariantMap &map); +protected: + StdIOSettings(const StdIOSettings &other) = default; + StdIOSettings(StdIOSettings &&other) = default; + StdIOSettings &operator=(const StdIOSettings &other) = default; + StdIOSettings &operator=(StdIOSettings &&other) = default; }; class LanguageClientSettings { public: static void init(); - static QList fromSettings(QSettings *settings); - static void toSettings(QSettings *settings, const QList &languageClientSettings); - + static QList fromSettings(QSettings *settings); + static void toSettings(QSettings *settings, const QList &languageClientSettings); }; } // namespace LanguageClient