📦 deps(lsp_server): update conan dependencies
lsp-server ci / build-and-test (push) Failing after 0s

This commit is contained in:
csh
2026-05-27 09:54:39 +08:00
parent 7838f3ec3d
commit f4f629c232
9 changed files with 380 additions and 16 deletions
+1
View File
@@ -1,6 +1,7 @@
module;
// Global module fragment: pull in third-party headers
#include <bit>
#include <taskflow/taskflow.hpp>
export module taskflow;
+18
View File
@@ -29,6 +29,9 @@ export namespace lsp::codec
template<typename T>
static protocol::LSPAny SerializeViaJson(const T& obj);
template<typename T>
static T ConvertEnum(const protocol::LSPAny& any);
};
}
@@ -165,6 +168,14 @@ namespace lsp::codec
return std::nullopt;
return FromLSPAny<typename Type::value_type>(any);
}
else if constexpr (std::is_enum_v<Type>)
{
return ConvertEnum<Type>(any);
}
else if constexpr (requires { from_lsp_any_custom(std::type_identity<Type>{}, any); })
{
return from_lsp_any_custom(std::type_identity<Type>{}, any);
}
else if constexpr (is_user_struct_v<Type>)
{
return ConvertViaJson<Type>(any);
@@ -198,6 +209,13 @@ namespace lsp::codec
throw ConversionError("LSPAny does not contain a compatible numeric type");
}
template<typename T>
T LSPAnyConverter::ConvertEnum(const protocol::LSPAny& any)
{
using Underlying = std::underlying_type_t<T>;
return static_cast<T>(ExtractNumber<Underlying>(any));
}
template<typename T>
T LSPAnyConverter::ConvertViaJson(const protocol::LSPAny& any)
{
@@ -241,3 +241,167 @@ export namespace lsp::protocol
std::vector<InlineCompletionItem> items;
};
}
export namespace lsp::protocol
{
namespace completion_conversion_detail
{
inline const LSPObject& RequireObject(const LSPAny& any, std::string_view context)
{
if (!any.Is<LSPObject>())
throw std::runtime_error(std::string(context) + " must be an object");
return any.Get<LSPObject>();
}
inline const LSPArray& RequireArray(const LSPAny& any, std::string_view context)
{
if (!any.Is<LSPArray>())
throw std::runtime_error(std::string(context) + " must be an array");
return any.Get<LSPArray>();
}
inline const LSPAny* FindField(const LSPObject& obj, std::string_view key)
{
auto it = obj.find(string(key));
if (it == obj.end() || it->second.Is<std::nullptr_t>())
return nullptr;
return &it->second;
}
inline string ReadString(const LSPAny& any, std::string_view context)
{
if (!any.Is<string>())
throw std::runtime_error(std::string(context) + " must be a string");
return any.Get<string>();
}
inline boolean ReadBoolean(const LSPAny& any, std::string_view context)
{
if (!any.Is<boolean>())
throw std::runtime_error(std::string(context) + " must be a boolean");
return any.Get<boolean>();
}
inline std::int64_t ReadInteger(const LSPAny& any, std::string_view context)
{
if (any.Is<integer>())
return any.Get<integer>();
if (any.Is<uinteger>())
return any.Get<uinteger>();
throw std::runtime_error(std::string(context) + " must be an integer");
}
template<typename T>
std::optional<string> OptionalString(const LSPObject& obj, T key)
{
if (const auto* field = FindField(obj, key))
return ReadString(*field, key);
return std::nullopt;
}
template<typename T>
std::optional<boolean> OptionalBoolean(const LSPObject& obj, T key)
{
if (const auto* field = FindField(obj, key))
return ReadBoolean(*field, key);
return std::nullopt;
}
template<typename Enum, typename T>
std::optional<Enum> OptionalEnum(const LSPObject& obj, T key)
{
if (const auto* field = FindField(obj, key))
return static_cast<Enum>(ReadInteger(*field, key));
return std::nullopt;
}
template<typename T>
std::optional<std::vector<string>> OptionalStringVector(const LSPObject& obj, T key)
{
const auto* field = FindField(obj, key);
if (field == nullptr)
return std::nullopt;
const auto& arr = RequireArray(*field, key);
std::vector<string> values;
values.reserve(arr.size());
for (const auto& item : arr)
values.push_back(ReadString(item, key));
return values;
}
}
inline CompletionItemLabelDetails from_lsp_any_custom(std::type_identity<CompletionItemLabelDetails>,
const LSPAny& any)
{
const auto& obj = completion_conversion_detail::RequireObject(any, "CompletionItemLabelDetails");
CompletionItemLabelDetails details;
details.detail = completion_conversion_detail::OptionalString(obj, "detail");
details.description = completion_conversion_detail::OptionalString(obj, "description");
return details;
}
inline CompletionItem from_lsp_any_custom(std::type_identity<CompletionItem>, const LSPAny& any)
{
const auto& obj = completion_conversion_detail::RequireObject(any, "CompletionItem");
CompletionItem item;
const auto* label = completion_conversion_detail::FindField(obj, "label");
if (label == nullptr)
throw std::runtime_error("Missing required field: label");
item.label = completion_conversion_detail::ReadString(*label, "label");
if (const auto* label_details = completion_conversion_detail::FindField(obj, "labelDetails"))
item.labelDetails = from_lsp_any_custom(std::type_identity<CompletionItemLabelDetails>{}, *label_details);
item.kind = completion_conversion_detail::OptionalEnum<CompletionItemKind>(obj, "kind");
item.detail = completion_conversion_detail::OptionalString(obj, "detail");
item.preselect = completion_conversion_detail::OptionalBoolean(obj, "preselect");
item.sortText = completion_conversion_detail::OptionalString(obj, "sortText");
item.filterText = completion_conversion_detail::OptionalString(obj, "filterText");
item.insertText = completion_conversion_detail::OptionalString(obj, "insertText");
item.insertTextFormat = completion_conversion_detail::OptionalEnum<InsertTextFormat>(obj, "insertTextFormat");
item.insertTextMode = completion_conversion_detail::OptionalEnum<InsertTextMode>(obj, "insertTextMode");
item.textEditText = completion_conversion_detail::OptionalString(obj, "textEditText");
item.commitCharacters = completion_conversion_detail::OptionalStringVector(obj, "commitCharacters");
if (const auto* data = completion_conversion_detail::FindField(obj, "data"))
item.data = *data;
return item;
}
inline CompletionList from_lsp_any_custom(std::type_identity<CompletionList>, const LSPAny& any)
{
const auto& obj = completion_conversion_detail::RequireObject(any, "CompletionList");
CompletionList list;
const auto* is_incomplete = completion_conversion_detail::FindField(obj, "isIncomplete");
if (is_incomplete == nullptr)
throw std::runtime_error("Missing required field: isIncomplete");
list.isIncomplete = completion_conversion_detail::ReadBoolean(*is_incomplete, "isIncomplete");
if (const auto* items = completion_conversion_detail::FindField(obj, "items"))
{
const auto& arr = completion_conversion_detail::RequireArray(*items, "items");
list.items.reserve(arr.size());
for (const auto& item : arr)
list.items.push_back(from_lsp_any_custom(std::type_identity<CompletionItem>{}, item));
}
if (const auto* item_defaults = completion_conversion_detail::FindField(obj, "itemDefaults"))
{
const auto& defaults_obj = completion_conversion_detail::RequireObject(*item_defaults, "itemDefaults");
list.itemDefaults.commitCharacters =
completion_conversion_detail::OptionalStringVector(defaults_obj, "commitCharacters");
list.itemDefaults.insertTextFormat =
completion_conversion_detail::OptionalEnum<InsertTextFormat>(defaults_obj, "insertTextFormat");
list.itemDefaults.insertTextMode =
completion_conversion_detail::OptionalEnum<InsertTextMode>(defaults_obj, "insertTextMode");
if (const auto* data = completion_conversion_detail::FindField(defaults_obj, "data"))
list.itemDefaults.data = *data;
}
return list;
}
}
+31 -10
View File
@@ -16,6 +16,7 @@ export namespace lsp::scheduler
std::mutex mutex;
std::condition_variable cv;
bool completed = false;
bool callback_completed = false;
std::optional<std::string> result;
std::exception_ptr error;
std::chrono::steady_clock::time_point start_time{};
@@ -141,7 +142,7 @@ namespace lsp::scheduler
if (!state)
return false;
std::unique_lock<std::mutex> lk(state->mutex);
state->cv.wait(lk, [state]() { return state->completed; });
state->cv.wait(lk, [state]() { return state->completed && state->callback_completed; });
return true;
}
@@ -151,7 +152,7 @@ namespace lsp::scheduler
if (!state)
return std::nullopt;
std::unique_lock<std::mutex> lk(state->mutex);
if (!state->completed || state->error)
if (!state->completed || !state->callback_completed || state->error)
return std::nullopt;
return state->result;
}
@@ -213,7 +214,7 @@ namespace lsp::scheduler
}
std::unique_lock<std::mutex> lk(state->mutex);
state->cv.wait(lk, [state]() { return state->completed; });
state->cv.wait(lk, [state]() { return state->completed && state->callback_completed; });
return true;
}
@@ -231,7 +232,7 @@ namespace lsp::scheduler
for (const auto& state : tasks)
{
std::unique_lock<std::mutex> lk(state->mutex);
state->cv.wait(lk, [state]() { return state->completed; });
state->cv.wait(lk, [state]() { return state->completed && state->callback_completed; });
}
// Ensure the underlying executor finishes any tasks that may have been
@@ -334,22 +335,42 @@ namespace lsp::scheduler
state->error = std::make_exception_ptr(std::runtime_error("Task failed"));
}
state->cv.notify_all();
UnregisterTask(task_id, state);
auto elapsed = GetElapsedTime(start_time);
if (failed)
bool callback_failed = false;
if (callback)
{
try
{
callback(result, is_cancelled);
}
catch (...)
{
callback_failed = true;
std::unique_lock<std::mutex> lk(state->mutex);
state->error = std::current_exception();
}
}
const bool has_failed = failed || callback_failed;
if (has_failed)
++failed_;
else if (is_cancelled)
++cancelled_;
else
++completed_;
if (callback)
callback(result, is_cancelled);
{
std::unique_lock<std::mutex> lk(state->mutex);
state->callback_completed = true;
}
state->cv.notify_all();
spdlog::info("[{}] Task completed. cancelled={}, failed={}, elapsed={}", task_id, is_cancelled, failed, FormatDuration(elapsed));
if (callback_failed)
spdlog::error("[{}] Task callback threw exception", task_id);
spdlog::info("[{}] Task completed. cancelled={}, failed={}, elapsed={}", task_id, is_cancelled, has_failed, FormatDuration(elapsed));
}
bool AsyncExecutor::RegisterTask(const std::string& task_id, const detail::ActiveEntry& ctx)