LUA: Client and Utils bindings update

Change-Id: Icad01906aa9f9405004ce342399fcb42354e77df
Reviewed-by: Marcus Tillmanns <marcus.tillmanns@qt.io>
Reviewed-by: <mua@spyro-soft.com>
This commit is contained in:
Lukasz Papierkowski
2024-07-19 11:44:26 +02:00
committed by lie
parent a858e305d5
commit f4d8eaca00
4 changed files with 126 additions and 40 deletions

View File

@@ -26,6 +26,43 @@ using namespace Core;
using namespace TextEditor;
using namespace ProjectExplorer;
namespace {
class RequestWithResponse : public LanguageServerProtocol::JsonRpcMessage
{
sol::function m_callback;
LanguageServerProtocol::MessageId m_id;
public:
RequestWithResponse(const QJsonObject &obj, const sol::function &cb)
: LanguageServerProtocol::JsonRpcMessage(obj)
, m_callback(cb)
{
m_id = LanguageServerProtocol::MessageId(obj["id"]);
}
std::optional<LanguageServerProtocol::ResponseHandler> responseHandler() const override
{
if (!m_id.isValid())
qWarning() << "Invalid 'id' in request:" << toJsonObject();
return std::nullopt;
return LanguageServerProtocol::ResponseHandler{
m_id, [callback = m_callback](const JsonRpcMessage &msg) {
if (!callback.valid()) {
qWarning() << "Invalid Lua callback";
return;
}
auto result = ::Lua::LuaEngine::void_safe_call(
callback, ::Lua::LuaEngine::toTable(callback.lua_state(), msg.toJsonObject()));
QTC_CHECK_EXPECTED(result);
}};
}
};
} // anonymous namespace
namespace LanguageClient::Lua {
static void registerLuaApi();
@@ -73,14 +110,16 @@ public:
}
m_process = new Process;
m_process->setProcessMode(ProcessMode::Writer);
connect(m_process,
&Process::readyReadStandardError,
this,
&LuaLocalSocketClientInterface::readError);
connect(m_process,
&Process::readyReadStandardOutput,
this,
&LuaLocalSocketClientInterface::readOutput);
connect(
m_process,
&Process::readyReadStandardError,
this,
&LuaLocalSocketClientInterface::readError);
connect(
m_process,
&Process::readyReadStandardOutput,
this,
&LuaLocalSocketClientInterface::readOutput);
connect(m_process, &Process::started, this, [this]() {
this->LocalSocketClientInterface::startImpl();
emit started();
@@ -348,15 +387,24 @@ public:
}
}
void sendMessage(const sol::table &message)
void sendMessage(const sol::table &message, const sol::function &callback)
{
const QJsonValue messageValue = ::Lua::LuaEngine::toJson(message);
if (!messageValue.isObject())
throw sol::error("Message is not an object");
const LanguageServerProtocol::JsonRpcMessage jsonrpcmessage(messageValue.toObject());
auto make_request = [&]() -> std::unique_ptr<LanguageServerProtocol::JsonRpcMessage> {
if (callback.valid()) {
return std::make_unique<RequestWithResponse>(messageValue.toObject(), callback);
}
return std::make_unique<LanguageServerProtocol::JsonRpcMessage>(messageValue.toObject());
};
auto const request = make_request();
for (Client *c : LanguageClientManager::clientsForSettingId(m_settingsTypeId.toString())) {
if (c)
c->sendMessage(jsonrpcmessage);
c->sendMessage(*request);
}
}
@@ -545,6 +593,27 @@ static void registerLuaApi()
LanguageClientSettings::registerClientType(type);
return luaClient;
},
"documentVersion",
[](const Utils::FilePath &path) -> int {
auto client = LanguageClientManager::clientForFilePath(path);
if (!client) {
qWarning() << "documentVersion(). No client for file path:" << path;
return -1;
}
return client->documentVersion(path);
},
"hostPathToServerUri",
[](const Utils::FilePath &path) -> QString {
auto client = LanguageClientManager::clientForFilePath(path);
if (!client) {
qWarning() << "hostPathToServerUri(). No client for file path:" << path;
return {};
}
return client->hostPathToServerUri(path).toString();
});
return result;

View File

