forked from qt-creator/qt-creator
LuaLSP: Make init Options dynamic
Allows a LSP plugin to dynamically configure the initializationOptions Change-Id: Idc5d6526a732512b2e4e7394fb1c8b5749cde25d Reviewed-by: Christian Stenger <christian.stenger@qt.io>
This commit is contained in:
@@ -177,8 +177,10 @@ class LuaClientWrapper;
|
|||||||
class LuaClientSettings : public BaseSettings
|
class LuaClientSettings : public BaseSettings
|
||||||
{
|
{
|
||||||
std::weak_ptr<LuaClientWrapper> m_wrapper;
|
std::weak_ptr<LuaClientWrapper> m_wrapper;
|
||||||
|
QObject guard;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
LuaClientSettings(const LuaClientSettings &wrapper);
|
||||||
LuaClientSettings(const std::weak_ptr<LuaClientWrapper> &wrapper);
|
LuaClientSettings(const std::weak_ptr<LuaClientWrapper> &wrapper);
|
||||||
~LuaClientSettings() override = default;
|
~LuaClientSettings() override = default;
|
||||||
|
|
||||||
@@ -200,9 +202,11 @@ enum class TransportType { StdIO, LocalSocket };
|
|||||||
|
|
||||||
class LuaClientWrapper : public QObject
|
class LuaClientWrapper : public QObject
|
||||||
{
|
{
|
||||||
|
Q_OBJECT
|
||||||
public:
|
public:
|
||||||
TransportType m_transportType{TransportType::StdIO};
|
TransportType m_transportType{TransportType::StdIO};
|
||||||
std::function<expected_str<void>(CommandLine &)> m_cmdLineCallback;
|
std::function<expected_str<void>(CommandLine &)> m_cmdLineCallback;
|
||||||
|
std::function<expected_str<void>(QString &)> m_initOptionsCallback;
|
||||||
AspectContainer *m_aspects{nullptr};
|
AspectContainer *m_aspects{nullptr};
|
||||||
QString m_name;
|
QString m_name;
|
||||||
Utils::Id m_settingsTypeId;
|
Utils::Id m_settingsTypeId;
|
||||||
@@ -242,6 +246,23 @@ public:
|
|||||||
return cmdFromTable(res.get<sol::table>());
|
return cmdFromTable(res.get<sol::table>());
|
||||||
});
|
});
|
||||||
|
|
||||||
|
m_initOptionsCallback = addValue<QString>(
|
||||||
|
options,
|
||||||
|
"initializationOptions",
|
||||||
|
m_initializationOptions,
|
||||||
|
[](const sol::protected_function_result &res) -> expected_str<QString> {
|
||||||
|
if (res.get_type(0) == sol::type::table)
|
||||||
|
return ::Lua::LuaEngine::toJsonString(res.get<sol::table>());
|
||||||
|
else if (res.get_type(0) == sol::type::string)
|
||||||
|
return res.get<QString>(0);
|
||||||
|
return make_unexpected(QString("init callback did not return a table or string"));
|
||||||
|
});
|
||||||
|
|
||||||
|
if (auto initOptionsTable = options.get<sol::optional<sol::table>>("initializationOptions"))
|
||||||
|
m_initializationOptions = ::Lua::LuaEngine::toJsonString(*initOptionsTable);
|
||||||
|
else if (auto initOptionsString = options.get<sol::optional<QString>>("initializationOptions"))
|
||||||
|
m_initializationOptions = *initOptionsString;
|
||||||
|
|
||||||
m_name = options.get<QString>("name");
|
m_name = options.get<QString>("name");
|
||||||
m_settingsTypeId = Utils::Id::fromString(QString("Lua_%1").arg(m_name));
|
m_settingsTypeId = Utils::Id::fromString(QString("Lua_%1").arg(m_name));
|
||||||
m_serverName = options.get_or<QString>("serverName", "");
|
m_serverName = options.get_or<QString>("serverName", "");
|
||||||
@@ -273,22 +294,6 @@ public:
|
|||||||
m_languageFilter.mimeTypes.push_back(v.as<QString>());
|
m_languageFilter.mimeTypes.push_back(v.as<QString>());
|
||||||
}
|
}
|
||||||
|
|
||||||
auto initOptionsTable = options.get<sol::optional<sol::table>>("initializationOptions");
|
|
||||||
if (initOptionsTable) {
|
|
||||||
QJsonValue json = ::Lua::LuaEngine::toJson(*initOptionsTable);
|
|
||||||
QJsonDocument doc;
|
|
||||||
if (json.isArray()) {
|
|
||||||
doc.setArray(json.toArray());
|
|
||||||
m_initializationOptions = QString::fromUtf8(doc.toJson());
|
|
||||||
} else if (json.isObject()) {
|
|
||||||
doc.setObject(json.toObject());
|
|
||||||
m_initializationOptions = QString::fromUtf8(doc.toJson());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
auto initOptionsString = options.get<sol::optional<QString>>("initializationOptions");
|
|
||||||
if (initOptionsString)
|
|
||||||
m_initializationOptions = *initOptionsString;
|
|
||||||
|
|
||||||
// get<sol::optional<>> because on MSVC, get_or(..., nullptr) fails to compile
|
// get<sol::optional<>> because on MSVC, get_or(..., nullptr) fails to compile
|
||||||
m_aspects = options.get<sol::optional<AspectContainer *>>("settings").value_or(nullptr);
|
m_aspects = options.get<sol::optional<AspectContainer *>>("settings").value_or(nullptr);
|
||||||
|
|
||||||
@@ -461,6 +466,16 @@ public:
|
|||||||
if (!result)
|
if (!result)
|
||||||
qWarning() << "Error applying option callback:" << result.error();
|
qWarning() << "Error applying option callback:" << result.error();
|
||||||
}
|
}
|
||||||
|
if (m_initOptionsCallback) {
|
||||||
|
expected_str<void> result = m_initOptionsCallback(m_initializationOptions);
|
||||||
|
if (!result)
|
||||||
|
qWarning() << "Error applying init option callback:" << result.error();
|
||||||
|
|
||||||
|
// Right now there is only one option that needs to be mirrored to the LSP Settings,
|
||||||
|
// so we only emit optionsChanged() here. If another setting should need to be dynamic
|
||||||
|
// optionsChanged() needs to be called for it as well, but only once per updateOptions()
|
||||||
|
emit optionsChanged();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static CommandLine cmdFromTable(const sol::table &tbl)
|
static CommandLine cmdFromTable(const sol::table &tbl)
|
||||||
@@ -528,8 +543,23 @@ public:
|
|||||||
}
|
}
|
||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
signals:
|
||||||
|
void optionsChanged();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
LuaClientSettings::LuaClientSettings(const LuaClientSettings &other)
|
||||||
|
: BaseSettings::BaseSettings(other)
|
||||||
|
, m_wrapper(other.m_wrapper)
|
||||||
|
{
|
||||||
|
if (auto w = m_wrapper.lock()) {
|
||||||
|
QObject::connect(w.get(), &LuaClientWrapper::optionsChanged, &guard, [this] {
|
||||||
|
if (auto w = m_wrapper.lock())
|
||||||
|
m_initializationOptions = w->m_initializationOptions;
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
LuaClientSettings::LuaClientSettings(const std::weak_ptr<LuaClientWrapper> &wrapper)
|
LuaClientSettings::LuaClientSettings(const std::weak_ptr<LuaClientWrapper> &wrapper)
|
||||||
: m_wrapper(wrapper)
|
: m_wrapper(wrapper)
|
||||||
{
|
{
|
||||||
@@ -539,6 +569,10 @@ LuaClientSettings::LuaClientSettings(const std::weak_ptr<LuaClientWrapper> &wrap
|
|||||||
m_languageFilter = w->m_languageFilter;
|
m_languageFilter = w->m_languageFilter;
|
||||||
m_initializationOptions = w->m_initializationOptions;
|
m_initializationOptions = w->m_initializationOptions;
|
||||||
m_startBehavior = w->m_startBehavior;
|
m_startBehavior = w->m_startBehavior;
|
||||||
|
QObject::connect(w.get(), &LuaClientWrapper::optionsChanged, &guard, [this] {
|
||||||
|
if (auto w = m_wrapper.lock())
|
||||||
|
m_initializationOptions = w->m_initializationOptions;
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -548,6 +582,7 @@ bool LuaClientSettings::applyFromSettingsWidget(QWidget *widget)
|
|||||||
|
|
||||||
if (auto w = m_wrapper.lock()) {
|
if (auto w = m_wrapper.lock()) {
|
||||||
w->m_name = m_name;
|
w->m_name = m_name;
|
||||||
|
if (!w->m_initOptionsCallback)
|
||||||
w->m_initializationOptions = m_initializationOptions;
|
w->m_initializationOptions = m_initializationOptions;
|
||||||
w->m_languageFilter = m_languageFilter;
|
w->m_languageFilter = m_languageFilter;
|
||||||
w->m_startBehavior = m_startBehavior;
|
w->m_startBehavior = m_startBehavior;
|
||||||
@@ -570,6 +605,7 @@ void LuaClientSettings::fromMap(const Utils::Store &map)
|
|||||||
BaseSettings::fromMap(map);
|
BaseSettings::fromMap(map);
|
||||||
if (auto w = m_wrapper.lock()) {
|
if (auto w = m_wrapper.lock()) {
|
||||||
w->m_name = m_name;
|
w->m_name = m_name;
|
||||||
|
if (!w->m_initOptionsCallback)
|
||||||
w->m_initializationOptions = m_initializationOptions;
|
w->m_initializationOptions = m_initializationOptions;
|
||||||
w->m_languageFilter = m_languageFilter;
|
w->m_languageFilter = m_languageFilter;
|
||||||
w->m_startBehavior = m_startBehavior;
|
w->m_startBehavior = m_startBehavior;
|
||||||
|
@@ -10,7 +10,7 @@ local lsp = {}
|
|||||||
---@field serverName? string The socket path when transport == "localsocket".
|
---@field serverName? string The socket path when transport == "localsocket".
|
||||||
---@field languageFilter LanguageFilter The language filter deciding which files to open with the language server.
|
---@field languageFilter LanguageFilter The language filter deciding which files to open with the language server.
|
||||||
---@field startBehavior? "AlwaysOn"|"RequiresFile"|"RequiresProject"
|
---@field startBehavior? "AlwaysOn"|"RequiresFile"|"RequiresProject"
|
||||||
---@field initializationOptions? table|string The initialization options to pass to the language server, either a JSON string, or a table.
|
---@field initializationOptions? function|table|string The initialization options to pass to the language server, either a JSON string, a table, or a function that returns either.
|
||||||
---@field settings? AspectContainer
|
---@field settings? AspectContainer
|
||||||
---@field onStartFailed? function This callback is called when client failed to start.
|
---@field onStartFailed? function This callback is called when client failed to start.
|
||||||
local ClientOptions = {}
|
local ClientOptions = {}
|
||||||
|
Reference in New Issue
Block a user