📦 deps(lsp_server): update conan dependencies
lsp-server ci / build-and-test (push) Failing after 0s
lsp-server ci / build-and-test (push) Failing after 0s
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
module;
|
||||
|
||||
// Global module fragment: pull in third-party headers
|
||||
#include <bit>
|
||||
#include <taskflow/taskflow.hpp>
|
||||
|
||||
export module taskflow;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user