@@ -9,6 +9,7 @@
#include <utils/hostosinfo.h>
#include <QTimer>
#include <QUuid>
using namespace Utils;
@@ -25,41 +26,43 @@ void addUtilsModule()
sol::table utils = lua.create_table();
utils.set_function("waitms_cb", [guard = pluginSpec->connectionGuard.get()](int ms, const sol::function &cb) {
QTimer::singleShot(ms, guard, [cb]() { cb(); });
});
utils.set_function(
"waitms_cb",
[guard = pluginSpec->connectionGuard.get()](int ms, const sol::function &cb) {
QTimer::singleShot(ms, guard, [cb]() { cb(); });
});
auto dirEntries_cb =
[&futureSync, guard = pluginSpec->connectionGuard.get()](
const FilePath &p, const sol::table &options, const sol::function &cb) {
const QStringList nameFilters = options.get_or<QStringList>("nameFilters", {});
QDir::Filters fileFilters
= (QDir::Filters) options.get_or<int>("fileFilters", QDir::NoFilter);
QDirIterator::IteratorFlags flags
= (QDirIterator::IteratorFlags)
options.get_or<int>("flags", QDirIterator::NoIteratorFlags);
auto dirEntries_cb = [&futureSync, guard = pluginSpec->connectionGuard.get()](
const FilePath &p,
const sol::table &options,
const sol::function &cb) {
const QStringList nameFilters = options.get_or<QStringList>("nameFilters", {});
QDir::Filters fileFilters
= (QDir::Filters) options.get_or<int>("fileFilters", QDir::NoFilter);
QDirIterator::IteratorFlags flags
= (QDirIterator::IteratorFlags)
options.get_or<int>("flags", QDirIterator::NoIteratorFlags);
FileFilter filter(nameFilters, fileFilters, flags);
FileFilter filter(nameFilters, fileFilters, flags);
QFuture<FilePath> future = Utils::asyncRun(
[p, filter](QPromise<FilePath> &promise) {
p.iterateDirectory(
[&promise](const FilePath &item) {
if (promise.isCanceled())
return IterationPolicy::Stop;
QFuture<FilePath> future = Utils::asyncRun([p, filter](QPromise<FilePath> &promise) {
p.iterateDirectory(
[&promise](const FilePath &item) {
if (promise.isCanceled())
return IterationPolicy::Stop;
promise.addResult(item);
return IterationPolicy::Continue;
},
filter);
});
promise.addResult(item);
return IterationPolicy::Continue;
},
filter);
});
futureSync.addFuture<FilePath>(future);
futureSync.addFuture<FilePath>(future);
Utils::onFinished<FilePath>(future, guard, [cb](const QFuture<FilePath> &future) {
cb(future.results());
});
};
Utils::onFinished<FilePath>(future, guard, [cb](const QFuture<FilePath> &future) {
cb(future.results());
});
};
auto searchInPath_cb = [&futureSync,
guard = pluginSpec->connectionGuard
@@ -77,6 +80,8 @@ void addUtilsModule()
utils.set_function("__dirEntries_cb__", dirEntries_cb);
utils.set_function("__searchInPath_cb__", searchInPath_cb);
utils.set_function("createUuid", []() { return QUuid::createUuid().toString(); });
sol::function wrap = async["wrap"].get<sol::function>();
utils["waitms"] = wrap(utils["waitms_cb"]);

View File

@@ -32,6 +32,14 @@ function lsp.Client:registerMessage(msg, callback) end
---Sends a message to the language server.
function lsp.Client:sendMessage(msg, callback) end
---@param filePath FilePath to get the version of.
---@return int Returns -1 on error, otherwise current document version.
function lsp.Client:documentVersion(filePath) end
---
---@param filePath table file path to get the uri of.
---@return QString Returns empty string on error, otherwise the server URI string.
function lsp.Client:hostPathToServerUri(filePath) end
---Creates a new Language Client.
---@param options ClientOptions
---@return Client

View File

@@ -14,6 +14,10 @@ function utils.waitms(ms) end
---@param callback function The callback to call.
function utils.waitms_cb(ms, callback) end
---Creates a UUID.
---@return QString Arbitrary UUID string.
function utils.createUuid() end
---@class FilePath
utils.FilePath = {}