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
|
||||
{
|
||||
std::weak_ptr<LuaClientWrapper> m_wrapper;
|
||||
QObject guard;
|
||||
|
||||
public:
|
||||
LuaClientSettings(const LuaClientSettings &wrapper);
|
||||
LuaClientSettings(const std::weak_ptr<LuaClientWrapper> &wrapper);
|
||||
~LuaClientSettings() override = default;
|
||||
|
||||
@@ -200,9 +202,11 @@ enum class TransportType { StdIO, LocalSocket };
|
||||
|
||||
class LuaClientWrapper : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
TransportType m_transportType{TransportType::StdIO};
|
||||
std::function<expected_str<void>(CommandLine &)> m_cmdLineCallback;
|
||||
std::function<expected_str<void>(QString &)> m_initOptionsCallback;
|
||||
AspectContainer *m_aspects{nullptr};
|
||||
QString m_name;
|
||||
Utils::Id m_settingsTypeId;
|
||||
@@ -242,6 +246,23 @@ public:
|
||||
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_settingsTypeId = Utils::Id::fromString(QString("Lua_%1").arg(m_name));
|
||||
m_serverName = options.get_or<QString>("serverName", "");
|
||||
@@ -273,22 +294,6 @@ public:
|
||||
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
|
||||
m_aspects = options.get<sol::optional<AspectContainer *>>("settings").value_or(nullptr);
|
||||
|
||||
@@ -461,6 +466,16 @@ public:
|
||||
if (!result)
|
||||
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)
|
||||
@@ -528,8 +543,23 @@ public:
|
||||
}
|
||||
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)
|
||||
: m_wrapper(wrapper)
|
||||
{
|
||||
@@ -539,6 +569,10 @@ LuaClientSettings::LuaClientSettings(const std::weak_ptr<LuaClientWrapper> &wrap
|
||||
m_languageFilter = w->m_languageFilter;
|
||||
m_initializationOptions = w->m_initializationOptions;
|
||||
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()) {
|
||||
w->m_name = m_name;
|
||||
if (!w->m_initOptionsCallback)
|
||||
w->m_initializationOptions = m_initializationOptions;
|
||||
w->m_languageFilter = m_languageFilter;
|
||||
w->m_startBehavior = m_startBehavior;
|
||||
@@ -570,6 +605,7 @@ void LuaClientSettings::fromMap(const Utils::Store &map)
|
||||
BaseSettings::fromMap(map);
|
||||
if (auto w = m_wrapper.lock()) {
|
||||
w->m_name = m_name;
|
||||
if (!w->m_initOptionsCallback)
|
||||
w->m_initializationOptions = m_initializationOptions;
|
||||
w->m_languageFilter = m_languageFilter;
|
||||
w->m_startBehavior = m_startBehavior;
|
||||
|
@@ -10,7 +10,7 @@ local lsp = {}
|
||||
---@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 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 onStartFailed? function This callback is called when client failed to start.
|
||||
local ClientOptions = {}
|
||||
|
Reference in New Issue
Block a user