forked from qt-creator/qt-creator
Lua LSP: Add callback if server fails to start
Change-Id: I422baeffff96cf56a110cbf74716352c9104c5ef Reviewed-by: David Schulz <david.schulz@qt.io> Reviewed-by: <github-actions-qt-creator@cristianadam.eu>
This commit is contained in:
@@ -1,9 +1,12 @@
|
||||
// Copyright (C) 2024 The Qt Company Ltd.
|
||||
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
||||
|
||||
#include <coreplugin/editormanager/editormanager.h>
|
||||
|
||||
#include <languageclient/languageclientinterface.h>
|
||||
#include <languageclient/languageclientmanager.h>
|
||||
#include <languageclient/languageclientsettings.h>
|
||||
#include <languageclient/languageclienttr.h>
|
||||
|
||||
#include <lua/bindings/inheritance.h>
|
||||
#include <lua/luaengine.h>
|
||||
@@ -27,6 +30,19 @@ namespace LanguageClient::Lua {
|
||||
|
||||
static void registerLuaApi();
|
||||
|
||||
class LuaClient : public LanguageClient::Client
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
Utils::Id m_settingsId;
|
||||
|
||||
LuaClient(BaseClientInterface *interface, Utils::Id settingsId)
|
||||
: LanguageClient::Client(interface)
|
||||
, m_settingsId(settingsId)
|
||||
{}
|
||||
};
|
||||
|
||||
class LuaLanguageClientPlugin final : public ExtensionSystem::IPlugin
|
||||
{
|
||||
Q_OBJECT
|
||||
@@ -135,6 +151,8 @@ public:
|
||||
BaseSettings *copy() const override { return new LuaClientSettings(*this); }
|
||||
|
||||
protected:
|
||||
Client *createClient(BaseClientInterface *interface) const final;
|
||||
|
||||
BaseClientInterface *createInterface(ProjectExplorer::Project *project) const override;
|
||||
};
|
||||
enum class TransportType { StdIO, LocalSocket };
|
||||
@@ -154,6 +172,7 @@ public:
|
||||
BaseSettings::StartBehavior m_startBehavior = BaseSettings::RequiresFile;
|
||||
|
||||
std::optional<sol::protected_function> m_onInstanceStart;
|
||||
std::optional<sol::protected_function> m_startFailedCallback;
|
||||
QMap<QString, sol::protected_function> m_messageCallbacks;
|
||||
|
||||
QList<Client *> m_clients;
|
||||
@@ -190,6 +209,8 @@ public:
|
||||
m_startBehavior = startBehaviorFromString(
|
||||
options.get_or<QString>("startBehavior", "AlwaysOn"));
|
||||
|
||||
m_startFailedCallback = options.get<sol::protected_function>("onStartFailed");
|
||||
|
||||
QString transportType = options.get_or<QString>("transport", "stdio");
|
||||
if (transportType == "stdio")
|
||||
m_transportType = TransportType::StdIO;
|
||||
@@ -231,35 +252,45 @@ public:
|
||||
// get<sol::optional<>> because on MSVC, get_or(..., nullptr) fails to compile
|
||||
m_aspects = options.get<sol::optional<AspectContainer *>>("settings").value_or(nullptr);
|
||||
|
||||
if (m_aspects) {
|
||||
connect(m_aspects, &AspectContainer::applied, this, [this] {
|
||||
updateOptions();
|
||||
LanguageClientManager::applySettings();
|
||||
});
|
||||
}
|
||||
|
||||
connect(
|
||||
LanguageClientManager::instance(),
|
||||
&LanguageClientManager::clientInitialized,
|
||||
this,
|
||||
[this](Client *c) {
|
||||
if (m_onInstanceStart) {
|
||||
if (auto settings = LanguageClientManager::settingForClient(c)) {
|
||||
if (settings->m_settingsTypeId == m_settingsTypeId) {
|
||||
auto result = m_onInstanceStart->call();
|
||||
|
||||
if (!result.valid()) {
|
||||
qWarning() << "Error calling instance start callback:"
|
||||
<< (result.get<sol::error>().what());
|
||||
}
|
||||
auto luaClient = qobject_cast<LuaClient *>(c);
|
||||
if (luaClient && luaClient->m_settingsId == m_settingsTypeId && m_onInstanceStart) {
|
||||
QTC_CHECK(::Lua::LuaEngine::void_safe_call(*m_onInstanceStart, c));
|
||||
|
||||
m_clients.push_back(c);
|
||||
updateMessageCallbacks();
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
connect(
|
||||
LanguageClientManager::instance(),
|
||||
&LanguageClientManager::clientRemoved,
|
||||
this,
|
||||
[this](Client *c) {
|
||||
&LuaClientWrapper::onClientRemoved);
|
||||
}
|
||||
|
||||
void onClientRemoved(Client *c, bool unexpected)
|
||||
{
|
||||
auto luaClient = qobject_cast<LuaClient *>(c);
|
||||
if (!luaClient || luaClient->m_settingsId != m_settingsTypeId)
|
||||
return;
|
||||
|
||||
if (m_clients.contains(c))
|
||||
m_clients.removeOne(c);
|
||||
});
|
||||
|
||||
if (unexpected && m_startFailedCallback)
|
||||
sol::protected_function_result result = m_startFailedCallback->call();
|
||||
}
|
||||
|
||||
// TODO: Unregister Client settings from LanguageClientManager
|
||||
@@ -457,6 +488,12 @@ QWidget *LuaClientSettings::createSettingsWidget(QWidget *parent) const
|
||||
return new BaseSettingsWidget(this, parent);
|
||||
}
|
||||
|
||||
Client *LuaClientSettings::createClient(BaseClientInterface *interface) const
|
||||
{
|
||||
Client *client = new LuaClient(interface, m_settingsTypeId);
|
||||
return client;
|
||||
}
|
||||
|
||||
BaseClientInterface *LuaClientSettings::createInterface(ProjectExplorer::Project *project) const
|
||||
{
|
||||
if (auto w = m_wrapper.lock())
|
||||
|
@@ -11,6 +11,7 @@ local lsp = {}
|
||||
---@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 settings? AspectContainer
|
||||
---@field onStartFailed? function This callback is called when client failed to start.
|
||||
local ClientOptions = {}
|
||||
|
||||
---@class LanguageFilter
|
||||
|
@@ -24,6 +24,30 @@ local function createCommand()
|
||||
|
||||
return cmd
|
||||
end
|
||||
local function installServer()
|
||||
print("Lua Language Server not found, installing ...")
|
||||
local cmds = {
|
||||
mac = "brew install lua-language-server",
|
||||
windows = "winget install lua-language-server",
|
||||
linux = "sudo apt install lua-language-server"
|
||||
}
|
||||
|
||||
if a.wait(Process.runInTerminal(cmds[Utils.HostOsInfo.os])) == 0 then
|
||||
print("Lua Language Server installed!")
|
||||
local binary = a.wait(Utils.FilePath.fromUserInput("lua-language-server"):searchInPath())
|
||||
if binary:isExecutableFile() == false then
|
||||
mm.writeFlashing("Lua Language Server was installed, but I could not find it in your PATH")
|
||||
return false
|
||||
end
|
||||
|
||||
Settings.binary.value = binary:toUserOutput()
|
||||
Settings:apply()
|
||||
return true
|
||||
end
|
||||
|
||||
mm.writeFlashing("Lua Language Server installation failed!")
|
||||
return false
|
||||
end
|
||||
local function setupClient()
|
||||
Client = LSP.Client.create({
|
||||
name = 'Lua Language Server',
|
||||
@@ -35,6 +59,11 @@ local function setupClient()
|
||||
},
|
||||
settings = Settings,
|
||||
startBehavior = "RequiresFile",
|
||||
onStartFailed = function(ask)
|
||||
a.sync(function()
|
||||
installServer()
|
||||
end)()
|
||||
end
|
||||
})
|
||||
|
||||
Client.on_instance_start = function()
|
||||
@@ -46,24 +75,6 @@ local function setupClient()
|
||||
end)
|
||||
end
|
||||
|
||||
local function installServer()
|
||||
print("Lua Language Server not found, installing ...")
|
||||
local cmds = {
|
||||
mac = "brew install lua-language-server",
|
||||
windows = "winget install lua-language-server",
|
||||
linux = "sudo apt install lua-language-server"
|
||||
}
|
||||
if a.wait(Process.runInTerminal(cmds[Utils.HostOsInfo.os])) == 0 then
|
||||
print("Lua Language Server installed!")
|
||||
Settings.binary.defaultPath = Utils.FilePath.fromUserInput("lua-language-server"):resolveSymlinks()
|
||||
Settings:apply()
|
||||
return true
|
||||
end
|
||||
|
||||
print("Lua Language Server installation failed!")
|
||||
return false
|
||||
end
|
||||
|
||||
local function using(tbl)
|
||||
local result = _G
|
||||
for k, v in pairs(tbl) do result[k] = v end
|
||||
@@ -112,8 +123,14 @@ local function setupAspect()
|
||||
labelText = "Binary:",
|
||||
toolTip = "The path to the lua-language-server binary.",
|
||||
expectedKind = S.Kind.ExistingCommand,
|
||||
defaultPath = Utils.FilePath.fromUserInput("lua-language-server"):resolveSymlinks(),
|
||||
defaultPath = Utils.FilePath.fromUserInput("lua-language-server"),
|
||||
})
|
||||
-- Search for the binary in the PATH
|
||||
local serverPath = Settings.binary.defaultPath
|
||||
local absolute = a.wait(serverPath:searchInPath()):resolveSymlinks()
|
||||
if absolute:isExecutableFile() == true then
|
||||
Settings.binary.defaultPath = absolute
|
||||
end
|
||||
Settings.developMode = S.BoolAspect.create({
|
||||
settingsKey = "LuaCopilot.DevelopMode",
|
||||
displayName = "Enable Develop Mode",
|
||||
@@ -143,15 +160,7 @@ local function setupAspect()
|
||||
return Settings
|
||||
end
|
||||
local function setup(parameters)
|
||||
print("Setting up Lua Language Server ...")
|
||||
setupAspect()
|
||||
local serverPath = Utils.FilePath.fromUserInput("lua-language-server")
|
||||
local absolute = a.wait(serverPath:searchInPath()):resolveSymlinks()
|
||||
if absolute:isExecutableFile() == true then
|
||||
Settings.binary.defaultPath = absolute
|
||||
else
|
||||
installServer()
|
||||
end
|
||||
setupClient()
|
||||
end
|
||||
|
||||
|
@@ -21,10 +21,4 @@ It will try to install it if it is not found.
|
||||
setup = function()
|
||||
require 'init'.setup()
|
||||
end,
|
||||
hooks = {
|
||||
editors = {
|
||||
documentOpened = function(doc) print("documentOpened", doc) end,
|
||||
documentClosed = function(doc) print("documentClosed", doc) end,
|
||||
}
|
||||
}
|
||||
} --[[@as QtcPlugin]]
|
||||
|
Reference in New Issue
Block a user