diff options
Diffstat (limited to 'Build/source/utils/asymptote/LspCpp/LibLsp')
171 files changed, 20682 insertions, 0 deletions
diff --git a/Build/source/utils/asymptote/LspCpp/LibLsp/JsonRpc/Cancellation.h b/Build/source/utils/asymptote/LspCpp/LibLsp/JsonRpc/Cancellation.h new file mode 100644 index 00000000000..b89f32f1663 --- /dev/null +++ b/Build/source/utils/asymptote/LspCpp/LibLsp/JsonRpc/Cancellation.h @@ -0,0 +1,23 @@ +#pragma once +#include <functional> +#include "lsRequestId.h" +#include <LibLsp/JsonRpc/NotificationInMessage.h> +using CancelMonitor = std::function<int()>; +namespace Cancellation +{ + + struct Params { + /** + * The request id to cancel. + */ + lsRequestId id; + + MAKE_SWAP_METHOD(Cancellation::Params, id); + }; + +}; +MAKE_REFLECT_STRUCT(Cancellation::Params, id); + +DEFINE_NOTIFICATION_TYPE(Notify_Cancellation, Cancellation::Params,"$/cancelRequest"); + + diff --git a/Build/source/utils/asymptote/LspCpp/LibLsp/JsonRpc/Condition.h b/Build/source/utils/asymptote/LspCpp/LibLsp/JsonRpc/Condition.h new file mode 100644 index 00000000000..a5f550041d3 --- /dev/null +++ b/Build/source/utils/asymptote/LspCpp/LibLsp/JsonRpc/Condition.h @@ -0,0 +1,48 @@ +#pragma once +#include <condition_variable> +template <class T> +class Condition +{ +public: + + std::mutex m_mutex; + std::condition_variable m_condition; + ~Condition() { + m_condition.notify_all(); + } + void notify(std::unique_ptr<T> data) noexcept + { + { + std::lock_guard<std::mutex> eventLock(m_mutex); + any.swap(data); + } + // wake up one waiter + m_condition.notify_one(); + }; + + + std::unique_ptr<T> wait(unsigned timeout=0) + { + std::unique_lock<std::mutex> ul(m_mutex); + if (!timeout) { + m_condition.wait(ul,[&]() { + if (!any) + return false; + return true; + }); + } + else{ + if(!any){ + std::cv_status status = m_condition.wait_for(ul, std::chrono::milliseconds(timeout)); + if (status == std::cv_status::timeout) + { + return {}; + } + } + } + return std::unique_ptr<T>(any.release()); + + } +private: + std::unique_ptr<T> any; +}; diff --git a/Build/source/utils/asymptote/LspCpp/LibLsp/JsonRpc/Context.cpp b/Build/source/utils/asymptote/LspCpp/LibLsp/JsonRpc/Context.cpp new file mode 100644 index 00000000000..5fb1ad4d45f --- /dev/null +++ b/Build/source/utils/asymptote/LspCpp/LibLsp/JsonRpc/Context.cpp @@ -0,0 +1,35 @@ +//===--- Context.cpp ---------------------------------------------*- C++-*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "Context.h" +#include <cassert> + +namespace lsp { + + +Context Context::empty() { return Context(/*dataPtr=*/nullptr); } + +Context::Context(std::shared_ptr<const Data> DataPtr) + : dataPtr(std::move(DataPtr)) {} + +Context Context::clone() const { return Context(dataPtr); } + +static Context ¤tContext() { + static thread_local auto c = Context::empty(); + return c; +} + +const Context &Context::current() { return currentContext(); } + +Context Context::swapCurrent(Context Replacement) { + std::swap(Replacement, currentContext()); + return Replacement; +} + + +} // lsp clang diff --git a/Build/source/utils/asymptote/LspCpp/LibLsp/JsonRpc/Context.h b/Build/source/utils/asymptote/LspCpp/LibLsp/JsonRpc/Context.h new file mode 100644 index 00000000000..20edf71b1cb --- /dev/null +++ b/Build/source/utils/asymptote/LspCpp/LibLsp/JsonRpc/Context.h @@ -0,0 +1,216 @@ +//===--- Context.h - Mechanism for passing implicit data --------*- C++-*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// Context for storing and retrieving implicit data. Useful for passing implicit +// parameters on a per-request basis. +// +//===----------------------------------------------------------------------===// + +#pragma once + +#include <memory> +#include <type_traits> + +namespace lsp { + + +/// Values in a Context are indexed by typed keys. +/// Key<T> serves two purposes: +/// - it provides a lookup key for the context (each Key is unique), +/// - it makes lookup type-safe: a Key<T> can only map to a T (or nothing). +/// +/// Example: +/// Key<int> RequestID; +/// Key<int> Version; +/// +/// Context Ctx = Context::empty().derive(RequestID, 10).derive(Version, 3); +/// assert(*Ctx.get(RequestID) == 10); +/// assert(*Ctx.get(Version) == 3); +/// +/// Keys are typically used across multiple functions, so most of the time you +/// would want to make them static class members or global variables. +template <class Type> class Key { +public: + static_assert(!std::is_reference<Type>::value, + "Reference arguments to Key<> are not allowed"); + + constexpr Key() = default; + + Key(Key const &) = delete; + Key &operator=(Key const &) = delete; + Key(Key &&) = delete; + Key &operator=(Key &&) = delete; +}; + +/// A context is an immutable container for per-request data that must be +/// propagated through layers that don't care about it. An example is a request +/// ID that we may want to use when logging. +/// +/// Conceptually, a context is a heterogeneous map<Key<T>, T>. Each key has +/// an associated value type, which allows the map to be typesafe. +/// +/// There is an "ambient" context for each thread, Context::current(). +/// Most functions should read from this, and use WithContextValue or +/// WithContext to extend or replace the context within a block scope. +/// Only code dealing with threads and extension points should need to use +/// other Context objects. +/// +/// You can't add data to an existing context, instead you create a new +/// immutable context derived from it with extra data added. When you retrieve +/// data, the context will walk up the parent chain until the key is found. +class Context { +public: + /// Returns an empty root context that contains no data. + static Context empty(); + /// Returns the context for the current thread, creating it if needed. + static const Context ¤t(); + // Sets the current() context to Replacement, and returns the old context. + // Prefer to use WithContext or WithContextValue to do this safely. + static Context swapCurrent(Context Replacement); + +private: + struct Data; + Context(std::shared_ptr<const Data> DataPtr); + +public: + /// Same as Context::empty(), please use Context::empty() instead. + Context() = default; + + /// Copy operations for this class are deleted, use an explicit clone() method + /// when you need a copy of the context instead. + Context(Context const &) = delete; + Context &operator=(const Context &) = delete; + + Context(Context &&) = default; + Context &operator=(Context &&) = default; + + /// Get data stored for a typed \p Key. If values are not found + /// \returns Pointer to the data associated with \p Key. If no data is + /// specified for \p Key, return null. + template <class Type> const Type *get(const Key<Type> &Key) const { + for (const Data *DataPtr = this->dataPtr.get(); DataPtr != nullptr; + DataPtr = DataPtr->parent.get()) { + if (DataPtr->KeyPtr == &Key) + return static_cast<const Type *>(DataPtr->value->getValuePtr()); + } + return nullptr; + } + + /// A helper to get a reference to a \p Key that must exist in the map. + /// Must not be called for keys that are not in the map. + template <class Type> const Type &getExisting(const Key<Type> &Key) const { + auto Val = get(Key); + assert(Val && "Key does not exist"); + return *Val; + } + + /// Derives a child context + /// It is safe to move or destroy a parent context after calling derive(). + /// The child will keep its parent alive, and its data remains accessible. + template <class Type> + Context derive(const Key<Type> &Key, + typename std::decay<Type>::type Value) const & { + return Context(std::make_shared<Data>( + Data{/*parent=*/dataPtr, &Key, + std::make_unique<TypedAnyStorage<typename std::decay<Type>::type>>( + std::move(Value))})); + } + + template <class Type> + Context + derive(const Key<Type> &Key, + typename std::decay<Type>::type Value) && /* takes ownership */ { + return Context(std::make_shared<Data>( + Data{/*parent=*/std::move(dataPtr), &Key, + std::make_unique<TypedAnyStorage<typename std::decay<Type>::type>>( + std::move(Value))})); + } + + /// Derives a child context, using an anonymous key. + /// Intended for objects stored only for their destructor's side-effect. + template <class Type> Context derive(Type &&Value) const & { + static Key<typename std::decay<Type>::type> Private; + return derive(Private, std::forward<Type>(Value)); + } + + template <class Type> Context derive(Type &&Value) && { + static Key<typename std::decay<Type>::type> Private; + return std::move(*this).derive(Private, std::forward<Type>(Value)); + } + + /// Clone this context object. + Context clone() const; + +private: + class AnyStorage { + public: + virtual ~AnyStorage() = default; + virtual void *getValuePtr() = 0; + }; + + template <class T> class TypedAnyStorage : public Context::AnyStorage { + static_assert(std::is_same<typename std::decay<T>::type, T>::value, + "Argument to TypedAnyStorage must be decayed"); + + public: + TypedAnyStorage(T &&Value) : value(std::move(Value)) {} + + void *getValuePtr() override { return &value; } + + private: + T value; + }; + + struct Data { + // We need to make sure parent outlives the value, so the order of members + // is important. We do that to allow classes stored in Context's child + // layers to store references to the data in the parent layers. + std::shared_ptr<const Data> parent; + const void *KeyPtr; + std::unique_ptr<AnyStorage> value; + }; + + std::shared_ptr<const Data> dataPtr; +}; + +/// WithContext replaces Context::current() with a provided scope. +/// When the WithContext is destroyed, the original scope is restored. +/// For extending the current context with new value, prefer WithContextValue. +class WithContext { +public: + WithContext(Context C) : restore(Context::swapCurrent(std::move(C))) {} + ~WithContext() { Context::swapCurrent(std::move(restore)); } + WithContext(const WithContext &) = delete; + WithContext &operator=(const WithContext &) = delete; + WithContext(WithContext &&) = delete; + WithContext &operator=(WithContext &&) = delete; + +private: + Context restore; +}; + +/// WithContextValue extends Context::current() with a single value. +/// When the WithContextValue is destroyed, the original scope is restored. +class WithContextValue { +public: + template <typename T> + WithContextValue(const Key<T> &K, typename std::decay<T>::type V) + : restore(Context::current().derive(K, std::move(V))) {} + + // Anonymous values can be used for the destructor side-effect. + template <typename T> + WithContextValue(T &&V) + : restore(Context::current().derive(std::forward<T>(V))) {} + +private: + WithContext restore; +}; + + +} // namespace lsp + diff --git a/Build/source/utils/asymptote/LspCpp/LibLsp/JsonRpc/Endpoint.cpp b/Build/source/utils/asymptote/LspCpp/LibLsp/JsonRpc/Endpoint.cpp new file mode 100644 index 00000000000..549744555b6 --- /dev/null +++ b/Build/source/utils/asymptote/LspCpp/LibLsp/JsonRpc/Endpoint.cpp @@ -0,0 +1,46 @@ +#include "Endpoint.h" +#include "message.h" + + +bool GenericEndpoint::notify(std::unique_ptr<LspMessage> msg) +{ + auto findIt = method2notification.find(msg->GetMethodType()); + + if (findIt != method2notification.end()) + { + return findIt->second(std::move(msg)); + } + std::string info = "can't find method2notification for notification:\n" + msg->ToJson() + "\n"; + log.log(lsp::Log::Level::SEVERE, info); + return false; +} + +bool GenericEndpoint::onResponse(const std::string& method, std::unique_ptr<LspMessage>msg) +{ + auto findIt = method2response.find(method); + + if (findIt != method2response.end()) + { + return findIt->second(std::move(msg)); + } + + std::string info = "can't find method2response for response:\n" + msg->ToJson() + "\n"; + log.log(lsp::Log::Level::SEVERE, info); + + return false; +} + + + +bool GenericEndpoint::onRequest(std::unique_ptr<LspMessage> request) +{ + auto findIt = method2request.find(request->GetMethodType()); + + if (findIt != method2request.end()) + { + return findIt->second(std::move(request)); + } + std::string info = "can't find method2request for request:\n" + request->ToJson() + "\n"; + log.log(lsp::Log::Level::SEVERE, info); + return false; +} diff --git a/Build/source/utils/asymptote/LspCpp/LibLsp/JsonRpc/Endpoint.h b/Build/source/utils/asymptote/LspCpp/LibLsp/JsonRpc/Endpoint.h new file mode 100644 index 00000000000..01d8e8ca91e --- /dev/null +++ b/Build/source/utils/asymptote/LspCpp/LibLsp/JsonRpc/Endpoint.h @@ -0,0 +1,53 @@ +#pragma once +#include <map> +#include <functional> +#include <memory> +#include "MessageIssue.h" +struct LspMessage; +struct NotificationInMessage; +struct lsBaseOutMessage; +struct RequestInMessage; + +using GenericResponseHandler = std::function< bool(std::unique_ptr<LspMessage>) >; +using GenericRequestHandler = std::function< bool(std::unique_ptr<LspMessage>) >; +using GenericNotificationHandler = std::function< bool(std::unique_ptr<LspMessage>) >; + +class Endpoint +{ +public: + virtual ~Endpoint() = default; + virtual bool onRequest(std::unique_ptr<LspMessage>) = 0; + virtual bool notify(std::unique_ptr<LspMessage>) = 0; + + virtual bool onResponse(const std::string&, std::unique_ptr<LspMessage>) = 0; + virtual void registerRequestHandler(const std::string&, GenericResponseHandler ) = 0; + virtual void registerNotifyHandler(const std::string&, GenericNotificationHandler ) = 0; +}; + +class GenericEndpoint :public Endpoint +{ + +public: + GenericEndpoint(lsp::Log& l):log(l){} + bool notify(std::unique_ptr<LspMessage>) override; + bool onResponse(const std::string&, std::unique_ptr<LspMessage>) override; + + bool onRequest(std::unique_ptr<LspMessage>) override; + std::map< std::string, GenericRequestHandler > method2request; + std::map< std::string, GenericResponseHandler > method2response; + std::map< std::string, GenericNotificationHandler > method2notification; + + void registerRequestHandler(const std::string& method, GenericResponseHandler cb) override + { + method2request[method] = cb; + } + + void registerNotifyHandler(const std::string& method, GenericNotificationHandler cb) override + { + method2notification[method] = cb; + } + lsp::Log& log; + + + +}; diff --git a/Build/source/utils/asymptote/LspCpp/LibLsp/JsonRpc/GCThreadContext.cpp b/Build/source/utils/asymptote/LspCpp/LibLsp/JsonRpc/GCThreadContext.cpp new file mode 100644 index 00000000000..15253411a16 --- /dev/null +++ b/Build/source/utils/asymptote/LspCpp/LibLsp/JsonRpc/GCThreadContext.cpp @@ -0,0 +1,17 @@ +#include "GCThreadContext.h" +#include <iostream> + +GCThreadContext::GCThreadContext() +{ +#ifdef USEGC + GC_get_stack_base(&gsb); + GC_register_my_thread(&gsb); +#endif +} + +GCThreadContext::~GCThreadContext() +{ +#ifdef USEGC + GC_unregister_my_thread(); +#endif +}
\ No newline at end of file diff --git a/Build/source/utils/asymptote/LspCpp/LibLsp/JsonRpc/GCThreadContext.h b/Build/source/utils/asymptote/LspCpp/LibLsp/JsonRpc/GCThreadContext.h new file mode 100644 index 00000000000..a0f7db288d4 --- /dev/null +++ b/Build/source/utils/asymptote/LspCpp/LibLsp/JsonRpc/GCThreadContext.h @@ -0,0 +1,19 @@ +#pragma once + +#if defined(USEGC) +#define GC_THREADS +#include <gc.h> +#endif + +class GCThreadContext +{ +public: + GCThreadContext(); + ~GCThreadContext(); + +private: +#if defined(USEGC) + GC_stack_base gsb; +#endif + +};
\ No newline at end of file diff --git a/Build/source/utils/asymptote/LspCpp/LibLsp/JsonRpc/MessageIssue.h b/Build/source/utils/asymptote/LspCpp/LibLsp/JsonRpc/MessageIssue.h new file mode 100644 index 00000000000..bda6e65d46d --- /dev/null +++ b/Build/source/utils/asymptote/LspCpp/LibLsp/JsonRpc/MessageIssue.h @@ -0,0 +1,182 @@ +#pragma once +#include <string> +#include <functional> +#include <vector> +namespace lsp +{ + class Log + { + public: + virtual ~Log() = default; + + enum class Level + { + /** + * OFF is a special level that can be used to turn off logging. + + */ + OFF = 1, + + /** + * SEVERE is a message level indicating a serious failure. + * <p> + * In general SEVERE messages should describe events that are + * of considerable importance and which will prevent normal + * program execution. They should be reasonably intelligible + * to end users and to system administrators. + + */ + SEVERE = 2, + + /** + * WARNING is a message level indicating a potential problem. + * <p> + * In general WARNING messages should describe events that will + * be of interest to end users or system managers, or which + * indicate potential problems. + + * + */ + WARNING = 3, + /** + * INFO is a message level for informational messages. + * <p> + * Typically INFO messages will be written to the console + * or its equivalent. So the INFO level should only be + * used for reasonably significant messages that will + * make sense to end users and system administrators. + + */ + INFO = 3, + /** + * CONFIG is a message level for static configuration messages. + * <p> + * CONFIG messages are intended to provide a variety of static + * configuration information, to assist in debugging problems + * that may be associated with particular configurations. + * For example, CONFIG message might include the CPU type, + * the graphics depth, the GUI look-and-feel, etc. + * This level is initialized to <CODE>4</CODE>. + */ + + CONFIG = 4, + + + + /** + * FINE is a message level providing tracing information. + * <p> + * All of FINE, FINER, and FINEST are intended for relatively + * detailed tracing. The exact meaning of the three levels will + * vary between subsystems, but in general, FINEST should be used + * for the most voluminous detailed output, FINER for somewhat + * less detailed output, and FINE for the lowest volume (and + * most important) messages. + * <p> + * In general the FINE level should be used for information + * that will be broadly interesting to developers who do not have + * a specialized interest in the specific subsystem. + * <p> + * FINE messages might include things like minor (recoverable) + * failures. Issues indicating potential performance problems + * are also worth logging as FINE. + * This level is initialized to <CODE>5</CODE>. + */ + FINE = 5, + + /** + * FINER indicates a fairly detailed tracing message. + * By default logging calls for entering, returning, or throwing + * an exception are traced at this level. + * This level is initialized to <CODE>400</CODE>. + */ + FINER = 6, + + /** + * FINEST indicates a highly detailed tracing message. + * This level is initialized to <CODE>300</CODE>. + */ + FINEST = 7, + + /** + * ALL indicates that all messages should be logged. + * This level is initialized to <CODE>Integer.MIN_VALUE</CODE>. + */ + ALL, + }; + virtual void log(Level level, std::wstring&& msg) = 0; + virtual void log(Level level, const std::wstring& msg) = 0; + virtual void log(Level level, std::string&& msg) = 0; + virtual void log(Level level, const std::string& msg) = 0; + + void info(const std::string& msg) + { + log(Level::INFO, msg); + } + void info(const std::wstring& msg) + { + log(Level::INFO, msg); + } + void error(const std::string& msg) + { + log(Level::SEVERE, msg); + } + void error(const std::wstring& msg) + { + log(Level::SEVERE, msg); + } + void warning(const std::string& msg) + { + log(Level::WARNING, msg); + } + void warning(const std::wstring& msg) + { + log(Level::WARNING, msg); + } + }; +} + +class MessageIssue { + +public: + std::string text; + + lsp::Log::Level code; + + MessageIssue(const std::string& text, lsp::Log::Level code) :text(text), code(code) + { + + + } + MessageIssue(std::string&& text, lsp::Log::Level code) :text(text), code(code) + { + + + } + + + std::string getText() { + return text; + } + + lsp::Log::Level getIssueCode() { + return code; + } + + + std::string toString() { + return getText(); + } + +}; +class MessageIssueHandler +{ +public: + /** + * Handle issues found while parsing or validating a message. The list of issues must not be empty. + */ + virtual ~MessageIssueHandler() = default; + + virtual void handle(std::vector<MessageIssue>&&) = 0; + virtual void handle( MessageIssue&&) = 0; +}; diff --git a/Build/source/utils/asymptote/LspCpp/LibLsp/JsonRpc/MessageJsonHandler.cpp b/Build/source/utils/asymptote/LspCpp/LibLsp/JsonRpc/MessageJsonHandler.cpp new file mode 100644 index 00000000000..111b29aa1c8 --- /dev/null +++ b/Build/source/utils/asymptote/LspCpp/LibLsp/JsonRpc/MessageJsonHandler.cpp @@ -0,0 +1,57 @@ +#include "MessageJsonHandler.h" +#include <string> +#include <rapidjson/document.h> + + + +std::unique_ptr<LspMessage> MessageJsonHandler::parseResponseMessage(const std::string& method, Reader& r) +{ + auto findIt = method2response.find(method); + + if( findIt != method2response.end()) + { + return findIt->second(r); + } + return nullptr; +} + +std::unique_ptr<LspMessage> MessageJsonHandler::parseRequstMessage(const std::string& method, Reader&r) +{ + auto findIt = method2request.find(method); + + if (findIt != method2request.end()) + { + return findIt->second(r); + } + return nullptr; +} + +bool MessageJsonHandler::resovleResponseMessage(Reader&r, std::pair<std::string, std::unique_ptr<LspMessage>>& result) +{ + for (auto& handler : method2response) + { + try + { + auto msg = handler.second(r); + result.first = handler.first; + result.second = std::move(msg); + return true; + } + catch (...) + { + + } + } + return false; +} + +std::unique_ptr<LspMessage> MessageJsonHandler::parseNotificationMessage(const std::string& method, Reader& r) +{ + auto findIt = method2notification.find(method); + + if (findIt != method2notification.end()) + { + return findIt->second(r); + } + return nullptr; +} diff --git a/Build/source/utils/asymptote/LspCpp/LibLsp/JsonRpc/MessageJsonHandler.h b/Build/source/utils/asymptote/LspCpp/LibLsp/JsonRpc/MessageJsonHandler.h new file mode 100644 index 00000000000..7e238b0cf6e --- /dev/null +++ b/Build/source/utils/asymptote/LspCpp/LibLsp/JsonRpc/MessageJsonHandler.h @@ -0,0 +1,61 @@ +#pragma once +#include <string> +#include <map> +#include <functional> +#include <LibLsp/JsonRpc/message.h> +class Reader; + + +using GenericRequestJsonHandler = std::function< std::unique_ptr<LspMessage>(Reader&) >; +using GenericResponseJsonHandler = std::function< std::unique_ptr<LspMessage>(Reader&) >; +using GenericNotificationJsonHandler = std::function< std::unique_ptr<LspMessage>(Reader&) >; + +class MessageJsonHandler +{ +public: + std::map< std::string, GenericRequestJsonHandler > method2request; + std::map< std::string, GenericResponseJsonHandler > method2response; + std::map< std::string, GenericNotificationJsonHandler > method2notification; + + + const GenericRequestJsonHandler* GetRequestJsonHandler(const char* methodInfo) const + { + const auto findIt = method2request.find(methodInfo); + return findIt == method2request.end() ? nullptr : &findIt->second; + } + + void SetRequestJsonHandler(const std::string& methodInfo, GenericRequestJsonHandler handler) + { + method2request[methodInfo] = handler; + } + + const GenericResponseJsonHandler* GetResponseJsonHandler(const char* methodInfo) const + { + const auto findIt = method2response.find(methodInfo); + return findIt == method2response.end() ? nullptr : &findIt->second; + } + + void SetResponseJsonHandler(const std::string& methodInfo,GenericResponseJsonHandler handler) + { + method2response[methodInfo] = handler; + } + + const GenericNotificationJsonHandler* GetNotificationJsonHandler(const char* methodInfo) const + { + const auto findIt = method2notification.find(methodInfo); + return findIt == method2notification.end() ? nullptr : &findIt->second; + } + + void SetNotificationJsonHandler(const std::string& methodInfo, GenericNotificationJsonHandler handler) + { + method2notification[methodInfo] = handler; + } + + + + std::unique_ptr<LspMessage> parseResponseMessage(const std::string&, Reader&); + std::unique_ptr<LspMessage> parseRequstMessage(const std::string&, Reader&); + bool resovleResponseMessage(Reader&, std::pair<std::string, std::unique_ptr<LspMessage>>& result); + std::unique_ptr<LspMessage> parseNotificationMessage(const std::string&, Reader&); +}; + diff --git a/Build/source/utils/asymptote/LspCpp/LibLsp/JsonRpc/MessageProducer.h b/Build/source/utils/asymptote/LspCpp/LibLsp/JsonRpc/MessageProducer.h new file mode 100644 index 00000000000..ab7a29a17f7 --- /dev/null +++ b/Build/source/utils/asymptote/LspCpp/LibLsp/JsonRpc/MessageProducer.h @@ -0,0 +1,13 @@ +#pragma once +#include <string> +#include <functional> + +class MessageProducer +{ +public: + + + typedef std::function< void(std::string&&) > MessageConsumer; + virtual ~MessageProducer() = default; + virtual void listen(MessageConsumer) = 0; +}; diff --git a/Build/source/utils/asymptote/LspCpp/LibLsp/JsonRpc/NotificationInMessage.h b/Build/source/utils/asymptote/LspCpp/LibLsp/JsonRpc/NotificationInMessage.h new file mode 100644 index 00000000000..e4841b5703c --- /dev/null +++ b/Build/source/utils/asymptote/LspCpp/LibLsp/JsonRpc/NotificationInMessage.h @@ -0,0 +1,62 @@ +#pragma once + + +#include "lsRequestId.h" +#include "LibLsp/JsonRpc/message.h" + + + +// NotificationInMessage does not have |id|. +struct NotificationInMessage : public LspMessage { + + Kind GetKid() override + { + return NOTIFICATION_MESSAGE; + } + MethodType GetMethodType() const override + { + return method.c_str(); + } + void SetMethodType(MethodType _t) override + { + method = _t; + } + std::string method; +}; +template <class T, class TDerived > +struct lsNotificationInMessage : NotificationInMessage { + + void ReflectWriter(Writer& writer) override { + Reflect(writer, static_cast<TDerived&>(*this)); + } + lsNotificationInMessage(MethodType _method) + { + method = _method; + } + + static std::unique_ptr<LspMessage> ReflectReader(Reader& visitor) { + + TDerived* temp = new TDerived(); + + std::unique_ptr<TDerived> message = std::unique_ptr<TDerived>(temp); + // Reflect may throw and *message will be partially deserialized. + Reflect(visitor, static_cast<TDerived&>(*temp)); + return message; + + } + void swap(lsNotificationInMessage& arg) noexcept + { + method.swap(method); + std::swap(params, arg.params); + } + T params; +}; + +#define DEFINE_NOTIFICATION_TYPE(MSG,paramType,methodInfo)\ +namespace MSG {\ + struct notify : public lsNotificationInMessage< paramType , notify >{\ + static constexpr MethodType kMethodInfo = methodInfo;\ + notify():lsNotificationInMessage(kMethodInfo){} \ + };\ +};\ +MAKE_REFLECT_STRUCT(MSG::notify, jsonrpc,method, params) diff --git a/Build/source/utils/asymptote/LspCpp/LibLsp/JsonRpc/RemoteEndPoint.cpp b/Build/source/utils/asymptote/LspCpp/LibLsp/JsonRpc/RemoteEndPoint.cpp new file mode 100644 index 00000000000..46f09ec6862 --- /dev/null +++ b/Build/source/utils/asymptote/LspCpp/LibLsp/JsonRpc/RemoteEndPoint.cpp @@ -0,0 +1,612 @@ +#include "MessageJsonHandler.h" +#include "Endpoint.h" +#include "message.h" +#include "RemoteEndPoint.h" +#include <future> +#include "Cancellation.h" +#include "StreamMessageProducer.h" +#include "NotificationInMessage.h" +#include "lsResponseMessage.h" +#include "Condition.h" +#include "Context.h" +#include "rapidjson/error/en.h" +#include "json.h" +#include "GCThreadContext.h" +#include "ScopeExit.h" +#include "stream.h" + +#define BOOST_BIND_GLOBAL_PLACEHOLDERS +#include "boost/threadpool.hpp" +#include <atomic> +namespace lsp { + +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +//===----------------------------------------------------------------------===// + +// Cancellation mechanism for long-running tasks. +// +// This manages interactions between: +// +// 1. Client code that starts some long-running work, and maybe cancels later. +// +// std::pair<Context, Canceler> Task = cancelableTask(); +// { +// WithContext Cancelable(std::move(Task.first)); +// Expected +// deepThoughtAsync([](int answer){ errs() << answer; }); +// } +// // ...some time later... +// if (User.fellAsleep()) +// Task.second(); +// +// (This example has an asynchronous computation, but synchronous examples +// work similarly - the Canceler should be invoked from another thread). +// +// 2. Library code that executes long-running work, and can exit early if the +// result is not needed. +// +// void deepThoughtAsync(std::function<void(int)> Callback) { +// runAsync([Callback]{ +// int A = ponder(6); +// if (getCancelledMonitor()) +// return; +// int B = ponder(9); +// if (getCancelledMonitor()) +// return; +// Callback(A * B); +// }); +// } +// +// (A real example may invoke the callback with an error on cancellation, +// the CancelledError is provided for this purpose). +// +// Cancellation has some caveats: +// - the work will only stop when/if the library code next checks for it. +// Code outside clangd such as Sema will not do this. +// - it's inherently racy: client code must be prepared to accept results +// even after requesting cancellation. +// - it's Context-based, so async work must be dispatched to threads in +// ways that preserve the context. (Like runAsync() or TUScheduler). +// + + /// A canceller requests cancellation of a task, when called. + /// Calling it again has no effect. + using Canceler = std::function<void()>; + + // We don't want a cancelable scope to "shadow" an enclosing one. + struct CancelState { + std::shared_ptr<std::atomic<int>> cancelled; + const CancelState* parent = nullptr; + lsRequestId id; + }; + static Key<CancelState> g_stateKey; + + /// Defines a new task whose cancellation may be requested. + /// The returned Context defines the scope of the task. + /// When the context is active, getCancelledMonitor() is 0 until the Canceler is + /// invoked, and equal to Reason afterwards. + /// Conventionally, Reason may be the LSP error code to return. + std::pair<Context, Canceler> cancelableTask(const lsRequestId& id,int reason = 1){ + assert(reason != 0 && "Can't detect cancellation if Reason is zero"); + CancelState state; + state.id = id; + state.cancelled = std::make_shared<std::atomic<int>>(); + state.parent = Context::current().get(g_stateKey); + return { + Context::current().derive(g_stateKey, state), + [reason, cancelled(state.cancelled)] { *cancelled = reason; }, + }; + } + /// If the current context is within a cancelled task, returns the reason. +/// (If the context is within multiple nested tasks, true if any are cancelled). +/// Always zero if there is no active cancelable task. +/// This isn't free (context lookup) - don't call it in a tight loop. + boost::optional<CancelMonitor> getCancelledMonitor(const lsRequestId& id, const Context& ctx = Context::current()){ + for (const CancelState* state = ctx.get(g_stateKey); state != nullptr; + state = state->parent) + { + if (id != state->id)continue; + const std::shared_ptr<std::atomic<int> > cancelled = state->cancelled; + std::function<int()> temp = [=]{ + return cancelled->load(); + }; + return std::move(temp); + } + + return {}; + } +} // namespace lsp + +using namespace lsp; +class PendingRequestInfo +{ + using RequestCallBack = std::function< bool(std::unique_ptr<LspMessage>) >; +public: + PendingRequestInfo(const std::string& md, + const RequestCallBack& callback); + PendingRequestInfo(const std::string& md); + PendingRequestInfo() {} + std::string method; + RequestCallBack futureInfo; +}; + +PendingRequestInfo::PendingRequestInfo(const std::string& _md, + const RequestCallBack& callback) : method(_md), + futureInfo(callback) +{ +} + +PendingRequestInfo::PendingRequestInfo(const std::string& md) : method(md) +{ +} +struct RemoteEndPoint::Data +{ + explicit Data(lsp::Log& _log , RemoteEndPoint* owner) + : m_id(0), next_request_cookie(0), message_producer(new StreamMessageProducer(*owner)), log(_log) + { + + } + ~Data() + { + delete message_producer; + } + std::atomic<unsigned> m_id; + boost::threadpool::pool tp; + // Method calls may be cancelled by ID, so keep track of their state. + // This needs a mutex: handlers may finish on a different thread, and that's + // when we clean up entries in the map. + mutable std::mutex request_cancelers_mutex; + + std::map< lsRequestId, std::pair<Canceler, /*Cookie*/ unsigned> > requestCancelers; + + std::atomic<unsigned> next_request_cookie; // To disambiguate reused IDs, see below. + void onCancel(Notify_Cancellation::notify* notify) { + std::lock_guard<std::mutex> Lock(request_cancelers_mutex); + const auto it = requestCancelers.find(notify->params.id); + if (it != requestCancelers.end()) + it->second.first(); // Invoke the canceler. + } + + // We run cancelable requests in a context that does two things: + // - allows cancellation using requestCancelers[ID] + // - cleans up the entry in requestCancelers when it's no longer needed + // If a client reuses an ID, the last wins and the first cannot be canceled. + Context cancelableRequestContext(lsRequestId id) { + auto task = cancelableTask(id, + /*Reason=*/static_cast<int>(lsErrorCodes::RequestCancelled)); + unsigned cookie; + { + std::lock_guard<std::mutex> Lock(request_cancelers_mutex); + cookie = next_request_cookie.fetch_add(1, std::memory_order_relaxed); + requestCancelers[id] = { std::move(task.second), cookie }; + } + // When the request ends, we can clean up the entry we just added. + // The cookie lets us check that it hasn't been overwritten due to ID + // reuse. + return task.first.derive(lsp::make_scope_exit([this, id, cookie] { + std::lock_guard<std::mutex> lock(request_cancelers_mutex); + const auto& it = requestCancelers.find(id); + if (it != requestCancelers.end() && it->second.second == cookie) + requestCancelers.erase(it); + })); + } + + std::map <lsRequestId, std::shared_ptr<PendingRequestInfo>> _client_request_futures; + StreamMessageProducer* message_producer; + std::atomic<bool> quit{}; + lsp::Log& log; + std::shared_ptr<lsp::istream> input; + std::shared_ptr<lsp::ostream> output; + + void pendingRequest(RequestInMessage& info, GenericResponseHandler&& handler) + { + auto id = m_id.fetch_add(1, std::memory_order_relaxed); + info.id.set(id); + std::lock_guard<std::mutex> lock(m_requsetInfo); + _client_request_futures[info.id] = std::make_shared<PendingRequestInfo>(info.method, handler); + + } + const std::shared_ptr<const PendingRequestInfo> getRequestInfo(const lsRequestId& _id) + { + std::lock_guard<std::mutex> lock(m_requsetInfo); + auto findIt = _client_request_futures.find(_id); + if (findIt != _client_request_futures.end()) + { + return findIt->second; + } + return nullptr; + } + + std::mutex m_requsetInfo; + void removeRequestInfo(const lsRequestId& _id) + { + std::lock_guard<std::mutex> lock(m_requsetInfo); + auto findIt = _client_request_futures.find(_id); + if (findIt != _client_request_futures.end()) + { + _client_request_futures.erase(findIt); + } + } + void clear() + { + { + std::lock_guard<std::mutex> lock(m_requsetInfo); + _client_request_futures.clear(); + + } + tp.clear(); + quit.store(true, std::memory_order_relaxed); + } +}; + +namespace +{ +void WriterMsg(std::shared_ptr<lsp::ostream>& output, LspMessage& msg) +{ + const auto& s = msg.ToJson(); + const auto value = + std::string("Content-Length: ") + std::to_string(s.size()) + "\r\n\r\n" + s; + output->write(value); + output->flush(); +} + +bool isResponseMessage(JsonReader& visitor) +{ + + if (!visitor.HasMember("id")) + { + return false; + } + + if (!visitor.HasMember("result") && !visitor.HasMember("error")) + { + return false; + } + + return true; +} + +bool isRequestMessage(JsonReader& visitor) +{ + if (!visitor.HasMember("method")) + { + return false; + } + if (!visitor["method"]->IsString()) + { + return false; + } + if (!visitor.HasMember("id")) + { + return false; + } + return true; +} +bool isNotificationMessage(JsonReader& visitor) +{ + if (!visitor.HasMember("method")) + { + return false; + } + if (!visitor["method"]->IsString()) + { + return false; + } + if (visitor.HasMember("id")) + { + return false; + } + return true; +} +} + +CancelMonitor RemoteEndPoint::getCancelMonitor(const lsRequestId& id) +{ + auto monitor = getCancelledMonitor(id); + if(monitor.has_value()) + { + return monitor.value(); + } + return [] { + return 0; + }; + +} + +RemoteEndPoint::RemoteEndPoint( + const std::shared_ptr < MessageJsonHandler >& json_handler,const std::shared_ptr < Endpoint>& localEndPoint, lsp::Log& _log, uint8_t max_workers): + d_ptr(new Data(_log,this)),jsonHandler(json_handler), local_endpoint(localEndPoint) +{ + jsonHandler->method2notification[Notify_Cancellation::notify::kMethodInfo] = [](Reader& visitor) + { + return Notify_Cancellation::notify::ReflectReader(visitor); + }; + + d_ptr->quit.store(false, std::memory_order_relaxed); + d_ptr->tp.size_controller().resize(max_workers); +} + +RemoteEndPoint::~RemoteEndPoint() +{ + delete d_ptr; + d_ptr->quit.store(true, std::memory_order_relaxed); +} + +bool RemoteEndPoint::dispatch(const std::string& content) +{ + rapidjson::Document document; + document.Parse(content.c_str(), content.length()); + if (document.HasParseError()) + { + std::string info ="lsp msg format error:"; + rapidjson::GetParseErrorFunc GetParseError = rapidjson::GetParseError_En; // or whatever + info+= GetParseError(document.GetParseError()); + info += "\n"; + info += "ErrorContext offset:\n"; + info += content.substr(document.GetErrorOffset()); + d_ptr->log.log(Log::Level::SEVERE, info); + + return false; + } + + JsonReader visitor{ &document }; + if (!visitor.HasMember("jsonrpc") || + std::string(visitor["jsonrpc"]->GetString()) != "2.0") + { + std::string reason; + reason = "Reason:Bad or missing jsonrpc version\n"; + reason += "content:\n" + content; + d_ptr->log.log(Log::Level::SEVERE, reason); + return false; + + } + LspMessage::Kind _kind = LspMessage::NOTIFICATION_MESSAGE; + try { + if (isRequestMessage(visitor)) + { + _kind = LspMessage::REQUEST_MESSAGE; + auto msg = jsonHandler->parseRequstMessage(visitor["method"]->GetString(), visitor); + if (msg) { + mainLoop(std::move(msg)); + } + else { + std::string info = "Unknown support request message when consumer message:\n"; + info += content; + d_ptr->log.log(Log::Level::WARNING, info); + return false; + } + } + else if (isResponseMessage(visitor)) + { + _kind = LspMessage::RESPONCE_MESSAGE; + lsRequestId id; + ReflectMember(visitor, "id", id); + + auto msgInfo = d_ptr->getRequestInfo(id); + if (!msgInfo) + { + std::pair<std::string, std::unique_ptr<LspMessage>> result; + auto b = jsonHandler->resovleResponseMessage(visitor, result); + if (b) + { + result.second->SetMethodType(result.first.c_str()); + mainLoop(std::move(result.second)); + } + else + { + std::string info = "Unknown response message :\n"; + info += content; + d_ptr->log.log(Log::Level::INFO, info); + } + } + else + { + + auto msg = jsonHandler->parseResponseMessage(msgInfo->method, visitor); + if (msg) { + mainLoop(std::move(msg)); + } + else + { + std::string info = "Unknown response message :\n"; + info += content; + d_ptr->log.log(Log::Level::SEVERE, info); + return false; + } + + } + } + else if (isNotificationMessage(visitor)) + { + auto msg = jsonHandler->parseNotificationMessage(visitor["method"]->GetString(), visitor); + if (!msg) + { + std::string info = "Unknown notification message :\n"; + info += content; + d_ptr->log.log(Log::Level::SEVERE, info); + return false; + } + mainLoop(std::move(msg)); + } + else + { + std::string info = "Unknown lsp message when consumer message:\n"; + info += content; + d_ptr->log.log(Log::Level::WARNING, info); + return false; + } + } + catch (std::exception& e) + { + + std::string info = "Exception when process "; + if(_kind==LspMessage::REQUEST_MESSAGE) + { + info += "request"; + } + if (_kind == LspMessage::RESPONCE_MESSAGE) + { + info += "response"; + } + else + { + info += "notification"; + } + info += " message:\n"; + info += e.what(); + std::string reason = "Reason:" + info + "\n"; + reason += "content:\n" + content; + d_ptr->log.log(Log::Level::SEVERE, reason); + return false; + } + return true; +} + + + +void RemoteEndPoint::internalSendRequest( RequestInMessage& info, GenericResponseHandler handler) +{ + std::lock_guard<std::mutex> lock(m_sendMutex); + if (!d_ptr->output || d_ptr->output->bad()) + { + std::string desc = "Output isn't good any more:\n"; + d_ptr->log.log(Log::Level::INFO, desc); + return ; + } + d_ptr->pendingRequest(info, std::move(handler)); + WriterMsg(d_ptr->output, info); +} + + +std::unique_ptr<LspMessage> RemoteEndPoint::internalWaitResponse(RequestInMessage& request, unsigned time_out) +{ + auto eventFuture = std::make_shared< Condition< LspMessage > >(); + internalSendRequest(request, [=](std::unique_ptr<LspMessage> data) + { + eventFuture->notify(std::move(data)); + return true; + }); + return eventFuture->wait(time_out); +} + +void RemoteEndPoint::mainLoop(std::unique_ptr<LspMessage>msg) +{ + if(d_ptr->quit.load(std::memory_order_relaxed)) + { + return; + } + const auto _kind = msg->GetKid(); + if (_kind == LspMessage::REQUEST_MESSAGE) + { + auto req = static_cast<RequestInMessage*>(msg.get()); + // Calls can be canceled by the client. Add cancellation context. + WithContext WithCancel(d_ptr->cancelableRequestContext(req->id)); + local_endpoint->onRequest(std::move(msg)); + } + + else if (_kind == LspMessage::RESPONCE_MESSAGE) + { + auto response = static_cast<ResponseInMessage*>(msg.get()); + auto msgInfo = d_ptr->getRequestInfo(response->id); + if (!msgInfo) + { + const auto _method_desc = msg->GetMethodType(); + local_endpoint->onResponse(_method_desc, std::move(msg)); + } + else + { + bool needLocal = true; + if (msgInfo->futureInfo) + { + if (msgInfo->futureInfo(std::move(msg))) + { + needLocal = false; + } + } + if (needLocal) + { + local_endpoint->onResponse(msgInfo->method, std::move(msg)); + } + d_ptr->removeRequestInfo(response->id); + } + } + else if (_kind == LspMessage::NOTIFICATION_MESSAGE) + { + if (strcmp(Notify_Cancellation::notify::kMethodInfo, msg->GetMethodType())==0) + { + d_ptr->onCancel(static_cast<Notify_Cancellation::notify*>(msg.get())); + } + else + { + local_endpoint->notify(std::move(msg)); + } + + } + else + { + std::string info = "Unknown lsp message when process message in mainLoop:\n"; + d_ptr->log.log(Log::Level::WARNING, info); + } +} + +void RemoteEndPoint::handle(std::vector<MessageIssue>&& issue) +{ + for(auto& it : issue) + { + d_ptr->log.log(it.code, it.text); + } +} + +void RemoteEndPoint::handle(MessageIssue&& issue) +{ + d_ptr->log.log(issue.code, issue.text); +} + + +void RemoteEndPoint::startProcessingMessages(std::shared_ptr<lsp::istream> r, + std::shared_ptr<lsp::ostream> w) +{ + d_ptr->quit.store(false, std::memory_order_relaxed); + d_ptr->input = r; + d_ptr->output = w; + d_ptr->message_producer->bind(r); + message_producer_thread_ = std::make_shared<std::thread>([&]() + { + d_ptr->message_producer->listen([&](std::string&& content){ + const auto temp = std::make_shared<std::string>(std::move(content)); + d_ptr->tp.schedule([this, temp]{ +#ifdef USEGC + GCThreadContext gcContext; +#endif + + dispatch(*temp); + }); + }); + }); +} + +void RemoteEndPoint::Stop() +{ + if(message_producer_thread_ && message_producer_thread_->joinable()) + { + message_producer_thread_->detach(); + } + d_ptr->clear(); + +} + +void RemoteEndPoint::sendMsg( LspMessage& msg) +{ + + std::lock_guard<std::mutex> lock(m_sendMutex); + if (!d_ptr->output || d_ptr->output->bad()) + { + std::string info = "Output isn't good any more:\n"; + d_ptr->log.log(Log::Level::INFO, info); + return; + } + WriterMsg(d_ptr->output, msg); + +} diff --git a/Build/source/utils/asymptote/LspCpp/LibLsp/JsonRpc/RemoteEndPoint.h b/Build/source/utils/asymptote/LspCpp/LibLsp/JsonRpc/RemoteEndPoint.h new file mode 100644 index 00000000000..3ae6b567a5c --- /dev/null +++ b/Build/source/utils/asymptote/LspCpp/LibLsp/JsonRpc/RemoteEndPoint.h @@ -0,0 +1,340 @@ +#pragma once +#include "LibLsp/lsp/lsp_diagnostic.h" +#include "LibLsp/JsonRpc/Cancellation.h" +#include "LibLsp/JsonRpc/lsResponseMessage.h" +#include "LibLsp/JsonRpc/RequestInMessage.h" +#include "LibLsp/JsonRpc/NotificationInMessage.h" +#include "traits.h" +#include <future> +#include <string> +#include "threaded_queue.h" +#include <unordered_map> +#include "MessageIssue.h" +#include "LibLsp/JsonRpc/MessageJsonHandler.h" +#include "Endpoint.h" + + +class MessageJsonHandler; +class Endpoint; +struct LspMessage; +class RemoteEndPoint; +namespace lsp { + class ostream; + class istream; + + //////////////////////////////////////////////////////////////////////////////// + // ResponseOrError<T> + //////////////////////////////////////////////////////////////////////////////// + + // ResponseOrError holds either the response to a request or an error + // message. + template <typename T> + struct ResponseOrError { + using Request = T; + ResponseOrError(); + ResponseOrError(const T& response); + ResponseOrError(T&& response); + ResponseOrError(const Rsp_Error& error); + ResponseOrError(Rsp_Error&& error); + ResponseOrError(const ResponseOrError& other); + ResponseOrError(ResponseOrError&& other) noexcept; + + ResponseOrError& operator=(const ResponseOrError& other); + ResponseOrError& operator=(ResponseOrError&& other) noexcept; + bool IsError() const { return is_error; } + std::string ToJson() + { + if (is_error) return error.ToJson(); + return response.ToJson(); + } + T response; + Rsp_Error error; // empty represents success. + bool is_error; + }; + + template <typename T> + ResponseOrError<T>::ResponseOrError(): is_error(false) + { + } + + template <typename T> + ResponseOrError<T>::ResponseOrError(const T& resp) : response(resp), is_error(false) {} + template <typename T> + ResponseOrError<T>::ResponseOrError(T&& resp) : response(std::move(resp)), is_error(false) {} + template <typename T> + ResponseOrError<T>::ResponseOrError(const Rsp_Error& err) : error(err), is_error(true) {} + template <typename T> + ResponseOrError<T>::ResponseOrError(Rsp_Error&& err) : error(std::move(err)), is_error(true) {} + template <typename T> + ResponseOrError<T>::ResponseOrError(const ResponseOrError& other) + : response(other.response), error(other.error), is_error(other.is_error) {} + template <typename T> + ResponseOrError<T>::ResponseOrError(ResponseOrError&& other) noexcept + : response(std::move(other.response)), error(std::move(other.error)), is_error(other.is_error) {} + template <typename T> + ResponseOrError<T>& ResponseOrError<T>::operator=( + const ResponseOrError& other) { + response = other.response; + error = other.error; + is_error = other.is_error; + return *this; + } + template <typename T> + ResponseOrError<T>& ResponseOrError<T>::operator=(ResponseOrError&& other) noexcept + { + response = std::move(other.response); + error = std::move(other.error); + is_error = other.is_error; + return *this; + } + +} + + +class RemoteEndPoint :MessageIssueHandler +{ + + template <typename F, int N> + using ParamType = lsp::traits::ParameterType<F, N>; + + template <typename T> + using IsRequest = lsp::traits::EnableIfIsType<RequestInMessage, T>; + + template <typename T> + using IsResponse = lsp::traits::EnableIfIsType<ResponseInMessage, T>; + + template <typename T> + using IsNotify = lsp::traits::EnableIfIsType<NotificationInMessage, T>; + + + template <typename F, typename ReturnType> + using IsRequestHandler = lsp::traits::EnableIf<lsp::traits::CompatibleWith< + F, + std::function<ReturnType(const RequestInMessage&)>>:: + value>; + + template <typename F, typename ReturnType> + using IsRequestHandlerWithMonitor = lsp::traits::EnableIf<lsp::traits::CompatibleWith< + F, + std::function<ReturnType(const RequestInMessage&,const CancelMonitor&)>>:: + value>; + +public: + + + RemoteEndPoint(const std::shared_ptr <MessageJsonHandler>& json_handler, + const std::shared_ptr < Endpoint >& localEndPoint, + lsp::Log& _log, uint8_t max_workers = 2); + + ~RemoteEndPoint() override; + template <typename F, typename RequestType = ParamType<F, 0>, typename ResponseType = typename RequestType::Response> + IsRequestHandler< F, lsp::ResponseOrError<ResponseType> > registerHandler(F&& handler) + { + ProcessRequestJsonHandler(handler); + local_endpoint->registerRequestHandler(RequestType::kMethodInfo, [=](std::unique_ptr<LspMessage> msg) { + auto req = reinterpret_cast<const RequestType*>(msg.get()); + lsp::ResponseOrError<ResponseType> res(handler(*req)); + if (res.is_error) { + res.error.id = req->id; + send(res.error); + } + else + { + res.response.id = req->id; + send(res.response); + } + return true; + }); + } + template <typename F, typename RequestType = ParamType<F, 0>, typename ResponseType = typename RequestType::Response> + IsRequestHandlerWithMonitor< F, lsp::ResponseOrError<ResponseType> > registerHandler(F&& handler) { + ProcessRequestJsonHandler(handler); + local_endpoint->registerRequestHandler(RequestType::kMethodInfo, [=](std::unique_ptr<LspMessage> msg) { + auto req = static_cast<const RequestType*>(msg.get()); + lsp::ResponseOrError<ResponseType> res(handler(*req , getCancelMonitor(req->id))); + if (res.is_error) { + res.error.id = req->id; + send(res.error); + } + else + { + res.response.id = req->id; + send(res.response); + } + return true; + }); + } + using RequestErrorCallback = std::function<void(const Rsp_Error&)>; + + template <typename T, typename F, typename ResponseType = ParamType<F, 0> > + void send(T& request, F&& handler, RequestErrorCallback onError) + { + ProcessRequestJsonHandler(handler); + auto cb = [=](std::unique_ptr<LspMessage> msg) { + if (!msg) + return true; + const auto result = msg.get(); + + if (static_cast<ResponseInMessage*>(result)->IsErrorType()) { + const auto rsp_error = static_cast<const Rsp_Error*>(result); + onError(*rsp_error); + } + else { + handler(*static_cast<ResponseType*>(result)); + } + + return true; + }; + internalSendRequest(request, cb); + } + + + template <typename F, typename NotifyType = ParamType<F, 0> > + IsNotify<NotifyType> registerHandler(F&& handler) { + { + std::lock_guard<std::mutex> lock(m_sendMutex); + if (!jsonHandler->GetNotificationJsonHandler(NotifyType::kMethodInfo)) + { + jsonHandler->SetNotificationJsonHandler(NotifyType::kMethodInfo, + [](Reader& visitor) + { + return NotifyType::ReflectReader(visitor); + }); + } + } + local_endpoint->registerNotifyHandler(NotifyType::kMethodInfo, [=](std::unique_ptr<LspMessage> msg) { + handler(*static_cast<NotifyType*>(msg.get())); + return true; + }); + } + + template <typename T, typename = IsRequest<T>> + std::future< lsp::ResponseOrError<typename T::Response> > send(T& request) { + + ProcessResponseJsonHandler(request); + using Response = typename T::Response; + auto promise = std::make_shared< std::promise<lsp::ResponseOrError<Response>>>(); + auto cb = [=](std::unique_ptr<LspMessage> msg) { + if (!msg) + return true; + auto result = msg.get(); + + if (reinterpret_cast<ResponseInMessage*>(result)->IsErrorType()) + { + Rsp_Error* rsp_error = static_cast<Rsp_Error*>(result); + Rsp_Error temp; + std::swap(temp, *rsp_error); + promise->set_value(std::move(lsp::ResponseOrError<Response>(std::move(temp)))); + } + else + { + Response temp; + std::swap(temp, *static_cast<Response*>(result)); + promise->set_value(std::move(lsp::ResponseOrError<Response>(std::move(temp)))); + } + return true; + }; + internalSendRequest(request, cb); + return promise->get_future(); + } + + template <typename T, typename = IsRequest<T>> + std::unique_ptr<lsp::ResponseOrError<typename T::Response>> waitResponse(T& request, const unsigned time_out = 0) + { + auto future_rsp = send(request); + if (time_out == 0) + { + future_rsp.wait(); + } + else + { + auto state = future_rsp.wait_for(std::chrono::milliseconds(time_out)); + if (std::future_status::timeout == state) + { + return {}; + } + } + + using Response = typename T::Response; + return std::make_unique<lsp::ResponseOrError<Response>>(std::move(future_rsp.get())); + } + + void send(NotificationInMessage& msg) + { + sendMsg(msg); + } + + void send(ResponseInMessage& msg) + { + sendMsg(msg); + } + + void sendNotification(NotificationInMessage& msg) + { + send(msg); + } + void sendResponse(ResponseInMessage& msg) + { + send(msg); + } + void startProcessingMessages(std::shared_ptr<lsp::istream> r, + std::shared_ptr<lsp::ostream> w); + + bool IsWorking() const + { + if (message_producer_thread_) + return true; + return false; + } + void Stop(); + + std::unique_ptr<LspMessage> internalWaitResponse(RequestInMessage&, unsigned time_out = 0); + + void internalSendRequest(RequestInMessage&, GenericResponseHandler); + + void handle(std::vector<MessageIssue>&&) override; + void handle(MessageIssue&&) override; +private: + CancelMonitor getCancelMonitor(const lsRequestId&); + void sendMsg(LspMessage& msg); + void mainLoop(std::unique_ptr<LspMessage>); + bool dispatch(const std::string&); + template <typename F, typename RequestType = ParamType<F, 0>> + IsRequest<RequestType> ProcessRequestJsonHandler(const F& handler) { + std::lock_guard<std::mutex> lock(m_sendMutex); + if (!jsonHandler->GetRequestJsonHandler(RequestType::kMethodInfo)) + { + jsonHandler->SetRequestJsonHandler(RequestType::kMethodInfo, + [](Reader& visitor) + { + return RequestType::ReflectReader(visitor); + }); + } + } + template <typename T, typename = IsRequest<T>> + void ProcessResponseJsonHandler(T& request) + { + using Response = typename T::Response; + std::lock_guard<std::mutex> lock(m_sendMutex); + if (!jsonHandler->GetResponseJsonHandler(T::kMethodInfo)) + { + jsonHandler->SetResponseJsonHandler(T::kMethodInfo, [](Reader& visitor) + { + if (visitor.HasMember("error")) + return Rsp_Error::ReflectReader(visitor); + return Response::ReflectReader(visitor); + }); + } + } + + struct Data; + + Data* d_ptr; + + std::shared_ptr < MessageJsonHandler> jsonHandler; + std::mutex m_sendMutex; + + std::shared_ptr < Endpoint > local_endpoint; +public: + std::shared_ptr < std::thread > message_producer_thread_; +}; diff --git a/Build/source/utils/asymptote/LspCpp/LibLsp/JsonRpc/RequestInMessage.h b/Build/source/utils/asymptote/LspCpp/LibLsp/JsonRpc/RequestInMessage.h new file mode 100644 index 00000000000..163d038a2ee --- /dev/null +++ b/Build/source/utils/asymptote/LspCpp/LibLsp/JsonRpc/RequestInMessage.h @@ -0,0 +1,70 @@ +#pragma once + + +#include "serializer.h" +#include <atomic> +#include <mutex> +#include "lsRequestId.h" +#include "LibLsp/JsonRpc/message.h" +#include "LibLsp/lsp/method_type.h" +#include "lsResponseMessage.h" + +struct RequestInMessage : public LspMessage { + // number or string, actually no null + lsRequestId id; + std::string method; + Kind GetKid() override + { + return REQUEST_MESSAGE; + } + +}; + + + +template <class T, class TDerived > +struct lsRequest : public RequestInMessage +{ + lsRequest(MethodType _method) + { + method = _method; + } + MethodType GetMethodType() const override { return method.c_str(); } + void SetMethodType(MethodType _method) override + { + method = _method; + } \ + void ReflectWriter(Writer& writer) override { + Reflect(writer, static_cast<TDerived&>(*this)); + } + + static std::unique_ptr<LspMessage> ReflectReader(Reader& visitor) { + + TDerived* temp = new TDerived(); + std::unique_ptr<TDerived> message = std::unique_ptr<TDerived>(temp); + // Reflect may throw and *message will be partially deserialized. + Reflect(visitor, static_cast<TDerived&>(*temp)); + return message; + } + void swap(lsRequest& arg) noexcept + { + id.swap(arg.id); + method.swap(method); + std::swap(params, arg.params); + } + T params; +}; + + +#define DEFINE_REQUEST_RESPONSE_TYPE(MSG,request_param,response_result,methodInfo)\ +namespace MSG {\ + struct response :public ResponseMessage< response_result, response> {}; \ + struct request : public lsRequest< request_param , request >{\ + static constexpr MethodType kMethodInfo = methodInfo;\ + request():lsRequest(kMethodInfo){} \ + using Response = response;\ + };\ +};\ +MAKE_REFLECT_STRUCT(MSG::request, jsonrpc, id, method, params);\ +MAKE_REFLECT_STRUCT(MSG::response, jsonrpc, id, result); + diff --git a/Build/source/utils/asymptote/LspCpp/LibLsp/JsonRpc/ScopeExit.h b/Build/source/utils/asymptote/LspCpp/LibLsp/JsonRpc/ScopeExit.h new file mode 100644 index 00000000000..024b700b4a4 --- /dev/null +++ b/Build/source/utils/asymptote/LspCpp/LibLsp/JsonRpc/ScopeExit.h @@ -0,0 +1,59 @@ +//===- llvm/ADT/ScopeExit.h - Execute code at scope exit --------*- C++ -*-===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +// +// This file defines the make_scope_exit function, which executes user-defined +// cleanup logic at scope exit. +// +//===----------------------------------------------------------------------===// +#pragma once +#include <type_traits> +#include <utility> + +namespace lsp { +namespace detail { + +template <typename Callable> class scope_exit { + Callable ExitFunction; + bool Engaged = true; // False once moved-from or release()d. + +public: + template <typename Fp> + explicit scope_exit(Fp &&F) : ExitFunction(std::forward<Fp>(F)) {} + + scope_exit(scope_exit &&Rhs) + : ExitFunction(std::move(Rhs.ExitFunction)), Engaged(Rhs.Engaged) { + Rhs.release(); + } + scope_exit(const scope_exit &) = delete; + scope_exit &operator=(scope_exit &&) = delete; + scope_exit &operator=(const scope_exit &) = delete; + + void release() { Engaged = false; } + + ~scope_exit() { + if (Engaged) + ExitFunction(); + } +}; + +} // end namespace detail + +// Keeps the callable object that is passed in, and execute it at the +// destruction of the returned object (usually at the scope exit where the +// returned object is kept). +// +// Interface is specified by p0052r2. +template <typename Callable> + detail::scope_exit<typename std::decay<Callable>::type> +make_scope_exit(Callable &&F) { + return detail::scope_exit<typename std::decay<Callable>::type>( + std::forward<Callable>(F)); +} + +} // end namespace lsp + diff --git a/Build/source/utils/asymptote/LspCpp/LibLsp/JsonRpc/StreamMessageProducer.cpp b/Build/source/utils/asymptote/LspCpp/LibLsp/JsonRpc/StreamMessageProducer.cpp new file mode 100644 index 00000000000..c9df4079807 --- /dev/null +++ b/Build/source/utils/asymptote/LspCpp/LibLsp/JsonRpc/StreamMessageProducer.cpp @@ -0,0 +1,191 @@ + +#include "StreamMessageProducer.h" +#include <cassert> + +#include "stream.h" + + +bool StartsWith(std::string value, std::string start); +bool StartsWith(std::string value, std::string start) { + if (start.size() > value.size()) + return false; + return std::equal(start.begin(), start.end(), value.begin()); +} + +using namespace std; +namespace +{ + string JSONRPC_VERSION = "2.0"; + string CONTENT_LENGTH_HEADER = "Content-Length"; + string CONTENT_TYPE_HEADER = "Content-Type"; + string JSON_MIME_TYPE = "application/json"; + string CRLF = "\r\n"; + +} + + void StreamMessageProducer::parseHeader(std::string& line, StreamMessageProducer::Headers& headers) + { + int sepIndex = line.find(':'); + if (sepIndex >= 0) { + auto key = line.substr(0, sepIndex); + if(key == CONTENT_LENGTH_HEADER) + { + headers.contentLength = atoi(line.substr(sepIndex + 1).data()); + } + else if(key == CONTENT_TYPE_HEADER) + { + int charsetIndex = line.find("charset="); + if (charsetIndex >= 0) + headers.charset = line.substr(charsetIndex + 8); + } + } + } + + +void StreamMessageProducer::listen(MessageConsumer callBack) +{ + if(!input) + return; + + keepRunning = true; + bool newLine = false; + Headers headers; + string headerBuilder ; + string debugBuilder ; + // Read the content length. It is terminated by the "\r\n" sequence. + while (keepRunning) + { + if(input->bad()) + { + std::string info = "Input stream is bad."; + auto what = input->what(); + if (what.size()) + { + info += "Reason:"; + info += input->what(); + } + MessageIssue issue(info, lsp::Log::Level::SEVERE); + issueHandler.handle(std::move(issue)); + return; + } + if(input->fail()) + { + std::string info = "Input fail."; + auto what = input->what(); + if(what.size()) + { + info += "Reason:"; + info += input->what(); + } + MessageIssue issue(info, lsp::Log::Level::WARNING); + issueHandler.handle(std::move(issue)); + if(input->need_to_clear_the_state()) + input->clear(); + else + { + return; + } + } + int c = input->get(); + if (c == EOF) { + // End of input stream has been reached + keepRunning = false; + } + else + { + + debugBuilder.push_back((char)c); + if (c == '\n') + { + if (newLine) { + // Two consecutive newlines have been read, which signals the start of the message content + if (headers.contentLength <= 0) + { + string info = "Unexpected token:" + debugBuilder; + info = +" (expected Content-Length: sequence);"; + MessageIssue issue(info, lsp::Log::Level::WARNING); + issueHandler.handle(std::move(issue)); + } + else { + bool result = handleMessage(headers,callBack); + if (!result) + keepRunning = false; + newLine = false; + } + headers.clear(); + debugBuilder.clear(); + } + else if (!headerBuilder.empty()) { + // A single newline ends a header line + parseHeader(headerBuilder, headers); + headerBuilder.clear(); + } + newLine = true; + } + else if (c != '\r') { + // Add the input to the current header line + + headerBuilder.push_back((char)c); + newLine = false; + } + } + } + +} + +void StreamMessageProducer::bind(std::shared_ptr<lsp::istream>_in) +{ + input = _in; +} + +bool StreamMessageProducer::handleMessage(Headers& headers ,MessageConsumer callBack) +{ + // Read content. + auto content_length = headers.contentLength; + std::string content(content_length,0); + auto data = &content[0]; + input->read(data, content_length); + if (input->bad()) + { + std::string info = "Input stream is bad."; + auto what = input->what(); + if (!what.empty()) + { + info += "Reason:"; + info += input->what(); + } + MessageIssue issue(info, lsp::Log::Level::SEVERE); + issueHandler.handle(std::move(issue)); + return false; + } + + if (input->eof()) + { + MessageIssue issue("No more input when reading content body", lsp::Log::Level::INFO); + issueHandler.handle(std::move(issue)); + return false; + } + if (input->fail()) + { + std::string info = "Input fail."; + auto what = input->what(); + if (!what.empty()) + { + info += "Reason:"; + info += input->what(); + } + MessageIssue issue(info, lsp::Log::Level::WARNING); + issueHandler.handle(std::move(issue)); + if (input->need_to_clear_the_state()) + input->clear(); + else + { + return false; + } + } + + callBack(std::move(content)); + + return true; +} + diff --git a/Build/source/utils/asymptote/LspCpp/LibLsp/JsonRpc/StreamMessageProducer.h b/Build/source/utils/asymptote/LspCpp/LibLsp/JsonRpc/StreamMessageProducer.h new file mode 100644 index 00000000000..439a9f1b0eb --- /dev/null +++ b/Build/source/utils/asymptote/LspCpp/LibLsp/JsonRpc/StreamMessageProducer.h @@ -0,0 +1,48 @@ +#pragma once +#include <string> +#include <functional> +#include "MessageProducer.h" +#include <iostream> +#include <memory> +#include "MessageIssue.h" + +namespace lsp { + class istream; +} + +class StreamMessageProducer : public MessageProducer +{ +public: + struct Headers + { + int contentLength = -1; + std::string charset; + void clear() + { + contentLength = -1; + charset.clear(); + } + }; + bool handleMessage(Headers& headers, MessageConsumer callBack); + StreamMessageProducer( + MessageIssueHandler& message_issue_handler, std::shared_ptr < lsp::istream> _input) + : issueHandler(message_issue_handler), + input(_input) + { + } + StreamMessageProducer( + MessageIssueHandler& message_issue_handler) + : issueHandler(message_issue_handler) + { + } + + bool keepRunning = false; + void listen(MessageConsumer) override; + void bind(std::shared_ptr < lsp::istream>); + void parseHeader(std::string& line, Headers& headers); +private: + MessageIssueHandler& issueHandler; + std::shared_ptr < lsp::istream> input; + + +}; diff --git a/Build/source/utils/asymptote/LspCpp/LibLsp/JsonRpc/TcpServer.cpp b/Build/source/utils/asymptote/LspCpp/LibLsp/JsonRpc/TcpServer.cpp new file mode 100644 index 00000000000..91883564737 --- /dev/null +++ b/Build/source/utils/asymptote/LspCpp/LibLsp/JsonRpc/TcpServer.cpp @@ -0,0 +1,299 @@ +// +// server.cpp + +#include "TcpServer.h" +#include <signal.h> +#include <utility> +#include <boost/bind/bind.hpp> + +#include "MessageIssue.h" +#include "stream.h" + + +namespace lsp { + struct tcp_connect_session; + + + class tcp_stream_wrapper :public istream, public ostream + { + public: + tcp_stream_wrapper(tcp_connect_session& _w); + + tcp_connect_session& session; + std::atomic<bool> quit{}; + std::shared_ptr < MultiQueueWaiter> request_waiter; + ThreadedQueue< char > on_request; + std::string error_message; + + + bool fail() override + { + return bad(); + } + + + + bool eof() override + { + return bad(); + } + bool good() override + { + return !bad(); + } + tcp_stream_wrapper& read(char* str, std::streamsize count) + override + { + auto some = on_request.TryDequeueSome(static_cast<size_t>( count )); + for (size_t i = 0; i < some.size(); ++i) + { + str[i] = some[i]; + } + for (std::streamsize i = 0; i < count; ++i) + { + str[i] = static_cast<char>(get()); + } + + return *this; + } + int get() override + { + return on_request.Dequeue(); + } + + bool bad() override; + + tcp_stream_wrapper& write(const std::string& c) override; + + tcp_stream_wrapper& write(std::streamsize _s) override; + + tcp_stream_wrapper& flush() override + { + return *this; + } + void reset_state() + { + return; + } + + void clear() override + { + + } + + std::string what() override; + bool need_to_clear_the_state() override + { + return false; + } + }; + struct tcp_connect_session:std::enable_shared_from_this<tcp_connect_session> + { + /// Buffer for incoming data. + std::array<unsigned char, 8192> buffer_; + boost::asio::ip::tcp::socket socket_; + /// Strand to ensure the connection's handlers are not called concurrently. + boost::asio::io_context::strand strand_; + std::shared_ptr<tcp_stream_wrapper> proxy_; + explicit tcp_connect_session(boost::asio::io_context& io_context, boost::asio::ip::tcp::socket&& _socket) + : socket_(std::move(_socket)), strand_(io_context), proxy_(new tcp_stream_wrapper(*this)) + { + do_read(); + } + void do_write(const std::string& data) + { + socket_.async_write_some(boost::asio::buffer(data.data(), data.size()), + boost::asio::bind_executor(strand_,[this](boost::system::error_code ec, std::size_t n) + { + if (!ec) + { + return; + } + proxy_->error_message = ec.message(); + + })); + } + void do_read() + { + socket_.async_read_some(boost::asio::buffer(buffer_), + boost::asio::bind_executor(strand_, + [this](boost::system::error_code ec, size_t bytes_transferred) + { + if (!ec) + { + std::vector<char> elements(buffer_.data(), buffer_.data() + bytes_transferred); + proxy_->on_request.EnqueueAll(std::move(elements), false); + do_read(); + return; + } + proxy_->error_message = ec.message(); + + })); + } + }; + + tcp_stream_wrapper::tcp_stream_wrapper(tcp_connect_session& _w): session(_w) + { + } + + bool tcp_stream_wrapper::bad() + { + return !session.socket_.is_open(); + } + + tcp_stream_wrapper& tcp_stream_wrapper::write(const std::string& c) + { + session.do_write(c); + return *this; + } + + tcp_stream_wrapper& tcp_stream_wrapper::write(std::streamsize _s) + { + session.do_write(std::to_string(_s)); + return *this; + } + + std::string tcp_stream_wrapper::what() + { + if (error_message.size()) + return error_message; + + if(! session.socket_.is_open()) + { + return "Socket is not open."; + } + return {}; + } + + struct TcpServer::Data + { + Data( + lsp::Log& log, uint32_t _max_workers) : + acceptor_(io_context_), _log(log) + { + } + + ~Data() + { + + } + /// The io_context used to perform asynchronous operations. + boost::asio::io_context io_context_; + + std::shared_ptr<boost::asio::io_service::work> work; + + std::shared_ptr<tcp_connect_session> _connect_session; + /// Acceptor used to listen for incoming connections. + boost::asio::ip::tcp::acceptor acceptor_; + + lsp::Log& _log; + + }; + + TcpServer::~TcpServer() + { + delete d_ptr; + } + + TcpServer::TcpServer(const std::string& address, const std::string& port, + std::shared_ptr < MessageJsonHandler> json_handler, + std::shared_ptr < Endpoint> localEndPoint, lsp::Log& log, uint32_t _max_workers) + : point(json_handler, localEndPoint, log, _max_workers),d_ptr(new Data( log, _max_workers)) + + { + + d_ptr->work = std::make_shared<boost::asio::io_service::work>(d_ptr->io_context_); + + // Open the acceptor with the option to reuse the address (i.e. SO_REUSEADDR). + boost::asio::ip::tcp::resolver resolver(d_ptr->io_context_); + boost::asio::ip::tcp::endpoint endpoint = + *resolver.resolve(address, port).begin(); + d_ptr->acceptor_.open(endpoint.protocol()); + d_ptr->acceptor_.set_option(boost::asio::ip::tcp::acceptor::reuse_address(true)); + try + { + d_ptr->acceptor_.bind(endpoint); + } + catch (boost::system::system_error & e) + { + std::string temp = "Socket Server bind failed."; + d_ptr->_log.log(lsp::Log::Level::INFO , temp + e.what()); + return; + } + d_ptr->acceptor_.listen(); + + do_accept(); + std::string desc = "Socket TcpServer " + address + " " + port + " start."; + d_ptr->_log.log(lsp::Log::Level::INFO, desc); + } + + void TcpServer::run() + { + // The io_context::run() call will block until all asynchronous operations + // have finished. While the TcpServer is running, there is always at least one + // asynchronous operation outstanding: the asynchronous accept call waiting + // for new incoming connections. + d_ptr->io_context_.run(); + + } + + void TcpServer::stop() + { + try + { + if(d_ptr->work) + d_ptr->work.reset(); + + do_stop(); + } + catch (...) + { + } + } + + void TcpServer::do_accept() + { + d_ptr->acceptor_.async_accept( + [this](boost::system::error_code ec, boost::asio::ip::tcp::socket socket) + { + // Check whether the TcpServer was stopped by a signal before this + // completion handler had a chance to run. + if (!d_ptr->acceptor_.is_open()) + { + return; + } + + if (!ec) + { + if(d_ptr->_connect_session) + { + if(d_ptr->_connect_session->socket_.is_open()) + { + std::string desc = "Disconnect previous client " + d_ptr->_connect_session->socket_.local_endpoint().address().to_string(); + d_ptr->_log.log(lsp::Log::Level::INFO, desc); + d_ptr->_connect_session->socket_.close(); + } + + point.Stop(); + } + auto local_point = socket.local_endpoint(); + + std::string desc = ("New client " + local_point.address().to_string() + " connect."); + d_ptr->_log.log(lsp::Log::Level::INFO, desc); + d_ptr->_connect_session = std::make_shared<tcp_connect_session>(d_ptr->io_context_,std::move(socket)); + + point.startProcessingMessages(d_ptr->_connect_session->proxy_, d_ptr->_connect_session->proxy_); + do_accept(); + } + }); + } + + void TcpServer::do_stop() + { + d_ptr->acceptor_.close(); + + point.Stop(); + + } + + } // namespace diff --git a/Build/source/utils/asymptote/LspCpp/LibLsp/JsonRpc/TcpServer.h b/Build/source/utils/asymptote/LspCpp/LibLsp/JsonRpc/TcpServer.h new file mode 100644 index 00000000000..e533acf0569 --- /dev/null +++ b/Build/source/utils/asymptote/LspCpp/LibLsp/JsonRpc/TcpServer.h @@ -0,0 +1,40 @@ +#pragma once + +#include <boost/asio.hpp> +#include <string> +#include "RemoteEndPoint.h" + +namespace lsp { + class Log; +} +namespace lsp +{ + /// The top-level class of the HTTP server. + class TcpServer + { + public: + TcpServer(const TcpServer&) = delete; + TcpServer& operator=(const TcpServer&) = delete; + ~TcpServer(); + /// Construct the server to listen on the specified TCP address and port, and + /// serve up files from the given directory. + explicit TcpServer(const std::string& address, const std::string& port, + std::shared_ptr < MessageJsonHandler> json_handler, + std::shared_ptr < Endpoint> localEndPoint, lsp::Log& ,uint32_t _max_workers = 2); + + /// Run the server's io_context loop. + void run(); + void stop(); + + RemoteEndPoint point; + private: + struct Data; + /// Perform an asynchronous accept operation. + void do_accept(); + + /// Wait for a request to stop the server. + void do_stop(); + Data* d_ptr = nullptr; + }; +} // namespace + diff --git a/Build/source/utils/asymptote/LspCpp/LibLsp/JsonRpc/WebSocketServer.cpp b/Build/source/utils/asymptote/LspCpp/LibLsp/JsonRpc/WebSocketServer.cpp new file mode 100644 index 00000000000..2cb83099c35 --- /dev/null +++ b/Build/source/utils/asymptote/LspCpp/LibLsp/JsonRpc/WebSocketServer.cpp @@ -0,0 +1,341 @@ +#include "MessageIssue.h" +#include "WebSocketServer.h" +#include <iostream> +#include <signal.h> +#include <utility> +#include "stream.h" +#include <boost/beast/core.hpp> +#include <boost/beast/websocket.hpp> +#include <boost/asio/dispatch.hpp> +namespace beast = boost::beast; // from <boost/beast.hpp> +namespace http = beast::http; // from <boost/beast/http.hpp> +namespace websocket = beast::websocket; // from <boost/beast/websocket.hpp> +namespace net = boost::asio; // from <boost/asio.hpp> +using tcp = boost::asio::ip::tcp; // from <boost/asio/ip/tcp.hpp> +namespace lsp { + + // Echoes back all received WebSocket messages + class server_session : public std::enable_shared_from_this<server_session> + { + websocket::stream<beast::tcp_stream> ws_; + + beast::flat_buffer buffer_; + std::string user_agent_; + public: + std::shared_ptr<websocket_stream_wrapper> proxy_; + // Take ownership of the socket + explicit + server_session(tcp::socket&& socket,const std::string& user_agent) + : ws_(std::move(socket)),user_agent_(user_agent) + { + proxy_ = std::make_shared<websocket_stream_wrapper>(ws_); + } + + // Get on the correct executor + void + run() + { + // We need to be executing within a strand to perform async operations + // on the I/O objects in this server_session. Although not strictly necessary + // for single-threaded contexts, this example code is written to be + // thread-safe by default. + net::dispatch(ws_.get_executor(), + beast::bind_front_handler( + &server_session::on_run, + shared_from_this())); + } + + // Start the asynchronous operation + void + on_run() + { + // Set suggested timeout settings for the websocket + ws_.set_option( + websocket::stream_base::timeout::suggested( + beast::role_type::server)); + + // Set a decorator to change the Server of the handshake + ws_.set_option(websocket::stream_base::decorator( + [=](websocket::response_type& res) + { + res.set(http::field::server, user_agent_.c_str()); + })); + // Accept the websocket handshake + ws_.async_accept( + beast::bind_front_handler( + &server_session::on_accept, + shared_from_this())); + } + + void + on_accept(beast::error_code ec) + { + if (ec) + return ; + + // Read a message + // Read a message into our buffer + ws_.async_read( + buffer_, + beast::bind_front_handler( + &server_session::on_read, + shared_from_this())); + } + + + + void + on_read( + beast::error_code ec, + std::size_t bytes_transferred) + { + + if(!ec) + { + char* data = reinterpret_cast<char*>(buffer_.data().data()); + std::vector<char> elements(data, data + bytes_transferred); + + buffer_.clear(); + proxy_->on_request.EnqueueAll(std::move(elements), false); + + // Read a message into our buffer + ws_.async_read( + buffer_, + beast::bind_front_handler( + &server_session::on_read, + shared_from_this())); + return; + } + if (ec){ + proxy_->error_message = ec.message(); + } + } + + + + void close() + { + if(ws_.is_open()) + { + boost::system::error_code ec; + ws_.close(websocket::close_code::normal, ec); + } + + } + }; + + //------------------------------------------------------------------------------ + + struct WebSocketServer::Data + { + Data(const std::string& user_agent, lsp::Log& log) : + acceptor_(io_context_), user_agent_(user_agent), _log(log) + + { + } + + ~Data() + { + + } + /// The io_context used to perform asynchronous operations. + boost::asio::io_context io_context_; + + std::shared_ptr<boost::asio::io_service::work> work; + + /// Acceptor used to listen for incoming connections. + boost::asio::ip::tcp::acceptor acceptor_; + + std::shared_ptr < server_session> _server_session; + + std::string user_agent_; + lsp::Log& _log; + + }; + + websocket_stream_wrapper::websocket_stream_wrapper(boost::beast::websocket::stream<boost::beast::tcp_stream>& _w): + ws_(_w), request_waiter(new MultiQueueWaiter()), + on_request(request_waiter) + { + } + + bool websocket_stream_wrapper::fail() + { + return bad(); + } + + bool websocket_stream_wrapper::eof() + { + return bad(); + } + + bool websocket_stream_wrapper::good() + { + return !bad(); + } + + websocket_stream_wrapper& websocket_stream_wrapper::read(char* str, std::streamsize count) + { + auto some = on_request.TryDequeueSome(static_cast<size_t>(count)); + + for (size_t i = 0; i < some.size(); ++i) + { + str[i] = some[i]; + } + for (std::streamsize i = 0; i < count; ++i) + { + str[i] = static_cast<char>(get()); + } + return *this; + } + + int websocket_stream_wrapper::get() + { + return on_request.Dequeue(); + } + + bool websocket_stream_wrapper::bad() + { + return !ws_.next_layer().socket().is_open(); + } + + websocket_stream_wrapper& websocket_stream_wrapper::write(const std::string& c) + { + ws_.write(boost::asio::buffer(std::string(c))); + return *this; + } + + + websocket_stream_wrapper& websocket_stream_wrapper::write(std::streamsize _s) + { + std::ostringstream temp; + temp << _s; + ws_.write(boost::asio::buffer(temp.str())); + return *this; + } + + websocket_stream_wrapper& websocket_stream_wrapper::flush() + { + return *this; + } + + void websocket_stream_wrapper::clear() + { + } + + std::string websocket_stream_wrapper::what() + { + if (!error_message.empty()) + return error_message; + + if (!ws_.next_layer().socket().is_open()) + { + return "Socket is not open."; + } + return {}; + } + + WebSocketServer::~WebSocketServer() + { + delete d_ptr; + } + + WebSocketServer::WebSocketServer(const std::string& user_agent, const std::string& address, const std::string& port, + std::shared_ptr < MessageJsonHandler> json_handler, + std::shared_ptr < Endpoint> localEndPoint, lsp::Log& log, uint32_t _max_workers) + : point(json_handler,localEndPoint,log, _max_workers),d_ptr(new Data(user_agent,log)) + + { + + d_ptr->work = std::make_shared<boost::asio::io_service::work>(d_ptr->io_context_); + + // Open the acceptor with the option to reuse the address (i.e. SO_REUSEADDR). + boost::asio::ip::tcp::resolver resolver(d_ptr->io_context_); + boost::asio::ip::tcp::endpoint endpoint = + *resolver.resolve(address, port).begin(); + d_ptr->acceptor_.open(endpoint.protocol()); + d_ptr->acceptor_.set_option(boost::asio::ip::tcp::acceptor::reuse_address(true)); + try + { + d_ptr->acceptor_.bind(endpoint); + } + catch (boost::system::system_error & e) + { + std::string temp = "Socket Server blid faild."; + d_ptr->_log.log(lsp::Log::Level::INFO , temp + e.what()); + return; + } + d_ptr->acceptor_.listen(); + + do_accept(); + std::string desc = "Socket WebSocketServer " + address + " " + port + " start."; + d_ptr->_log.log(lsp::Log::Level::INFO, desc); + } + + void WebSocketServer::run() + { + // The io_context::run() call will block until all asynchronous operations + // have finished. While the WebSocketServer is running, there is always at least one + // asynchronous operation outstanding: the asynchronous accept call waiting + // for new incoming connections. + d_ptr->io_context_.run(); + + } + + void WebSocketServer::stop() + { + try + { + if(d_ptr->work) + d_ptr->work.reset(); + + do_stop(); + } + catch (...) + { + } + } + + void WebSocketServer::do_accept() + { + d_ptr->acceptor_.async_accept( + [this](boost::system::error_code ec, boost::asio::ip::tcp::socket socket) + { + // Check whether the WebSocketServer was stopped by a signal before this + // completion handler had a chance to run. + if (!d_ptr->acceptor_.is_open()) + { + return; + } + if (!ec) + { + if(d_ptr->_server_session) + { + try + { + d_ptr->_server_session->close(); + point.Stop(); + } + catch (...) + { + } + } + d_ptr->_server_session = std::make_shared<server_session>(std::move(socket), d_ptr->user_agent_); + d_ptr->_server_session->run(); + + point.startProcessingMessages(d_ptr->_server_session->proxy_, d_ptr->_server_session->proxy_); + do_accept(); + } + + }); + } + + void WebSocketServer::do_stop() + { + d_ptr->acceptor_.close(); + + point.Stop(); + + } + + } // namespace diff --git a/Build/source/utils/asymptote/LspCpp/LibLsp/JsonRpc/WebSocketServer.h b/Build/source/utils/asymptote/LspCpp/LibLsp/JsonRpc/WebSocketServer.h new file mode 100644 index 00000000000..5206525cebe --- /dev/null +++ b/Build/source/utils/asymptote/LspCpp/LibLsp/JsonRpc/WebSocketServer.h @@ -0,0 +1,87 @@ +#pragma once + +#include <boost/asio.hpp> +#include <string> +#include <boost/beast/core/tcp_stream.hpp> +#include <boost/beast/websocket/stream.hpp> + + +#include "RemoteEndPoint.h" +#include "stream.h" +#include "threaded_queue.h" + +namespace lsp { + class Log; +} + + +namespace lsp +{ + + + + class websocket_stream_wrapper :public istream, public ostream + { + public: + + websocket_stream_wrapper(boost::beast::websocket::stream<boost::beast::tcp_stream>& _w); + + boost::beast::websocket::stream<boost::beast::tcp_stream>& ws_; + std::atomic<bool> quit{}; + std::shared_ptr < MultiQueueWaiter> request_waiter; + ThreadedQueue< char > on_request; + std::string error_message; + bool fail() override; + + bool eof() override; + + bool good() override; + + websocket_stream_wrapper& read(char* str, std::streamsize count) override; + + int get() override; + + bool bad() override; + + websocket_stream_wrapper& write(const std::string& c) override; + + websocket_stream_wrapper& write(std::streamsize _s) override; + + websocket_stream_wrapper& flush() override; + + void clear() override; + + std::string what() override; + }; + + /// The top-level class of the HTTP server. + class WebSocketServer + { + public: + WebSocketServer(const WebSocketServer&) = delete; + WebSocketServer& operator=(const WebSocketServer&) = delete; + ~WebSocketServer(); + /// Construct the server to listen on the specified TCP address and port, and + /// serve up files from the given directory. + explicit WebSocketServer(const std::string& user_agent, const std::string& address, const std::string& port, + std::shared_ptr < MessageJsonHandler> json_handler, + std::shared_ptr < Endpoint> localEndPoint, lsp::Log& ,uint32_t _max_workers = 2); + + /// Run the server's io_context loop. + void run(); + void stop(); + + RemoteEndPoint point; + private: + struct Data; + /// Perform an asynchronous accept operation. + void do_accept(); + + /// Wait for a request to stop the server. + void do_stop(); + Data* d_ptr = nullptr; + + + }; + + } // namespace diff --git a/Build/source/utils/asymptote/LspCpp/LibLsp/JsonRpc/json.h b/Build/source/utils/asymptote/LspCpp/LibLsp/JsonRpc/json.h new file mode 100644 index 00000000000..98ee91b544a --- /dev/null +++ b/Build/source/utils/asymptote/LspCpp/LibLsp/JsonRpc/json.h @@ -0,0 +1,81 @@ +#pragma once + +#include "serializer.h" + +#include <rapidjson/document.h> +#include <rapidjson/prettywriter.h> + +class JsonReader : public Reader { + + std::vector<const char*> path_; + + public: + rapidjson::GenericValue<rapidjson::UTF8<>>* m_; + JsonReader(rapidjson::GenericValue<rapidjson::UTF8<>>* m) : m_(m) {} + SerializeFormat Format() const override { return SerializeFormat::Json; } + + bool IsBool() override { return m_->IsBool(); } + bool IsNull() override { return m_->IsNull(); } + bool IsArray() override { return m_->IsArray(); } + bool IsInt() override { return m_->IsInt(); } + bool IsInt64() override { return m_->IsInt64(); } + bool IsUint64() override { return m_->IsUint64(); } + bool IsDouble() override { return m_->IsDouble(); } + bool IsNumber() override { return m_->IsNumber(); } + bool IsString() override { return m_->IsString(); } + + void GetNull() override {} + bool GetBool() override { return m_->GetBool(); } + int GetInt() override { return m_->GetInt(); } + uint32_t GetUint32() override { return uint32_t(m_->GetUint64()); } + int64_t GetInt64() override { return m_->GetInt64(); } + uint64_t GetUint64() override { return m_->GetUint64(); } + double GetDouble() override { return m_->GetDouble(); } + std::string GetString() override { return m_->GetString(); } + + bool HasMember(const char* x) override + { + if (m_->IsObject()) + return m_->HasMember(x); + else + return false; + } + std::unique_ptr<Reader> operator[](const char* x) override { + auto& sub = (*m_)[x]; + return std::unique_ptr<JsonReader>(new JsonReader(&sub)); + } + + std::string ToString() const override; + + void IterMap(std::function<void(const char*, Reader&)> fn) override; + + void IterArray(std::function<void(Reader&)> fn) override; + + void DoMember(const char* name, std::function<void(Reader&)> fn) override; + + std::string GetPath() const; +}; + +class JsonWriter : public Writer { + + public: + rapidjson::Writer<rapidjson::StringBuffer>* m_; + + JsonWriter(rapidjson::Writer<rapidjson::StringBuffer>* m) : m_(m) {} + SerializeFormat Format() const override { return SerializeFormat::Json; } + + void Null() override { m_->Null(); } + void Bool(bool x) override { m_->Bool(x); } + void Int(int x) override { m_->Int(x); } + void Uint32(uint32_t x) override { m_->Uint64(x); } + void Int64(int64_t x) override { m_->Int64(x); } + void Uint64(uint64_t x) override { m_->Uint64(x); } + void Double(double x) override { m_->Double(x); } + void String(const char* x) override { m_->String(x); } + void String(const char* x, size_t len) override { m_->String(x, len); } + void StartArray(size_t) override { m_->StartArray(); } + void EndArray() override { m_->EndArray(); } + void StartObject() override { m_->StartObject(); } + void EndObject() override { m_->EndObject(); } + void Key(const char* name) override { m_->Key(name); } +}; diff --git a/Build/source/utils/asymptote/LspCpp/LibLsp/JsonRpc/lsRequestId.h b/Build/source/utils/asymptote/LspCpp/LibLsp/JsonRpc/lsRequestId.h new file mode 100644 index 00000000000..87e94669ab6 --- /dev/null +++ b/Build/source/utils/asymptote/LspCpp/LibLsp/JsonRpc/lsRequestId.h @@ -0,0 +1,51 @@ +#pragma once + +#include "LibLsp/JsonRpc/serializer.h" + +struct lsRequestId { + // The client can send the request id as an int or a string. We should output + // the same format we received. + enum Type { kNone, kInt, kString }; + Type type = kNone; + + int value = -1; + std::string k_string; + bool has_value() const { return type != kNone; } + void swap(lsRequestId& arg) noexcept + { + std::swap(arg, *this); + } + void set(int v) + { + value = v; + type = kInt; + } + void set(const std::string& v) + { + k_string = v; + type = kString; + } + bool operator==(const lsRequestId& rhs) const + { + if (type != rhs.type) return false; + if (type == kInt) + return value == rhs.value; + return k_string == rhs.k_string; + } + bool operator!=(const lsRequestId& rhs) const + { + return !operator==(rhs); + } + bool operator<(const lsRequestId& rhs) const + { + if (type != rhs.type) return false; + if (type == kInt) + return value < rhs.value; + return k_string < rhs.k_string; + } +}; +void Reflect(Reader& visitor, lsRequestId& value); +void Reflect(Writer& visitor, lsRequestId& value); + +// Debug method to convert an id to a string. +std::string ToString(const lsRequestId& id);
\ No newline at end of file diff --git a/Build/source/utils/asymptote/LspCpp/LibLsp/JsonRpc/lsResponseMessage.h b/Build/source/utils/asymptote/LspCpp/LibLsp/JsonRpc/lsResponseMessage.h new file mode 100644 index 00000000000..ba94167cf8b --- /dev/null +++ b/Build/source/utils/asymptote/LspCpp/LibLsp/JsonRpc/lsResponseMessage.h @@ -0,0 +1,71 @@ +#pragma once +#include "serializer.h" +#include "lsRequestId.h" +#include "LibLsp/JsonRpc/message.h" +#include "LibLsp/lsp/method_type.h" + + +struct ResponseInMessage :public LspMessage { + + lsRequestId id; + std::string m_methodType; + + virtual MethodType GetMethodType() const override + { + return m_methodType.data(); + }; + virtual void SetMethodType(MethodType _type) override + { + m_methodType = _type; + }; + + Kind GetKid() override + { + return RESPONCE_MESSAGE; + } + virtual bool IsErrorType() + { + return false; + } +}; +template <class TDerived > +struct BaseResponseMessage : ResponseInMessage { + + void ReflectWriter(Writer& writer) override { + Reflect(writer, static_cast<TDerived&>(*this)); + } + static std::unique_ptr<LspMessage> ReflectReader(Reader& visitor) { + + TDerived* temp = new TDerived(); + std::unique_ptr<TDerived> message = std::unique_ptr<TDerived>(temp); + // Reflect may throw and *message will be partially deserialized. + Reflect(visitor, static_cast<TDerived&>(*temp)); + return message; + } + +}; + + +template <class T, class TDerived > +struct ResponseMessage : BaseResponseMessage<TDerived> { + T result; + void swap(ResponseMessage<T, TDerived>& arg) noexcept + { + std::swap(result, arg.result); + this->id.swap(arg.id); + this->m_methodType.swap(arg.m_methodType); + } +}; + +template <class T, class TDerived > +struct ResponseError : BaseResponseMessage<TDerived> { + T error; + bool IsErrorType() override { return true; } + void swap(ResponseError<T, TDerived>& arg) noexcept + { + + this->id.swap(arg.id); + this->m_methodType.swap(arg.m_methodType); + std::swap(error, arg.error); + } +}; diff --git a/Build/source/utils/asymptote/LspCpp/LibLsp/JsonRpc/message.cpp b/Build/source/utils/asymptote/LspCpp/LibLsp/JsonRpc/message.cpp new file mode 100644 index 00000000000..e84455402c0 --- /dev/null +++ b/Build/source/utils/asymptote/LspCpp/LibLsp/JsonRpc/message.cpp @@ -0,0 +1,88 @@ +#include "message.h" +#include <rapidjson/stringbuffer.h> +#include <rapidjson/writer.h> +#include "serializer.h" +#include "lsRequestId.h" +#include "RequestInMessage.h" +#include "Condition.h" +#include "json.h" + +void LspMessage::Write(std::ostream& out) { + rapidjson::StringBuffer output; + rapidjson::Writer<rapidjson::StringBuffer> writer(output); + JsonWriter json_writer{ &writer }; + ReflectWriter(json_writer); + + const auto value = std::string("Content-Length: ") + std::to_string(output.GetSize()) + "\r\n\r\n" + output.GetString(); + out << value; + out.flush(); +} + +std::string LspMessage::ToJson() { + rapidjson::StringBuffer output; + rapidjson::Writer<rapidjson::StringBuffer> writer(output); + JsonWriter json_writer{ &writer }; + this->ReflectWriter(json_writer); + return output.GetString(); +} + +void Reflect(Reader& visitor, lsRequestId& value) { + if (visitor.IsInt()) { + value.type = lsRequestId::kInt; + value.value = visitor.GetInt(); + } + else if (visitor.IsInt64()) { + value.type = lsRequestId::kInt; + // `lsRequestId.value` is an `int`, so we're forced to truncate. + value.value = static_cast<int>(visitor.GetInt64()); + } + else if (visitor.IsString()) { + value.type = lsRequestId::kString; + value.k_string = visitor.GetString(); + value.value = atoi(value.k_string.c_str()); + + } + else { + value.type = lsRequestId::kNone; + value.value = -1; + } +} + +void Reflect(Writer& visitor, lsRequestId& value) { + switch (value.type) { + case lsRequestId::kNone: + visitor.Null(); + break; + case lsRequestId::kInt: + visitor.Int(value.value); + break; + case lsRequestId::kString: + + if(value.k_string.empty()) + { + std::string str = std::to_string(value.value); + visitor.String(str.c_str(), str.length()); + } + else + { + visitor.String(value.k_string.c_str(), value.k_string.length()); + } + break; + } +} + +std::string ToString(const lsRequestId& id) { + if (id.type != lsRequestId::kNone) + { + if(id.type == lsRequestId::kString) + { + if (!id.k_string.empty()) + return id.k_string; + } + return std::to_string(id.value); + } + + return ""; +} + + diff --git a/Build/source/utils/asymptote/LspCpp/LibLsp/JsonRpc/message.h b/Build/source/utils/asymptote/LspCpp/LibLsp/JsonRpc/message.h new file mode 100644 index 00000000000..6603f3fb3a2 --- /dev/null +++ b/Build/source/utils/asymptote/LspCpp/LibLsp/JsonRpc/message.h @@ -0,0 +1,34 @@ +#pragma once + +#include <atomic> +#include <string> +#include <iostream> +#include <LibLsp/JsonRpc/serializer.h> +#include "LibLsp/lsp/method_type.h" + +struct LspMessage +{ +public: + std::string jsonrpc = "2.0"; + virtual void ReflectWriter(Writer&) = 0; + + // Send the message to the language client by writing it to stdout. + void Write(std::ostream& out); + + + virtual MethodType GetMethodType() const = 0; + virtual void SetMethodType(MethodType) = 0; + + virtual ~LspMessage()=default; + enum Kind + { + REQUEST_MESSAGE, + RESPONCE_MESSAGE, + NOTIFICATION_MESSAGE + }; + + virtual Kind GetKid() = 0; + virtual std::string ToJson() ; + +}; + diff --git a/Build/source/utils/asymptote/LspCpp/LibLsp/JsonRpc/optional.hpp b/Build/source/utils/asymptote/LspCpp/LibLsp/JsonRpc/optional.hpp new file mode 100644 index 00000000000..86e3b407c66 --- /dev/null +++ b/Build/source/utils/asymptote/LspCpp/LibLsp/JsonRpc/optional.hpp @@ -0,0 +1,1846 @@ +// +// Copyright (c) 2014-2021 Martin Moene +// +// https://github.com/martinmoene/optional-lite +// +// Distributed under the Boost Software License, Version 1.0. +// (See accompanying file LICENSE.txt or copy at http://www.boost.org/LICENSE_1_0.txt) + +#pragma once + +#ifndef NONSTD_OPTIONAL_LITE_HPP +#define NONSTD_OPTIONAL_LITE_HPP + +#define optional_lite_MAJOR 3 +#define optional_lite_MINOR 5 +#define optional_lite_PATCH 0 + +#define optional_lite_VERSION optional_STRINGIFY(optional_lite_MAJOR) "." optional_STRINGIFY(optional_lite_MINOR) "." optional_STRINGIFY(optional_lite_PATCH) + +#define optional_STRINGIFY( x ) optional_STRINGIFY_( x ) +#define optional_STRINGIFY_( x ) #x + +// optional-lite configuration: + +#define optional_OPTIONAL_DEFAULT 0 +#define optional_OPTIONAL_NONSTD 1 +#define optional_OPTIONAL_STD 2 + +// tweak header support: + +#ifdef __has_include +# if __has_include(<nonstd/optional.tweak.hpp>) +# include <nonstd/optional.tweak.hpp> +# endif +#define optional_HAVE_TWEAK_HEADER 1 +#else +#define optional_HAVE_TWEAK_HEADER 0 +//# pragma message("optional.hpp: Note: Tweak header not supported.") +#endif + +// optional selection and configuration: + +#if !defined( optional_CONFIG_SELECT_OPTIONAL ) +# define optional_CONFIG_SELECT_OPTIONAL ( optional_HAVE_STD_OPTIONAL ? optional_OPTIONAL_STD : optional_OPTIONAL_NONSTD ) +#endif + +// Control presence of extensions: + +#ifndef optional_CONFIG_NO_EXTENSIONS +#define optional_CONFIG_NO_EXTENSIONS 0 +#endif + +// Control presence of exception handling (try and auto discover): + +#ifndef optional_CONFIG_NO_EXCEPTIONS +# if defined(_MSC_VER) +# include <cstddef> // for _HAS_EXCEPTIONS +# endif +# if defined(__cpp_exceptions) || defined(__EXCEPTIONS) || (_HAS_EXCEPTIONS) +# define optional_CONFIG_NO_EXCEPTIONS 0 +# else +# define optional_CONFIG_NO_EXCEPTIONS 1 +# endif +#endif + +// C++ language version detection (C++20 is speculative): +// Note: VC14.0/1900 (VS2015) lacks too much from C++14. + +#ifndef optional_CPLUSPLUS +# if defined(_MSVC_LANG ) && !defined(__clang__) +# define optional_CPLUSPLUS (_MSC_VER == 1900 ? 201103L : _MSVC_LANG ) +# else +# define optional_CPLUSPLUS __cplusplus +# endif +#endif + +#define optional_CPP98_OR_GREATER ( optional_CPLUSPLUS >= 199711L ) +#define optional_CPP11_OR_GREATER ( optional_CPLUSPLUS >= 201103L ) +#define optional_CPP11_OR_GREATER_ ( optional_CPLUSPLUS >= 201103L ) +#define optional_CPP14_OR_GREATER ( optional_CPLUSPLUS >= 201402L ) +#define optional_CPP17_OR_GREATER ( optional_CPLUSPLUS >= 201703L ) +#define optional_CPP20_OR_GREATER ( optional_CPLUSPLUS >= 202000L ) + +// C++ language version (represent 98 as 3): + +#define optional_CPLUSPLUS_V ( optional_CPLUSPLUS / 100 - (optional_CPLUSPLUS > 200000 ? 2000 : 1994) ) + +// Use C++17 std::optional if available and requested: + +#if optional_CPP17_OR_GREATER && defined(__has_include ) +# if __has_include( <optional> ) +# define optional_HAVE_STD_OPTIONAL 1 +# else +# define optional_HAVE_STD_OPTIONAL 0 +# endif +#else +# define optional_HAVE_STD_OPTIONAL 0 +#endif + +#define optional_USES_STD_OPTIONAL ( (optional_CONFIG_SELECT_OPTIONAL == optional_OPTIONAL_STD) || ((optional_CONFIG_SELECT_OPTIONAL == optional_OPTIONAL_DEFAULT) && optional_HAVE_STD_OPTIONAL) ) + +// +// in_place: code duplicated in any-lite, expected-lite, optional-lite, value-ptr-lite, variant-lite: +// + +#ifndef nonstd_lite_HAVE_IN_PLACE_TYPES +#define nonstd_lite_HAVE_IN_PLACE_TYPES 1 + +// C++17 std::in_place in <utility>: + +#if optional_CPP17_OR_GREATER + +#include <utility> + +namespace nonstd { + +using std::in_place; +using std::in_place_type; +using std::in_place_index; +using std::in_place_t; +using std::in_place_type_t; +using std::in_place_index_t; + +#define nonstd_lite_in_place_t( T) std::in_place_t +#define nonstd_lite_in_place_type_t( T) std::in_place_type_t<T> +#define nonstd_lite_in_place_index_t(K) std::in_place_index_t<K> + +#define nonstd_lite_in_place( T) std::in_place_t{} +#define nonstd_lite_in_place_type( T) std::in_place_type_t<T>{} +#define nonstd_lite_in_place_index(K) std::in_place_index_t<K>{} + +} // namespace nonstd + +#else // optional_CPP17_OR_GREATER + +#include <cstddef> + +namespace nonstd { +namespace detail { + +template< class T > +struct in_place_type_tag {}; + +template< std::size_t K > +struct in_place_index_tag {}; + +} // namespace detail + +struct in_place_t {}; + +template< class T > +inline in_place_t in_place( detail::in_place_type_tag<T> /*unused*/ = detail::in_place_type_tag<T>() ) +{ + return in_place_t(); +} + +template< std::size_t K > +inline in_place_t in_place( detail::in_place_index_tag<K> /*unused*/ = detail::in_place_index_tag<K>() ) +{ + return in_place_t(); +} + +template< class T > +inline in_place_t in_place_type( detail::in_place_type_tag<T> /*unused*/ = detail::in_place_type_tag<T>() ) +{ + return in_place_t(); +} + +template< std::size_t K > +inline in_place_t in_place_index( detail::in_place_index_tag<K> /*unused*/ = detail::in_place_index_tag<K>() ) +{ + return in_place_t(); +} + +// mimic templated typedef: + +#define nonstd_lite_in_place_t( T) nonstd::in_place_t(&)( nonstd::detail::in_place_type_tag<T> ) +#define nonstd_lite_in_place_type_t( T) nonstd::in_place_t(&)( nonstd::detail::in_place_type_tag<T> ) +#define nonstd_lite_in_place_index_t(K) nonstd::in_place_t(&)( nonstd::detail::in_place_index_tag<K> ) + +#define nonstd_lite_in_place( T) nonstd::in_place_type<T> +#define nonstd_lite_in_place_type( T) nonstd::in_place_type<T> +#define nonstd_lite_in_place_index(K) nonstd::in_place_index<K> + +} // namespace nonstd + +#endif // optional_CPP17_OR_GREATER +#endif // nonstd_lite_HAVE_IN_PLACE_TYPES + +// +// Using std::optional: +// + +#if optional_USES_STD_OPTIONAL + +#include <optional> + +namespace nonstd { + + using std::optional; + using std::bad_optional_access; + using std::hash; + + using std::nullopt; + using std::nullopt_t; + + using std::operator==; + using std::operator!=; + using std::operator<; + using std::operator<=; + using std::operator>; + using std::operator>=; + using std::make_optional; + using std::swap; +} + +#else // optional_USES_STD_OPTIONAL + +#include <cassert> +#include <utility> + +// optional-lite alignment configuration: + +#ifndef optional_CONFIG_MAX_ALIGN_HACK +# define optional_CONFIG_MAX_ALIGN_HACK 0 +#endif + +#ifndef optional_CONFIG_ALIGN_AS +// no default, used in #if defined() +#endif + +#ifndef optional_CONFIG_ALIGN_AS_FALLBACK +# define optional_CONFIG_ALIGN_AS_FALLBACK double +#endif + +// Compiler warning suppression: + +#if defined(__clang__) +# pragma clang diagnostic push +# pragma clang diagnostic ignored "-Wundef" +#elif defined(__GNUC__) +# pragma GCC diagnostic push +# pragma GCC diagnostic ignored "-Wundef" +#elif defined(_MSC_VER ) +# pragma warning( push ) +#endif + +// half-open range [lo..hi): +#define optional_BETWEEN( v, lo, hi ) ( (lo) <= (v) && (v) < (hi) ) + +// Compiler versions: +// +// MSVC++ 6.0 _MSC_VER == 1200 optional_COMPILER_MSVC_VERSION == 60 (Visual Studio 6.0) +// MSVC++ 7.0 _MSC_VER == 1300 optional_COMPILER_MSVC_VERSION == 70 (Visual Studio .NET 2002) +// MSVC++ 7.1 _MSC_VER == 1310 optional_COMPILER_MSVC_VERSION == 71 (Visual Studio .NET 2003) +// MSVC++ 8.0 _MSC_VER == 1400 optional_COMPILER_MSVC_VERSION == 80 (Visual Studio 2005) +// MSVC++ 9.0 _MSC_VER == 1500 optional_COMPILER_MSVC_VERSION == 90 (Visual Studio 2008) +// MSVC++ 10.0 _MSC_VER == 1600 optional_COMPILER_MSVC_VERSION == 100 (Visual Studio 2010) +// MSVC++ 11.0 _MSC_VER == 1700 optional_COMPILER_MSVC_VERSION == 110 (Visual Studio 2012) +// MSVC++ 12.0 _MSC_VER == 1800 optional_COMPILER_MSVC_VERSION == 120 (Visual Studio 2013) +// MSVC++ 14.0 _MSC_VER == 1900 optional_COMPILER_MSVC_VERSION == 140 (Visual Studio 2015) +// MSVC++ 14.1 _MSC_VER >= 1910 optional_COMPILER_MSVC_VERSION == 141 (Visual Studio 2017) +// MSVC++ 14.2 _MSC_VER >= 1920 optional_COMPILER_MSVC_VERSION == 142 (Visual Studio 2019) + +#if defined(_MSC_VER ) && !defined(__clang__) +# define optional_COMPILER_MSVC_VER (_MSC_VER ) +# define optional_COMPILER_MSVC_VERSION (_MSC_VER / 10 - 10 * ( 5 + (_MSC_VER < 1900 ) ) ) +#else +# define optional_COMPILER_MSVC_VER 0 +# define optional_COMPILER_MSVC_VERSION 0 +#endif + +#define optional_COMPILER_VERSION( major, minor, patch ) ( 10 * (10 * (major) + (minor) ) + (patch) ) + +#if defined(__GNUC__) && !defined(__clang__) +# define optional_COMPILER_GNUC_VERSION optional_COMPILER_VERSION(__GNUC__, __GNUC_MINOR__, __GNUC_PATCHLEVEL__) +#else +# define optional_COMPILER_GNUC_VERSION 0 +#endif + +#if defined(__clang__) +# define optional_COMPILER_CLANG_VERSION optional_COMPILER_VERSION(__clang_major__, __clang_minor__, __clang_patchlevel__) +#else +# define optional_COMPILER_CLANG_VERSION 0 +#endif + +#if optional_BETWEEN(optional_COMPILER_MSVC_VERSION, 70, 140 ) +# pragma warning( disable: 4345 ) // initialization behavior changed +#endif + +#if optional_BETWEEN(optional_COMPILER_MSVC_VERSION, 70, 150 ) +# pragma warning( disable: 4814 ) // in C++14 'constexpr' will not imply 'const' +#endif + +// Presence of language and library features: + +#define optional_HAVE(FEATURE) ( optional_HAVE_##FEATURE ) + +#ifdef _HAS_CPP0X +# define optional_HAS_CPP0X _HAS_CPP0X +#else +# define optional_HAS_CPP0X 0 +#endif + +// Unless defined otherwise below, consider VC14 as C++11 for optional-lite: + +#if optional_COMPILER_MSVC_VER >= 1900 +# undef optional_CPP11_OR_GREATER +# define optional_CPP11_OR_GREATER 1 +#endif + +#define optional_CPP11_90 (optional_CPP11_OR_GREATER_ || optional_COMPILER_MSVC_VER >= 1500) +#define optional_CPP11_100 (optional_CPP11_OR_GREATER_ || optional_COMPILER_MSVC_VER >= 1600) +#define optional_CPP11_110 (optional_CPP11_OR_GREATER_ || optional_COMPILER_MSVC_VER >= 1700) +#define optional_CPP11_120 (optional_CPP11_OR_GREATER_ || optional_COMPILER_MSVC_VER >= 1800) +#define optional_CPP11_140 (optional_CPP11_OR_GREATER_ || optional_COMPILER_MSVC_VER >= 1900) +#define optional_CPP11_141 (optional_CPP11_OR_GREATER_ || optional_COMPILER_MSVC_VER >= 1910) + +#define optional_CPP14_000 (optional_CPP14_OR_GREATER) +#define optional_CPP17_000 (optional_CPP17_OR_GREATER) + +// clang >= 2.9, gcc >= 4.9, msvc >= vc14.0/1900 (vs15): +#define optional_CPP11_140_C290_G490 ((optional_CPP11_OR_GREATER_ && (optional_COMPILER_CLANG_VERSION >= 290 || optional_COMPILER_GNUC_VERSION >= 490)) || (optional_COMPILER_MSVC_VER >= 1900)) + +// clang >= 3.5, msvc >= vc11 (vs12): +#define optional_CPP11_110_C350 ( optional_CPP11_110 && !optional_BETWEEN( optional_COMPILER_CLANG_VERSION, 1, 350 ) ) + +// clang >= 3.5, gcc >= 5.0, msvc >= vc11 (vs12): +#define optional_CPP11_110_C350_G500 \ + ( optional_CPP11_110 && \ + !( optional_BETWEEN( optional_COMPILER_CLANG_VERSION, 1, 350 ) \ + || optional_BETWEEN( optional_COMPILER_GNUC_VERSION , 1, 500 ) ) ) + +// Presence of C++11 language features: + +#define optional_HAVE_CONSTEXPR_11 optional_CPP11_140 +#define optional_HAVE_IS_DEFAULT optional_CPP11_140 +#define optional_HAVE_NOEXCEPT optional_CPP11_140 +#define optional_HAVE_NULLPTR optional_CPP11_100 +#define optional_HAVE_REF_QUALIFIER optional_CPP11_140_C290_G490 +#define optional_HAVE_STATIC_ASSERT optional_CPP11_110 +#define optional_HAVE_INITIALIZER_LIST optional_CPP11_140 + +// Presence of C++14 language features: + +#define optional_HAVE_CONSTEXPR_14 optional_CPP14_000 + +// Presence of C++17 language features: + +#define optional_HAVE_NODISCARD optional_CPP17_000 + +// Presence of C++ library features: + +#define optional_HAVE_CONDITIONAL optional_CPP11_120 +#define optional_HAVE_REMOVE_CV optional_CPP11_120 +#define optional_HAVE_TYPE_TRAITS optional_CPP11_90 + +#define optional_HAVE_TR1_TYPE_TRAITS (!! optional_COMPILER_GNUC_VERSION ) +#define optional_HAVE_TR1_ADD_POINTER (!! optional_COMPILER_GNUC_VERSION ) + +#define optional_HAVE_IS_ASSIGNABLE optional_CPP11_110_C350 +#define optional_HAVE_IS_MOVE_CONSTRUCTIBLE optional_CPP11_110_C350 +#define optional_HAVE_IS_NOTHROW_MOVE_ASSIGNABLE optional_CPP11_110_C350 +#define optional_HAVE_IS_NOTHROW_MOVE_CONSTRUCTIBLE optional_CPP11_110_C350 +#define optional_HAVE_IS_TRIVIALLY_COPY_CONSTRUCTIBLE optional_CPP11_110_C350_G500 +#define optional_HAVE_IS_TRIVIALLY_MOVE_CONSTRUCTIBLE optional_CPP11_110_C350_G500 + +// C++ feature usage: + +#if optional_HAVE( CONSTEXPR_11 ) +# define optional_constexpr constexpr +#else +# define optional_constexpr /*constexpr*/ +#endif + +#if optional_HAVE( IS_DEFAULT ) +# define optional_is_default = default; +#else +# define optional_is_default {} +#endif + +#if optional_HAVE( CONSTEXPR_14 ) +# define optional_constexpr14 constexpr +#else +# define optional_constexpr14 /*constexpr*/ +#endif + +#if optional_HAVE( NODISCARD ) +# define optional_nodiscard [[nodiscard]] +#else +# define optional_nodiscard /*[[nodiscard]]*/ +#endif + +#if optional_HAVE( NOEXCEPT ) +# define optional_noexcept noexcept +#else +# define optional_noexcept /*noexcept*/ +#endif + +#if optional_HAVE( NULLPTR ) +# define optional_nullptr nullptr +#else +# define optional_nullptr NULL +#endif + +#if optional_HAVE( REF_QUALIFIER ) +// NOLINTNEXTLINE( bugprone-macro-parentheses ) +# define optional_ref_qual & +# define optional_refref_qual && +#else +# define optional_ref_qual /*&*/ +# define optional_refref_qual /*&&*/ +#endif + +#if optional_HAVE( STATIC_ASSERT ) +# define optional_static_assert(expr, text) static_assert(expr, text); +#else +# define optional_static_assert(expr, text) /*static_assert(expr, text);*/ +#endif + +// additional includes: + +#if optional_CONFIG_NO_EXCEPTIONS +// already included: <cassert> +#else +# include <stdexcept> +#endif + +#if optional_CPP11_OR_GREATER +# include <functional> +#endif + +#if optional_HAVE( INITIALIZER_LIST ) +# include <initializer_list> +#endif + +#if optional_HAVE( TYPE_TRAITS ) +# include <type_traits> +#elif optional_HAVE( TR1_TYPE_TRAITS ) +# include <tr1/type_traits> +#endif + +// Method enabling + +#if optional_CPP11_OR_GREATER + +#define optional_REQUIRES_0(...) \ + template< bool B = (__VA_ARGS__), typename std::enable_if<B, int>::type = 0 > + +#define optional_REQUIRES_T(...) \ + , typename std::enable_if< (__VA_ARGS__), int >::type = 0 + +#define optional_REQUIRES_R(R, ...) \ + typename std::enable_if< (__VA_ARGS__), R>::type + +#define optional_REQUIRES_A(...) \ + , typename std::enable_if< (__VA_ARGS__), void*>::type = nullptr + +#endif + +// +// optional: +// + +namespace nonstd { namespace optional_lite { + +namespace std11 { + +template< class T, T v > struct integral_constant { enum { value = v }; }; +template< bool B > struct bool_constant : integral_constant<bool, B>{}; + +typedef bool_constant< true > true_type; +typedef bool_constant< false > false_type; + +#if optional_CPP11_OR_GREATER + using std::move; +#else + template< typename T > T & move( T & t ) { return t; } +#endif + +#if optional_HAVE( CONDITIONAL ) + using std::conditional; +#else + template< bool B, typename T, typename F > struct conditional { typedef T type; }; + template< typename T, typename F > struct conditional<false, T, F> { typedef F type; }; +#endif // optional_HAVE_CONDITIONAL + +#if optional_HAVE( IS_ASSIGNABLE ) + using std::is_assignable; +#else + template< class T, class U > struct is_assignable : std11::true_type{}; +#endif + +#if optional_HAVE( IS_MOVE_CONSTRUCTIBLE ) + using std::is_move_constructible; +#else + template< class T > struct is_move_constructible : std11::true_type{}; +#endif + +#if optional_HAVE( IS_NOTHROW_MOVE_ASSIGNABLE ) + using std::is_nothrow_move_assignable; +#else + template< class T > struct is_nothrow_move_assignable : std11::true_type{}; +#endif + +#if optional_HAVE( IS_NOTHROW_MOVE_CONSTRUCTIBLE ) + using std::is_nothrow_move_constructible; +#else + template< class T > struct is_nothrow_move_constructible : std11::true_type{}; +#endif + +#if optional_HAVE( IS_TRIVIALLY_COPY_CONSTRUCTIBLE ) + using std::is_trivially_copy_constructible; +#else + template< class T > struct is_trivially_copy_constructible : std11::true_type{}; +#endif + +#if optional_HAVE( IS_TRIVIALLY_MOVE_CONSTRUCTIBLE ) + using std::is_trivially_move_constructible; +#else + template< class T > struct is_trivially_move_constructible : std11::true_type{}; +#endif + +} // namespace std11 + +#if optional_CPP11_OR_GREATER + +/// type traits C++17: + +namespace std17 { + +#if optional_CPP17_OR_GREATER + +using std::is_swappable; +using std::is_nothrow_swappable; + +#elif optional_CPP11_OR_GREATER + +namespace detail { + +using std::swap; + +struct is_swappable +{ + template< typename T, typename = decltype( swap( std::declval<T&>(), std::declval<T&>() ) ) > + static std11::true_type test( int /*unused*/ ); + + template< typename > + static std11::false_type test(...); +}; + +struct is_nothrow_swappable +{ + // wrap noexcept(expr) in separate function as work-around for VC140 (VS2015): + + template< typename T > + static constexpr bool satisfies() + { + return noexcept( swap( std::declval<T&>(), std::declval<T&>() ) ); + } + + template< typename T > + static auto test( int /*unused*/ ) -> std11::integral_constant<bool, satisfies<T>()>{} + + template< typename > + static auto test(...) -> std11::false_type; +}; + +} // namespace detail + +// is [nothow] swappable: + +template< typename T > +struct is_swappable : decltype( detail::is_swappable::test<T>(0) ){}; + +template< typename T > +struct is_nothrow_swappable : decltype( detail::is_nothrow_swappable::test<T>(0) ){}; + +#endif // optional_CPP17_OR_GREATER + +} // namespace std17 + +/// type traits C++20: + +namespace std20 { + +template< typename T > +struct remove_cvref +{ + typedef typename std::remove_cv< typename std::remove_reference<T>::type >::type type; +}; + +} // namespace std20 + +#endif // optional_CPP11_OR_GREATER + +/// class optional + +template< typename T > +class optional; + +namespace detail { + +// C++11 emulation: + +struct nulltype{}; + +template< typename Head, typename Tail > +struct typelist +{ + typedef Head head; + typedef Tail tail; +}; + +#if optional_CONFIG_MAX_ALIGN_HACK + +// Max align, use most restricted type for alignment: + +#define optional_UNIQUE( name ) optional_UNIQUE2( name, __LINE__ ) +#define optional_UNIQUE2( name, line ) optional_UNIQUE3( name, line ) +#define optional_UNIQUE3( name, line ) name ## line + +#define optional_ALIGN_TYPE( type ) \ + type optional_UNIQUE( _t ); struct_t< type > optional_UNIQUE( _st ) + +template< typename T > +struct struct_t { T _; }; + +union max_align_t +{ + optional_ALIGN_TYPE( char ); + optional_ALIGN_TYPE( short int ); + optional_ALIGN_TYPE( int ); + optional_ALIGN_TYPE( long int ); + optional_ALIGN_TYPE( float ); + optional_ALIGN_TYPE( double ); + optional_ALIGN_TYPE( long double ); + optional_ALIGN_TYPE( char * ); + optional_ALIGN_TYPE( short int * ); + optional_ALIGN_TYPE( int * ); + optional_ALIGN_TYPE( long int * ); + optional_ALIGN_TYPE( float * ); + optional_ALIGN_TYPE( double * ); + optional_ALIGN_TYPE( long double * ); + optional_ALIGN_TYPE( void * ); + +#ifdef HAVE_LONG_LONG + optional_ALIGN_TYPE( long long ); +#endif + + struct Unknown; + + Unknown ( * optional_UNIQUE(_) )( Unknown ); + Unknown * Unknown::* optional_UNIQUE(_); + Unknown ( Unknown::* optional_UNIQUE(_) )( Unknown ); + + struct_t< Unknown ( * )( Unknown) > optional_UNIQUE(_); + struct_t< Unknown * Unknown::* > optional_UNIQUE(_); + struct_t< Unknown ( Unknown::* )(Unknown) > optional_UNIQUE(_); +}; + +#undef optional_UNIQUE +#undef optional_UNIQUE2 +#undef optional_UNIQUE3 + +#undef optional_ALIGN_TYPE + +#elif defined( optional_CONFIG_ALIGN_AS ) // optional_CONFIG_MAX_ALIGN_HACK + +// Use user-specified type for alignment: + +#define optional_ALIGN_AS( unused ) \ + optional_CONFIG_ALIGN_AS + +#else // optional_CONFIG_MAX_ALIGN_HACK + +// Determine POD type to use for alignment: + +#define optional_ALIGN_AS( to_align ) \ + typename type_of_size< alignment_types, alignment_of< to_align >::value >::type + +template< typename T > +struct alignment_of; + +template< typename T > +struct alignment_of_hack +{ + char c; + T t; + alignment_of_hack(); +}; + +template< size_t A, size_t S > +struct alignment_logic +{ + enum { value = A < S ? A : S }; +}; + +template< typename T > +struct alignment_of +{ + enum { value = alignment_logic< + sizeof( alignment_of_hack<T> ) - sizeof(T), sizeof(T) >::value }; +}; + +template< typename List, size_t N > +struct type_of_size +{ + typedef typename std11::conditional< + N == sizeof( typename List::head ), + typename List::head, + typename type_of_size<typename List::tail, N >::type >::type type; +}; + +template< size_t N > +struct type_of_size< nulltype, N > +{ + typedef optional_CONFIG_ALIGN_AS_FALLBACK type; +}; + +template< typename T> +struct struct_t { T _; }; + +#define optional_ALIGN_TYPE( type ) \ + typelist< type , typelist< struct_t< type > + +struct Unknown; + +typedef + optional_ALIGN_TYPE( char ), + optional_ALIGN_TYPE( short ), + optional_ALIGN_TYPE( int ), + optional_ALIGN_TYPE( long ), + optional_ALIGN_TYPE( float ), + optional_ALIGN_TYPE( double ), + optional_ALIGN_TYPE( long double ), + + optional_ALIGN_TYPE( char *), + optional_ALIGN_TYPE( short * ), + optional_ALIGN_TYPE( int * ), + optional_ALIGN_TYPE( long * ), + optional_ALIGN_TYPE( float * ), + optional_ALIGN_TYPE( double * ), + optional_ALIGN_TYPE( long double * ), + + optional_ALIGN_TYPE( Unknown ( * )( Unknown ) ), + optional_ALIGN_TYPE( Unknown * Unknown::* ), + optional_ALIGN_TYPE( Unknown ( Unknown::* )( Unknown ) ), + + nulltype + > > > > > > > > > > > > > > + > > > > > > > > > > > > > > + > > > > > > + alignment_types; + +#undef optional_ALIGN_TYPE + +#endif // optional_CONFIG_MAX_ALIGN_HACK + +/// C++03 constructed union to hold value. + +template< typename T > +union storage_t +{ +//private: +// template< typename > friend class optional; + + typedef T value_type; + + storage_t() optional_is_default + + explicit storage_t( value_type const & v ) + { + construct_value( v ); + } + + void construct_value( value_type const & v ) + { + ::new( value_ptr() ) value_type( v ); + } + +#if optional_CPP11_OR_GREATER + + explicit storage_t( value_type && v ) + { + construct_value( std::move( v ) ); + } + + void construct_value( value_type && v ) + { + ::new( value_ptr() ) value_type( std::move( v ) ); + } + + template< class... Args > + storage_t( nonstd_lite_in_place_t(T), Args&&... args ) + { + emplace( std::forward<Args>(args)... ); + } + + template< class... Args > + void emplace( Args&&... args ) + { + ::new( value_ptr() ) value_type( std::forward<Args>(args)... ); + } + + template< class U, class... Args > + void emplace( std::initializer_list<U> il, Args&&... args ) + { + ::new( value_ptr() ) value_type( il, std::forward<Args>(args)... ); + } + +#endif + + void destruct_value() + { + value_ptr()->~T(); + } + + optional_nodiscard value_type const * value_ptr() const + { + return as<value_type>(); + } + + value_type * value_ptr() + { + return as<value_type>(); + } + + optional_nodiscard value_type const & value() const optional_ref_qual + { + return * value_ptr(); + } + + value_type & value() optional_ref_qual + { + return * value_ptr(); + } + +#if optional_HAVE( REF_QUALIFIER ) + + optional_nodiscard value_type const && value() const optional_refref_qual + { + return std::move( value() ); + } + + value_type && value() optional_refref_qual + { + return std::move( value() ); + } + +#endif + +#if optional_CPP11_OR_GREATER + + using aligned_storage_t = typename std::aligned_storage< sizeof(value_type), alignof(value_type) >::type; + aligned_storage_t data; + +#elif optional_CONFIG_MAX_ALIGN_HACK + + typedef struct { unsigned char data[ sizeof(value_type) ]; } aligned_storage_t; + + max_align_t hack; + aligned_storage_t data; + +#else + typedef optional_ALIGN_AS(value_type) align_as_type; + + typedef struct { align_as_type data[ 1 + ( sizeof(value_type) - 1 ) / sizeof(align_as_type) ]; } aligned_storage_t; + aligned_storage_t data; + +# undef optional_ALIGN_AS + +#endif // optional_CONFIG_MAX_ALIGN_HACK + + optional_nodiscard void * ptr() optional_noexcept + { + return &data; + } + + optional_nodiscard void const * ptr() const optional_noexcept + { + return &data; + } + + template <typename U> + optional_nodiscard U * as() + { + return reinterpret_cast<U*>( ptr() ); + } + + template <typename U> + optional_nodiscard U const * as() const + { + return reinterpret_cast<U const *>( ptr() ); + } +}; + +} // namespace detail + +/// disengaged state tag + +struct nullopt_t +{ + struct init{}; + explicit optional_constexpr nullopt_t( init /*unused*/ ) optional_noexcept {} +}; + +#if optional_HAVE( CONSTEXPR_11 ) +constexpr nullopt_t nullopt{ nullopt_t::init{} }; +#else +// extra parenthesis to prevent the most vexing parse: +const nullopt_t nullopt(( nullopt_t::init() )); +#endif + +/// optional access error + +#if ! optional_CONFIG_NO_EXCEPTIONS + +class bad_optional_access : public std::logic_error +{ +public: + explicit bad_optional_access() + : logic_error( "bad optional access" ) {} +}; + +#endif //optional_CONFIG_NO_EXCEPTIONS + +/// optional + +template< typename T> +class optional +{ + optional_static_assert(( !std::is_same<typename std::remove_cv<T>::type, nullopt_t>::value ), + "T in optional<T> must not be of type 'nullopt_t'.") + + optional_static_assert(( !std::is_same<typename std::remove_cv<T>::type, in_place_t>::value ), + "T in optional<T> must not be of type 'in_place_t'.") + + optional_static_assert(( std::is_object<T>::value && std::is_destructible<T>::value && !std::is_array<T>::value ), + "T in optional<T> must meet the Cpp17Destructible requirements.") + +private: + template< typename > friend class optional; + + typedef void (optional::*safe_bool)() const; + +public: + typedef T value_type; + + // x.x.3.1, constructors + + // 1a - default construct + optional_constexpr optional() optional_noexcept + : has_value_( false ) + , contained() + {} + + // 1b - construct explicitly empty + // NOLINTNEXTLINE( google-explicit-constructor, hicpp-explicit-conversions ) + optional_constexpr optional( nullopt_t /*unused*/ ) optional_noexcept + : has_value_( false ) + , contained() + {} + + // 2 - copy-construct +#if optional_CPP11_OR_GREATER + // template< typename U = T + // optional_REQUIRES_T( + // std::is_copy_constructible<U>::value + // || std11::is_trivially_copy_constructible<U>::value + // ) + // > +#endif + optional_constexpr14 optional( optional const & other ) + : has_value_( other.has_value() ) + { + if ( other.has_value() ) + { + contained.construct_value( other.contained.value() ); + } + } + +#if optional_CPP11_OR_GREATER + + // 3 (C++11) - move-construct from optional + template< typename U = T + optional_REQUIRES_T( + std11::is_move_constructible<U>::value + || std11::is_trivially_move_constructible<U>::value + ) + > + optional_constexpr14 optional( optional && other ) + // NOLINTNEXTLINE( performance-noexcept-move-constructor ) + noexcept( std11::is_nothrow_move_constructible<T>::value ) + : has_value_( other.has_value() ) + { + if ( other.has_value() ) + { + contained.construct_value( std::move( other.contained.value() ) ); + } + } + + // 4a (C++11) - explicit converting copy-construct from optional + template< typename U + optional_REQUIRES_T( + std::is_constructible<T, U const &>::value + && !std::is_constructible<T, optional<U> & >::value + && !std::is_constructible<T, optional<U> && >::value + && !std::is_constructible<T, optional<U> const & >::value + && !std::is_constructible<T, optional<U> const && >::value + && !std::is_convertible< optional<U> & , T>::value + && !std::is_convertible< optional<U> && , T>::value + && !std::is_convertible< optional<U> const & , T>::value + && !std::is_convertible< optional<U> const &&, T>::value + && !std::is_convertible< U const & , T>::value /*=> explicit */ + ) + > + explicit optional( optional<U> const & other ) + : has_value_( other.has_value() ) + { + if ( other.has_value() ) + { + contained.construct_value( T{ other.contained.value() } ); + } + } +#endif // optional_CPP11_OR_GREATER + + // 4b (C++98 and later) - non-explicit converting copy-construct from optional + template< typename U +#if optional_CPP11_OR_GREATER + optional_REQUIRES_T( + std::is_constructible<T, U const &>::value + && !std::is_constructible<T, optional<U> & >::value + && !std::is_constructible<T, optional<U> && >::value + && !std::is_constructible<T, optional<U> const & >::value + && !std::is_constructible<T, optional<U> const && >::value + && !std::is_convertible< optional<U> & , T>::value + && !std::is_convertible< optional<U> && , T>::value + && !std::is_convertible< optional<U> const & , T>::value + && !std::is_convertible< optional<U> const &&, T>::value + && std::is_convertible< U const & , T>::value /*=> non-explicit */ + ) +#endif // optional_CPP11_OR_GREATER + > + // NOLINTNEXTLINE( google-explicit-constructor, hicpp-explicit-conversions ) + /*non-explicit*/ optional( optional<U> const & other ) + : has_value_( other.has_value() ) + { + if ( other.has_value() ) + { + contained.construct_value( other.contained.value() ); + } + } + +#if optional_CPP11_OR_GREATER + + // 5a (C++11) - explicit converting move-construct from optional + template< typename U + optional_REQUIRES_T( + std::is_constructible<T, U &&>::value + && !std::is_constructible<T, optional<U> & >::value + && !std::is_constructible<T, optional<U> && >::value + && !std::is_constructible<T, optional<U> const & >::value + && !std::is_constructible<T, optional<U> const && >::value + && !std::is_convertible< optional<U> & , T>::value + && !std::is_convertible< optional<U> && , T>::value + && !std::is_convertible< optional<U> const & , T>::value + && !std::is_convertible< optional<U> const &&, T>::value + && !std::is_convertible< U &&, T>::value /*=> explicit */ + ) + > + explicit optional( optional<U> && other + ) + : has_value_( other.has_value() ) + { + if ( other.has_value() ) + { + contained.construct_value( T{ std::move( other.contained.value() ) } ); + } + } + + // 5a (C++11) - non-explicit converting move-construct from optional + template< typename U + optional_REQUIRES_T( + std::is_constructible<T, U &&>::value + && !std::is_constructible<T, optional<U> & >::value + && !std::is_constructible<T, optional<U> && >::value + && !std::is_constructible<T, optional<U> const & >::value + && !std::is_constructible<T, optional<U> const && >::value + && !std::is_convertible< optional<U> & , T>::value + && !std::is_convertible< optional<U> && , T>::value + && !std::is_convertible< optional<U> const & , T>::value + && !std::is_convertible< optional<U> const &&, T>::value + && std::is_convertible< U &&, T>::value /*=> non-explicit */ + ) + > + // NOLINTNEXTLINE( google-explicit-constructor, hicpp-explicit-conversions ) + /*non-explicit*/ optional( optional<U> && other ) + : has_value_( other.has_value() ) + { + if ( other.has_value() ) + { + contained.construct_value( std::move( other.contained.value() ) ); + } + } + + // 6 (C++11) - in-place construct + template< typename... Args + optional_REQUIRES_T( + std::is_constructible<T, Args&&...>::value + ) + > + optional_constexpr explicit optional( nonstd_lite_in_place_t(T), Args&&... args ) + : has_value_( true ) + , contained( in_place, std::forward<Args>(args)... ) + {} + + // 7 (C++11) - in-place construct, initializer-list + template< typename U, typename... Args + optional_REQUIRES_T( + std::is_constructible<T, std::initializer_list<U>&, Args&&...>::value + ) + > + optional_constexpr explicit optional( nonstd_lite_in_place_t(T), std::initializer_list<U> il, Args&&... args ) + : has_value_( true ) + , contained( T( il, std::forward<Args>(args)...) ) + {} + + // 8a (C++11) - explicit move construct from value + template< typename U = T + optional_REQUIRES_T( + std::is_constructible<T, U&&>::value + && !std::is_same<typename std20::remove_cvref<U>::type, nonstd_lite_in_place_t(U)>::value + && !std::is_same<typename std20::remove_cvref<U>::type, optional<T>>::value + && !std::is_convertible<U&&, T>::value /*=> explicit */ + ) + > + optional_constexpr explicit optional( U && value ) + : has_value_( true ) + , contained( nonstd_lite_in_place(T), std::forward<U>( value ) ) + {} + + // 8b (C++11) - non-explicit move construct from value + template< typename U = T + optional_REQUIRES_T( + std::is_constructible<T, U&&>::value + && !std::is_same<typename std20::remove_cvref<U>::type, nonstd_lite_in_place_t(U)>::value + && !std::is_same<typename std20::remove_cvref<U>::type, optional<T>>::value + && std::is_convertible<U&&, T>::value /*=> non-explicit */ + ) + > + // NOLINTNEXTLINE( google-explicit-constructor, hicpp-explicit-conversions ) + optional_constexpr /*non-explicit*/ optional( U && value ) + : has_value_( true ) + , contained( nonstd_lite_in_place(T), std::forward<U>( value ) ) + {} + +#else // optional_CPP11_OR_GREATER + + // 8 (C++98) + optional( value_type const & value ) + : has_value_( true ) + , contained( value ) + {} + +#endif // optional_CPP11_OR_GREATER + + // x.x.3.2, destructor + + ~optional() + { + if ( has_value() ) + { + contained.destruct_value(); + } + } + + // x.x.3.3, assignment + + // 1 (C++98and later) - assign explicitly empty + optional & operator=( nullopt_t /*unused*/) optional_noexcept + { + reset(); + return *this; + } + + // 2 (C++98and later) - copy-assign from optional +#if optional_CPP11_OR_GREATER + // NOLINTNEXTLINE( cppcoreguidelines-c-copy-assignment-signature, misc-unconventional-assign-operator ) + optional_REQUIRES_R( + optional &, + true +// std::is_copy_constructible<T>::value +// && std::is_copy_assignable<T>::value + ) + operator=( optional const & other ) + noexcept( + std11::is_nothrow_move_assignable<T>::value + && std11::is_nothrow_move_constructible<T>::value + ) +#else + optional & operator=( optional const & other ) +#endif + { + if ( (has_value() == true ) && (other.has_value() == false) ) { reset(); } + else if ( (has_value() == false) && (other.has_value() == true ) ) { initialize( *other ); } + else if ( (has_value() == true ) && (other.has_value() == true ) ) { contained.value() = *other; } + return *this; + } + +#if optional_CPP11_OR_GREATER + + // 3 (C++11) - move-assign from optional + // NOLINTNEXTLINE( cppcoreguidelines-c-copy-assignment-signature, misc-unconventional-assign-operator ) + optional_REQUIRES_R( + optional &, + true +// std11::is_move_constructible<T>::value +// && std::is_move_assignable<T>::value + ) + operator=( optional && other ) noexcept + { + if ( (has_value() == true ) && (other.has_value() == false) ) { reset(); } + else if ( (has_value() == false) && (other.has_value() == true ) ) { initialize( std::move( *other ) ); } + else if ( (has_value() == true ) && (other.has_value() == true ) ) { contained.value() = std::move( *other ); } + return *this; + } + + // 4 (C++11) - move-assign from value + template< typename U = T > + // NOLINTNEXTLINE( cppcoreguidelines-c-copy-assignment-signature, misc-unconventional-assign-operator ) + optional_REQUIRES_R( + optional &, + std::is_constructible<T , U>::value + && std11::is_assignable<T&, U>::value + && !std::is_same<typename std20::remove_cvref<U>::type, nonstd_lite_in_place_t(U)>::value + && !std::is_same<typename std20::remove_cvref<U>::type, optional<T>>::value + && !(std::is_scalar<T>::value && std::is_same<T, typename std::decay<U>::type>::value) + ) + operator=( U && value ) + { + if ( has_value() ) + { + contained.value() = std::forward<U>( value ); + } + else + { + initialize( T( std::forward<U>( value ) ) ); + } + return *this; + } + +#else // optional_CPP11_OR_GREATER + + // 4 (C++98) - copy-assign from value + template< typename U /*= T*/ > + optional & operator=( U const & value ) + { + if ( has_value() ) contained.value() = value; + else initialize( T( value ) ); + return *this; + } + +#endif // optional_CPP11_OR_GREATER + + // 5 (C++98 and later) - converting copy-assign from optional + template< typename U > +#if optional_CPP11_OR_GREATER + // NOLINTNEXTLINE( cppcoreguidelines-c-copy-assignment-signature, misc-unconventional-assign-operator ) + optional_REQUIRES_R( + optional&, + std::is_constructible< T , U const &>::value + && std11::is_assignable< T&, U const &>::value + && !std::is_constructible<T, optional<U> & >::value + && !std::is_constructible<T, optional<U> && >::value + && !std::is_constructible<T, optional<U> const & >::value + && !std::is_constructible<T, optional<U> const && >::value + && !std::is_convertible< optional<U> & , T>::value + && !std::is_convertible< optional<U> && , T>::value + && !std::is_convertible< optional<U> const & , T>::value + && !std::is_convertible< optional<U> const &&, T>::value + && !std11::is_assignable< T&, optional<U> & >::value + && !std11::is_assignable< T&, optional<U> && >::value + && !std11::is_assignable< T&, optional<U> const & >::value + && !std11::is_assignable< T&, optional<U> const && >::value + ) +#else + optional& +#endif // optional_CPP11_OR_GREATER + operator=( optional<U> const & other ) + { + return *this = optional( other ); + } + +#if optional_CPP11_OR_GREATER + + // 6 (C++11) - converting move-assign from optional + template< typename U > + // NOLINTNEXTLINE( cppcoreguidelines-c-copy-assignment-signature, misc-unconventional-assign-operator ) + optional_REQUIRES_R( + optional&, + std::is_constructible< T , U>::value + && std11::is_assignable< T&, U>::value + && !std::is_constructible<T, optional<U> & >::value + && !std::is_constructible<T, optional<U> && >::value + && !std::is_constructible<T, optional<U> const & >::value + && !std::is_constructible<T, optional<U> const && >::value + && !std::is_convertible< optional<U> & , T>::value + && !std::is_convertible< optional<U> && , T>::value + && !std::is_convertible< optional<U> const & , T>::value + && !std::is_convertible< optional<U> const &&, T>::value + && !std11::is_assignable< T&, optional<U> & >::value + && !std11::is_assignable< T&, optional<U> && >::value + && !std11::is_assignable< T&, optional<U> const & >::value + && !std11::is_assignable< T&, optional<U> const && >::value + ) + operator=( optional<U> && other ) + { + return *this = optional( std::move( other ) ); + } + + // 7 (C++11) - emplace + template< typename... Args + optional_REQUIRES_T( + std::is_constructible<T, Args&&...>::value + ) + > + T& emplace( Args&&... args ) + { + *this = nullopt; + contained.emplace( std::forward<Args>(args)... ); + has_value_ = true; + return contained.value(); + } + + // 8 (C++11) - emplace, initializer-list + template< typename U, typename... Args + optional_REQUIRES_T( + std::is_constructible<T, std::initializer_list<U>&, Args&&...>::value + ) + > + T& emplace( std::initializer_list<U> il, Args&&... args ) + { + *this = nullopt; + contained.emplace( il, std::forward<Args>(args)... ); + has_value_ = true; + return contained.value(); + } + +#endif // optional_CPP11_OR_GREATER + + // x.x.3.4, swap + + void swap( optional & other ) +#if optional_CPP11_OR_GREATER + noexcept( + std11::is_nothrow_move_constructible<T>::value + && std17::is_nothrow_swappable<T>::value + ) +#endif + { + using std::swap; + if ( (has_value() == true ) && (other.has_value() == true ) ) { swap( **this, *other ); } + else if ( (has_value() == false) && (other.has_value() == true ) ) { initialize( std11::move(*other) ); other.reset(); } + else if ( (has_value() == true ) && (other.has_value() == false) ) { other.initialize( std11::move(**this) ); reset(); } + } + + // x.x.3.5, observers + + optional_constexpr value_type const * operator ->() const + { + return assert( has_value() ), + contained.value_ptr(); + } + + optional_constexpr14 value_type * operator ->() + { + return assert( has_value() ), + contained.value_ptr(); + } + + optional_constexpr value_type const & operator *() const optional_ref_qual + { + return assert( has_value() ), + contained.value(); + } + + optional_constexpr14 value_type & operator *() optional_ref_qual + { + return assert( has_value() ), + contained.value(); + } + +#if optional_HAVE( REF_QUALIFIER ) + + optional_constexpr value_type const && operator *() const optional_refref_qual + { + return std::move( **this ); + } + + optional_constexpr14 value_type && operator *() optional_refref_qual + { + return std::move( **this ); + } + +#endif + +#if optional_CPP11_OR_GREATER + optional_constexpr explicit operator bool() const optional_noexcept + { + return has_value(); + } +#else + optional_constexpr operator safe_bool() const optional_noexcept + { + return has_value() ? &optional::this_type_does_not_support_comparisons : 0; + } +#endif + + // NOLINTNEXTLINE( modernize-use-nodiscard ) + /*optional_nodiscard*/ optional_constexpr bool has_value() const optional_noexcept + { + return has_value_; + } + + // NOLINTNEXTLINE( modernize-use-nodiscard ) + /*optional_nodiscard*/ optional_constexpr14 value_type const & value() const optional_ref_qual + { +#if optional_CONFIG_NO_EXCEPTIONS + assert( has_value() ); +#else + if ( ! has_value() ) + { + throw bad_optional_access(); + } +#endif + return contained.value(); + } + + optional_constexpr14 value_type & value() optional_ref_qual + { +#if optional_CONFIG_NO_EXCEPTIONS + assert( has_value() ); +#else + if ( ! has_value() ) + { + throw bad_optional_access(); + } +#endif + return contained.value(); + } + +#if optional_HAVE( REF_QUALIFIER ) && ( !optional_COMPILER_GNUC_VERSION || optional_COMPILER_GNUC_VERSION >= 490 ) + + // NOLINTNEXTLINE( modernize-use-nodiscard ) + /*optional_nodiscard*/ optional_constexpr value_type const && value() const optional_refref_qual + { + return std::move( value() ); + } + + optional_constexpr14 value_type && value() optional_refref_qual + { + return std::move( value() ); + } + +#endif + +#if optional_HAVE( REF_QUALIFIER ) + + template< typename U > + optional_constexpr value_type value_or( U && v ) const optional_ref_qual + { + return has_value() ? contained.value() : static_cast<T>(std::forward<U>( v ) ); + } + + template< typename U > + optional_constexpr14 value_type value_or( U && v ) optional_refref_qual + { +#if optional_COMPILER_CLANG_VERSION + return has_value() ? /*std::move*/( contained.value() ) : static_cast<T>(std::forward<U>( v ) ); +#else + return has_value() ? std::move( contained.value() ) : static_cast<T>(std::forward<U>( v ) ); +#endif + } + +#else + + template< typename U > + optional_constexpr value_type value_or( U const & v ) const + { + return has_value() ? contained.value() : static_cast<value_type>( v ); + } + +#endif // optional_HAVE( REF_QUALIFIER ) + +#if !optional_CONFIG_NO_EXTENSIONS +#if optional_HAVE( REF_QUALIFIER ) + + template< typename F > + optional_constexpr value_type value_or_eval( F f ) const & + { + return has_value() ? contained.value() : f(); + } + + template< typename F > + optional_constexpr14 value_type value_or_eval( F f ) && + { + if ( has_value() ) + { + return std::move( contained.value() ); + } + else + { + return f(); + } + } + +#else + + template< typename F > + optional_constexpr value_type value_or_eval( F f ) const + { + return has_value() ? contained.value() : f(); + } + +#endif // optional_HAVE( REF_QUALIFIER ) +#endif // !optional_CONFIG_NO_EXTENSIONS + + // x.x.3.6, modifiers + + void reset() optional_noexcept + { + if ( has_value() ) + { + contained.destruct_value(); + } + + has_value_ = false; + } + +private: + void this_type_does_not_support_comparisons() const {} + + template< typename V > + void initialize( V const & value ) + { + assert( ! has_value() ); + contained.construct_value( value ); + has_value_ = true; + } + +#if optional_CPP11_OR_GREATER + template< typename V > + void initialize( V && value ) + { + assert( ! has_value() ); + contained.construct_value( std::move( value ) ); + has_value_ = true; + } + +#endif + +private: + bool has_value_; + detail::storage_t< value_type > contained; + +}; + +// Relational operators + +template< typename T, typename U > +optional_nodiscard optional_constexpr bool operator==( optional<T> const & x, optional<U> const & y ) +{ + return bool(x) != bool(y) ? false : !bool( x ) ? true : *x == *y; +} + +template< typename T, typename U > +optional_nodiscard optional_constexpr bool operator!=( optional<T> const & x, optional<U> const & y ) +{ + return !(x == y); +} + +template< typename T, typename U > +optional_nodiscard optional_constexpr bool operator<( optional<T> const & x, optional<U> const & y ) +{ + return (!y) ? false : (!x) ? true : *x < *y; +} + +template< typename T, typename U > +optional_nodiscard optional_constexpr bool operator>( optional<T> const & x, optional<U> const & y ) +{ + return (y < x); +} + +template< typename T, typename U > +optional_nodiscard optional_constexpr bool operator<=( optional<T> const & x, optional<U> const & y ) +{ + return !(y < x); +} + +template< typename T, typename U > +optional_nodiscard optional_constexpr bool operator>=( optional<T> const & x, optional<U> const & y ) +{ + return !(x < y); +} + +// Comparison with nullopt + +template< typename T > +optional_nodiscard optional_constexpr bool operator==( optional<T> const & x, nullopt_t /*unused*/ ) optional_noexcept +{ + return (!x); +} + +template< typename T > +optional_nodiscard optional_constexpr bool operator==( nullopt_t /*unused*/, optional<T> const & x ) optional_noexcept +{ + return (!x); +} + +template< typename T > +optional_nodiscard optional_constexpr bool operator!=( optional<T> const & x, nullopt_t /*unused*/ ) optional_noexcept +{ + return bool(x); +} + +template< typename T > +optional_nodiscard optional_constexpr bool operator!=( nullopt_t /*unused*/, optional<T> const & x ) optional_noexcept +{ + return bool(x); +} + +template< typename T > +optional_nodiscard optional_constexpr bool operator<( optional<T> const & /*unused*/, nullopt_t /*unused*/ ) optional_noexcept +{ + return false; +} + +template< typename T > +optional_nodiscard optional_constexpr bool operator<( nullopt_t /*unused*/, optional<T> const & x ) optional_noexcept +{ + return bool(x); +} + +template< typename T > +optional_nodiscard optional_constexpr bool operator<=( optional<T> const & x, nullopt_t /*unused*/ ) optional_noexcept +{ + return (!x); +} + +template< typename T > +optional_nodiscard optional_constexpr bool operator<=( nullopt_t /*unused*/, optional<T> const & /*unused*/ ) optional_noexcept +{ + return true; +} + +template< typename T > +optional_nodiscard optional_constexpr bool operator>( optional<T> const & x, nullopt_t /*unused*/ ) optional_noexcept +{ + return bool(x); +} + +template< typename T > +optional_nodiscard optional_constexpr bool operator>( nullopt_t /*unused*/, optional<T> const & /*unused*/ ) optional_noexcept +{ + return false; +} + +template< typename T > +optional_nodiscard optional_constexpr bool operator>=( optional<T> const & /*unused*/, nullopt_t /*unused*/ ) optional_noexcept +{ + return true; +} + +template< typename T > +optional_nodiscard optional_constexpr bool operator>=( nullopt_t /*unused*/, optional<T> const & x ) optional_noexcept +{ + return (!x); +} + +// Comparison with T + +template< typename T, typename U > +optional_nodiscard optional_constexpr bool operator==( optional<T> const & x, U const & v ) +{ + return bool(x) ? *x == v : false; +} + +template< typename T, typename U > +optional_nodiscard optional_constexpr bool operator==( U const & v, optional<T> const & x ) +{ + return bool(x) ? v == *x : false; +} + +template< typename T, typename U > +optional_nodiscard optional_constexpr bool operator!=( optional<T> const & x, U const & v ) +{ + return bool(x) ? *x != v : true; +} + +template< typename T, typename U > +optional_nodiscard optional_constexpr bool operator!=( U const & v, optional<T> const & x ) +{ + return bool(x) ? v != *x : true; +} + +template< typename T, typename U > +optional_nodiscard optional_constexpr bool operator<( optional<T> const & x, U const & v ) +{ + return bool(x) ? *x < v : true; +} + +template< typename T, typename U > +optional_nodiscard optional_constexpr bool operator<( U const & v, optional<T> const & x ) +{ + return bool(x) ? v < *x : false; +} + +template< typename T, typename U > +optional_nodiscard optional_constexpr bool operator<=( optional<T> const & x, U const & v ) +{ + return bool(x) ? *x <= v : true; +} + +template< typename T, typename U > +optional_nodiscard optional_constexpr bool operator<=( U const & v, optional<T> const & x ) +{ + return bool(x) ? v <= *x : false; +} + +template< typename T, typename U > +optional_nodiscard optional_constexpr bool operator>( optional<T> const & x, U const & v ) +{ + return bool(x) ? *x > v : false; +} + +template< typename T, typename U > +optional_nodiscard optional_constexpr bool operator>( U const & v, optional<T> const & x ) +{ + return bool(x) ? v > *x : true; +} + +template< typename T, typename U > +optional_nodiscard optional_constexpr bool operator>=( optional<T> const & x, U const & v ) +{ + return bool(x) ? *x >= v : false; +} + +template< typename T, typename U > +optional_nodiscard optional_constexpr bool operator>=( U const & v, optional<T> const & x ) +{ + return bool(x) ? v >= *x : true; +} + +// Specialized algorithms + +template< typename T +#if optional_CPP11_OR_GREATER + optional_REQUIRES_T( + std11::is_move_constructible<T>::value + && std17::is_swappable<T>::value ) +#endif +> +void swap( optional<T> & x, optional<T> & y ) +#if optional_CPP11_OR_GREATER + noexcept( noexcept( x.swap(y) ) ) +#endif +{ + x.swap( y ); +} + +#if optional_CPP11_OR_GREATER + +template< typename T > +optional_constexpr optional< typename std::decay<T>::type > make_optional( T && value ) +{ + return optional< typename std::decay<T>::type >( std::forward<T>( value ) ); +} + +template< typename T, typename...Args > +optional_constexpr optional<T> make_optional( Args&&... args ) +{ + return optional<T>( nonstd_lite_in_place(T), std::forward<Args>(args)...); +} + +template< typename T, typename U, typename... Args > +optional_constexpr optional<T> make_optional( std::initializer_list<U> il, Args&&... args ) +{ + return optional<T>( nonstd_lite_in_place(T), il, std::forward<Args>(args)...); +} + +#else + +template< typename T > +optional<T> make_optional( T const & value ) +{ + return optional<T>( value ); +} + +#endif // optional_CPP11_OR_GREATER + +} // namespace optional_lite + +using optional_lite::optional; +using optional_lite::nullopt_t; +using optional_lite::nullopt; + +#if ! optional_CONFIG_NO_EXCEPTIONS +using optional_lite::bad_optional_access; +#endif + +using optional_lite::make_optional; + +} // namespace nonstd + +#if optional_CPP11_OR_GREATER + +// specialize the std::hash algorithm: + +namespace std { + +template< class T > +struct hash< nonstd::optional<T> > +{ +public: + std::size_t operator()( nonstd::optional<T> const & v ) const optional_noexcept + { + return bool( v ) ? std::hash<T>{}( *v ) : 0; + } +}; + +} //namespace std + +#endif // optional_CPP11_OR_GREATER + +#if defined(__clang__) +# pragma clang diagnostic pop +#elif defined(__GNUC__) +# pragma GCC diagnostic pop +#elif defined(_MSC_VER ) +# pragma warning( pop ) +#endif + +#endif // optional_USES_STD_OPTIONAL + +#endif // NONSTD_OPTIONAL_LITE_HPP diff --git a/Build/source/utils/asymptote/LspCpp/LibLsp/JsonRpc/serializer.cpp b/Build/source/utils/asymptote/LspCpp/LibLsp/JsonRpc/serializer.cpp new file mode 100644 index 00000000000..356d803b5d8 --- /dev/null +++ b/Build/source/utils/asymptote/LspCpp/LibLsp/JsonRpc/serializer.cpp @@ -0,0 +1,214 @@ +#include "serializer.h" +#include <stdexcept> +#include <rapidjson/allocators.h> +#include "json.h" + + + +//// Elementary types + +void JsonNull::swap(JsonNull& arg) noexcept +{ +} + + +void Reflect(Reader& visitor, uint8_t& value) { + if (!visitor.IsInt()) + throw std::invalid_argument("uint8_t"); + value = (uint8_t)visitor.GetInt(); +} +void Reflect(Writer& visitor, uint8_t& value) { + visitor.Int(value); +} + +void Reflect(Reader& visitor, short& value) { + if (!visitor.IsInt()) + throw std::invalid_argument("short"); + value = (short)visitor.GetInt(); +} +void Reflect(Writer& visitor, short& value) { + visitor.Int(value); +} + +void Reflect(Reader& visitor, unsigned short& value) { + if (!visitor.IsInt()) + throw std::invalid_argument("unsigned short"); + value = (unsigned short)visitor.GetInt(); +} +void Reflect(Writer& visitor, unsigned short& value) { + visitor.Int(value); +} + +void Reflect(Reader& visitor, int& value) { + if (!visitor.IsInt()) + throw std::invalid_argument("int"); + value = visitor.GetInt(); +} +void Reflect(Writer& visitor, int& value) { + visitor.Int(value); +} + +void Reflect(Reader& visitor, unsigned& value) { + if (!visitor.IsUint64()) + throw std::invalid_argument("unsigned"); + value = visitor.GetUint32(); +} +void Reflect(Writer& visitor, unsigned& value) { + visitor.Uint32(value); +} + +void Reflect(Reader& visitor, long& value) { + if (!visitor.IsInt64()) + throw std::invalid_argument("long"); + value = long(visitor.GetInt64()); +} +void Reflect(Writer& visitor, long& value) { + visitor.Int64(value); +} + +void Reflect(Reader& visitor, unsigned long& value) { + if (!visitor.IsUint64()) + throw std::invalid_argument("unsigned long"); + value = (unsigned long)visitor.GetUint64(); +} +void Reflect(Writer& visitor, unsigned long& value) { + visitor.Uint64(value); +} + +void Reflect(Reader& visitor, long long& value) { + if (!visitor.IsInt64()) + throw std::invalid_argument("long long"); + value = visitor.GetInt64(); +} +void Reflect(Writer& visitor, long long& value) { + visitor.Int64(value); +} + +void Reflect(Reader& visitor, unsigned long long& value) { + if (!visitor.IsUint64()) + throw std::invalid_argument("unsigned long long"); + value = visitor.GetUint64(); +} +void Reflect(Writer& visitor, unsigned long long& value) { + visitor.Uint64(value); +} + +void Reflect(Reader& visitor, double& value) { + if (!visitor.IsNumber()) + throw std::invalid_argument("double"); + value = visitor.GetDouble(); +} +void Reflect(Writer& visitor, double& value) { + visitor.Double(value); +} + +void Reflect(Reader& visitor, bool& value) { + if (!visitor.IsBool()) + throw std::invalid_argument("bool"); + value = visitor.GetBool(); +} +void Reflect(Writer& visitor, bool& value) { + visitor.Bool(value); +} + +void Reflect(Reader& visitor, std::string& value) { + if (!visitor.IsString()) + throw std::invalid_argument("std::string"); + value = visitor.GetString(); +} +void Reflect(Writer& visitor, std::string& value) { + visitor.String(value.c_str(), (rapidjson::SizeType)value.size()); +} + +void Reflect(Reader& visitor, JsonNull& value) { + visitor.GetNull(); +} + +void Reflect(Writer& visitor, JsonNull& value) { + visitor.Null(); +} + + +void Reflect(Reader& visitor, SerializeFormat& value) { + std::string fmt = visitor.GetString(); + value = fmt[0] == 'm' ? SerializeFormat::MessagePack : SerializeFormat::Json; +} + +void Reflect(Writer& visitor, SerializeFormat& value) { + switch (value) { + case SerializeFormat::Json: + visitor.String("json"); + break; + case SerializeFormat::MessagePack: + visitor.String("msgpack"); + break; + } +} + + +std::string JsonReader::ToString() const +{ + rapidjson::StringBuffer strBuf; + strBuf.Clear(); + rapidjson::Writer<rapidjson::StringBuffer> writer(strBuf); + m_->Accept(writer); + std::string strJson = strBuf.GetString(); + return strJson; +} + +void JsonReader::IterMap(std::function<void(const char*, Reader&)> fn) +{ + path_.push_back("0"); + for (auto& entry : m_->GetObject()) + { + auto saved = m_; + m_ = &(entry.value); + + fn(entry.name.GetString(), *this); + m_ = saved; + } + path_.pop_back(); +} + + void JsonReader::IterArray(std::function<void(Reader&)> fn) +{ + if (!m_->IsArray()) + throw std::invalid_argument("array"); + // Use "0" to indicate any element for now. + path_.push_back("0"); + for (auto& entry : m_->GetArray()) + { + auto saved = m_; + m_ = &entry; + fn(*this); + m_ = saved; + } + path_.pop_back(); +} + +void JsonReader::DoMember(const char* name, std::function<void(Reader&)> fn) +{ + path_.push_back(name); + auto it = m_->FindMember(name); + if (it != m_->MemberEnd()) + { + auto saved = m_; + m_ = &it->value; + fn(*this); + m_ = saved; + } + path_.pop_back(); +} + +std::string JsonReader::GetPath() const +{ + std::string ret; + for (auto& t : path_) + { + ret += '/'; + ret += t; + } + ret.pop_back(); + return ret; +} + diff --git a/Build/source/utils/asymptote/LspCpp/LibLsp/JsonRpc/serializer.h b/Build/source/utils/asymptote/LspCpp/LibLsp/JsonRpc/serializer.h new file mode 100644 index 00000000000..10456f40b5a --- /dev/null +++ b/Build/source/utils/asymptote/LspCpp/LibLsp/JsonRpc/serializer.h @@ -0,0 +1,378 @@ +#pragma once + + +#include <macro_map.h> +#ifdef boost +#include "optional.hpp" +#else +#include <boost/optional.hpp> +#endif +#include <cassert> +#include <memory> +#include <string> +#include <type_traits> +#include <vector> +#include <functional> +#include <map> +#include <algorithm> + + +struct AbsolutePath; + +enum class SerializeFormat { Json, MessagePack }; + +// A tag type that can be used to write `null` to json. +struct JsonNull +{ + void swap(JsonNull& arg) noexcept; +}; + + + +class Reader { +public: + virtual ~Reader() {} + virtual SerializeFormat Format() const = 0; + + virtual bool IsBool() = 0; + virtual bool IsNull() = 0; + virtual bool IsArray() = 0; + virtual bool IsInt() = 0; + virtual bool IsInt64() = 0; + virtual bool IsUint64() = 0; + virtual bool IsDouble() = 0; + virtual bool IsNumber() = 0; + virtual bool IsString() = 0; + + virtual void GetNull() = 0; + virtual bool GetBool() = 0; + virtual int GetInt() = 0; + virtual uint32_t GetUint32() = 0; + virtual int64_t GetInt64() = 0; + virtual uint64_t GetUint64() = 0; + virtual double GetDouble() = 0; + virtual std::string GetString() = 0; + + virtual bool HasMember(const char* x) = 0; + virtual std::unique_ptr<Reader> operator[](const char* x) = 0; + virtual void IterMap( std::function<void(const char*, Reader&)> fn) = 0; + virtual void IterArray(std::function<void(Reader&)> fn) = 0; + virtual void DoMember(const char* name, std::function<void(Reader&)> fn) = 0; + virtual std::string ToString() const = 0; +}; + + + +class Writer { +public: + virtual ~Writer() {} + virtual SerializeFormat Format() const = 0; + + virtual void Null() = 0; + virtual void Bool(bool x) = 0; + virtual void Int(int x) = 0; + virtual void Uint32(uint32_t x) = 0; + virtual void Int64(int64_t x) = 0; + virtual void Uint64(uint64_t x) = 0; + virtual void Double(double x) = 0; + virtual void String(const char* x) = 0; + virtual void String(const char* x, size_t len) = 0; + virtual void StartArray(size_t) = 0; + virtual void EndArray() = 0; + virtual void StartObject() = 0; + virtual void EndObject() = 0; + virtual void Key(const char* name) = 0; +}; + + + +struct optionals_mandatory_tag {}; + +#define REFLECT_MEMBER_START() ReflectMemberStart(visitor, value) +#define REFLECT_MEMBER_END() ReflectMemberEnd(visitor, value); +#define REFLECT_MEMBER_END1(value) ReflectMemberEnd(visitor, value); +#define REFLECT_MEMBER(name) ReflectMember(visitor, #name, value.name) +#define REFLECT_MEMBER_OPTIONALS(name) \ + ReflectMember(visitor, #name, value.name, optionals_mandatory_tag{}) +#define REFLECT_MEMBER2(name, value) ReflectMember(visitor, name, value) + +#define MAKE_REFLECT_TYPE_PROXY(type_name) \ + MAKE_REFLECT_TYPE_PROXY2(type_name, std::underlying_type<type_name>::type) +#define MAKE_REFLECT_TYPE_PROXY2(type, as_type) \ + inline void Reflect(Reader& visitor, type& value) { \ + as_type value0; \ + ::Reflect(visitor, value0); \ + value = static_cast<type>(value0); \ + } \ + inline void Reflect(Writer& visitor, type& value) { \ + auto value0 = static_cast<as_type>(value); \ + ::Reflect(visitor, value0); \ + } + +#define _MAPPABLE_REFLECT_MEMBER(name) REFLECT_MEMBER(name); +#define _MAPPABLE_REFLECT_MEMBER_OPTIONALS(name) REFLECT_MEMBER_OPTIONALS(name); + +#define MAKE_REFLECT_EMPTY_STRUCT(type, ...) \ + template <typename TVisitor> \ + void Reflect(TVisitor& visitor, type& value) { \ + REFLECT_MEMBER_START(); \ + REFLECT_MEMBER_END(); \ + } + +#define MAKE_REFLECT_STRUCT(type, ...) \ + template <typename TVisitor> \ + void Reflect(TVisitor& visitor, type& value) { \ + REFLECT_MEMBER_START(); \ + MACRO_MAP(_MAPPABLE_REFLECT_MEMBER, __VA_ARGS__) \ + REFLECT_MEMBER_END(); \ + } + + +#define _MAPPABLE_SWAP_MEMBER(name) std::swap(name,arg.name); + +#define MAKE_SWAP_METHOD(type, ...) \ +void swap(type& arg) noexcept{ \ + MACRO_MAP(_MAPPABLE_SWAP_MEMBER, __VA_ARGS__) \ +} + +#define MAKE_REFLECT_STRUCT_OPTIONALS_MANDATORY(type, ...) \ + template <typename TVisitor> \ + void Reflect(TVisitor& visitor, type& value) { \ + REFLECT_MEMBER_START(); \ + MACRO_MAP(_MAPPABLE_REFLECT_MEMBER_OPTIONALS, __VA_ARGS__) \ + REFLECT_MEMBER_END(); \ + } + +// clang-format off +// Config has many fields, we need to support at least its number of fields. +#define NUM_VA_ARGS_IMPL(_1,_2,_3,_4,_5,_6,_7,_8,_9,_10,_11,_12,_13,_14,_15,_16,_17,_18,_19,_20,_21,_22,_23,_24,_25,_26,_27,_28,_29,_30,N,...) N +#define NUM_VA_ARGS(...) NUM_VA_ARGS_IMPL(__VA_ARGS__,30,29,28,27,26,25,24,23,22,21,20,19,18,17,16,15,14,13,12,11,10,9,8,7,6,5,4,3,2,1) +// clang-format on + +#define _MAPPABLE_REFLECT_ARRAY(name) Reflect(visitor, value.name); + +// Reflects the struct so it is serialized as an array instead of an object. +// This currently only supports writers. +#define MAKE_REFLECT_STRUCT_WRITER_AS_ARRAY(type, ...) \ + inline void Reflect(Writer& visitor, type& value) { \ + visitor.StartArray(NUM_VA_ARGS(__VA_ARGS__)); \ + MACRO_MAP(_MAPPABLE_REFLECT_ARRAY, __VA_ARGS__) \ + visitor.EndArray(); \ + } + +//// Elementary types + +void Reflect(Reader& visitor, uint8_t& value); +void Reflect(Writer& visitor, uint8_t& value); + +void Reflect(Reader& visitor, short& value); +void Reflect(Writer& visitor, short& value); + +void Reflect(Reader& visitor, unsigned short& value); +void Reflect(Writer& visitor, unsigned short& value); + +void Reflect(Reader& visitor, int& value); +void Reflect(Writer& visitor, int& value); + +void Reflect(Reader& visitor, unsigned& value); +void Reflect(Writer& visitor, unsigned& value); + +void Reflect(Reader& visitor, long& value); +void Reflect(Writer& visitor, long& value); + +void Reflect(Reader& visitor, unsigned long& value); +void Reflect(Writer& visitor, unsigned long& value); + +void Reflect(Reader& visitor, long long& value); +void Reflect(Writer& visitor, long long& value); + +void Reflect(Reader& visitor, unsigned long long& value); +void Reflect(Writer& visitor, unsigned long long& value); + +void Reflect(Reader& visitor, double& value); +void Reflect(Writer& visitor, double& value); + +void Reflect(Reader& visitor, bool& value); +void Reflect(Writer& visitor, bool& value); + +void Reflect(Reader& visitor, std::string& value); +void Reflect(Writer& visitor, std::string& value); + +void Reflect(Reader& visitor, JsonNull& value); +void Reflect(Writer& visitor, JsonNull& value); + +void Reflect(Reader& visitor, SerializeFormat& value); +void Reflect(Writer& visitor, SerializeFormat& value); + +//// Type constructors + +template <typename T> +void Reflect(Reader& visitor, boost::optional<T>& value) { + if (visitor.IsNull()) { + visitor.GetNull(); + return; + } + T real_value; + Reflect(visitor, real_value); + value = std::move(real_value); +} +template <typename T> +void Reflect(Writer& visitor, boost::optional<T>& value) { + if (value) + Reflect(visitor, *value); + else + visitor.Null(); +} + + +template <typename T> +void ReflectMember(Writer& visitor, const char* name, boost::optional<T>& value) { + // For TypeScript optional property key?: value in the spec, + // We omit both key and value if value is std::nullopt (null) for JsonWriter + // to reduce output. But keep it for other serialization formats. + if (value || visitor.Format() != SerializeFormat::Json) { + visitor.Key(name); + Reflect(visitor, value); + } +} + + + +template <typename T> +void ReflectMember(Writer& visitor, + const char* name, + T& value, + optionals_mandatory_tag) { + visitor.Key(name); + Reflect(visitor, value); +} +template <typename T> +void ReflectMember(Reader& visitor, + const char* name, + T& value, + optionals_mandatory_tag) { + Reflect(visitor, value); +} + +template<class T > +void Reflect(Reader& visitor, std::map<std::string, T>& value) +{ + visitor.IterMap([&](const char* name,Reader& entry) { + T entry_value; + Reflect(entry, entry_value); + value[name]=(std::move(entry_value)); + }); +} +template<class _Ty > +void Reflect(Writer& visitor, std::map<std::string, _Ty>& value) +{ + REFLECT_MEMBER_START(); + for (auto& it : value) + { + visitor.Key(it.first.c_str()); + Reflect(visitor, it.second); + } + REFLECT_MEMBER_END(); +} + +// std::vector +template <typename T> +void Reflect(Reader& visitor, std::vector<T>& values) { + visitor.IterArray([&](Reader& entry) { + T entry_value; + Reflect(entry, entry_value); + values.push_back(std::move(entry_value)); + }); +} + + +template <typename T> +void Reflect(Writer& visitor, std::vector<T>& values) { + visitor.StartArray(values.size()); + for (auto& value : values) + Reflect(visitor, value); + visitor.EndArray(); +} + +// ReflectMember + +inline void DefaultReflectMemberStart(Writer& visitor) { + visitor.StartObject(); +} +inline void DefaultReflectMemberStart(Reader& visitor) {} + +template <typename T> +bool ReflectMemberStart(Reader& visitor, T& value) { + return false; +} +template <typename T> +bool ReflectMemberStart(Writer& visitor, T& value) { + visitor.StartObject(); + return true; +} + +template <typename T> +void ReflectMemberEnd(Reader& visitor, T& value) {} +template <typename T> +void ReflectMemberEnd(Writer& visitor, T& value) { + visitor.EndObject(); +} + +template <typename T> +void ReflectMember(Reader& visitor, const char* name, T& value) { + visitor.DoMember(name, [&](Reader& child) { Reflect(child, value); }); +} +template <typename T> +void ReflectMember(Writer& visitor, const char* name, T& value) { + visitor.Key(name); + Reflect(visitor, value); +} + +template<class _Ty1, class _Ty2> +void Reflect(Writer& visitor, std::pair< boost::optional<_Ty1>, boost::optional<_Ty2> >& value) +{ + if (value.first) + { + Reflect(visitor, value.first); + } + else + { + Reflect(visitor, value.second); + } +} +template<class _Ty2> +void Reflect(Reader& visitor, std::pair< boost::optional<bool>, boost::optional<_Ty2> >& value) +{ + if(visitor.IsBool()) + { + Reflect(visitor, value.first); + return; + } + + Reflect(visitor, value.second); +} +template<class _Ty2> +void Reflect(Reader& visitor, std::pair< boost::optional<std::string>, boost::optional<_Ty2> >& value) +{ + if (visitor.IsString()) + { + Reflect(visitor, value.first); + return; + } + + Reflect(visitor, value.second); +} + + +template<class _Ty1, class _Ty2> +void Reflect(Reader& visitor, std::pair< boost::optional<_Ty1>, boost::optional<_Ty2> >& value) +{ + try + { + Reflect(visitor, value.second); + } + catch (...) + { + Reflect(visitor, value.first); + } +} diff --git a/Build/source/utils/asymptote/LspCpp/LibLsp/JsonRpc/stream.h b/Build/source/utils/asymptote/LspCpp/LibLsp/JsonRpc/stream.h new file mode 100644 index 00000000000..549c361950a --- /dev/null +++ b/Build/source/utils/asymptote/LspCpp/LibLsp/JsonRpc/stream.h @@ -0,0 +1,196 @@ +#pragma once +#include <mutex> +#include <string> +namespace lsp +{ + class stream + { + public: + virtual ~stream() = default; + virtual bool fail() = 0; + virtual bool bad() = 0; + virtual bool eof() = 0; + virtual bool good() = 0; + virtual void clear() = 0; + virtual std::string what() = 0; + virtual bool need_to_clear_the_state() + { + return false; + } + + bool operator!() + { + return bad(); + } + }; + class istream : public stream + { + public: + virtual int get() = 0; + virtual ~istream() = default; + virtual istream& read(char* str, std::streamsize count) = 0; + }; + template <class T > + class base_istream : public istream + { + public: + explicit base_istream(T& _t) :_impl(_t) + { + + } + + int get() override + { + return _impl.get(); + } + bool fail() override + { + return _impl.fail(); + } + bool bad() override + { + return _impl.bad(); + } + bool eof() override + { + return _impl.eof(); + } + bool good() override + { + return _impl.good(); + } + istream& read(char* str, std::streamsize count) override + { + _impl.read(str, count); + return *this; + } + + void clear() override + { + _impl.clear(); + } + T& _impl; + }; + class ostream : public stream + { + public: + virtual ~ostream() = default; + + virtual ostream& write(const std::string&) = 0; + virtual ostream& write(std::streamsize) = 0; + virtual ostream& flush() = 0; + + }; + template <class T > + class base_ostream : public ostream + { + public: + explicit base_ostream(T& _t) :_impl(_t) + { + + } + + bool fail() override + { + return _impl.fail(); + } + bool good() override + { + return _impl.good(); + } + bool bad() override + { + return _impl.bad(); + } + bool eof() override + { + return _impl.eof(); + } + + ostream& write(const std::string& c) override + { + _impl << c; + return *this; + } + + ostream& write(std::streamsize _s) override + { + + _impl << std::to_string(_s); + return *this; + } + + ostream& flush() override + { + _impl.flush(); + return *this; + } + + void clear() override + { + _impl.clear(); + } + protected: + T& _impl; + }; + + template <class T > + class base_iostream : public istream, public ostream + { + public: + explicit base_iostream(T& _t) :_impl(_t) + { + + } + + int get() override + { + return _impl.get(); + } + bool fail() override + { + return _impl.fail(); + } + bool bad() override + { + return _impl.bad(); + } + bool eof() override + { + return _impl.eof(); + } + bool good() override + { + return _impl.good(); + } + istream& read(char* str, std::streamsize count) override + { + _impl.read(str, count); + return *this; + } + ostream& write(const std::string& c) override + { + _impl << c; + return *this; + } + + ostream& write(std::streamsize _s) override + { + _impl << std::to_string(_s); + return *this; + } + + ostream& flush() override + { + _impl.flush(); + return *this; + } + + void clear() override + { + _impl.clear(); + } + protected: + T& _impl; + }; +} diff --git a/Build/source/utils/asymptote/LspCpp/LibLsp/JsonRpc/threaded_queue.cpp b/Build/source/utils/asymptote/LspCpp/LibLsp/JsonRpc/threaded_queue.cpp new file mode 100644 index 00000000000..17e965eadf1 --- /dev/null +++ b/Build/source/utils/asymptote/LspCpp/LibLsp/JsonRpc/threaded_queue.cpp @@ -0,0 +1,20 @@ +#include "threaded_queue.h" + +// static +bool MultiQueueWaiter::HasState( + std::initializer_list<BaseThreadQueue*> queues) { + for (BaseThreadQueue* queue : queues) { + if (!queue->IsEmpty()) + return true; + } + return false; +} + +bool MultiQueueWaiter::ValidateWaiter( + std::initializer_list<BaseThreadQueue*> queues) { + for (BaseThreadQueue* queue : queues) { + if (queue->waiter.get() != this) + return false; + } + return true; +} diff --git a/Build/source/utils/asymptote/LspCpp/LibLsp/JsonRpc/threaded_queue.h b/Build/source/utils/asymptote/LspCpp/LibLsp/JsonRpc/threaded_queue.h new file mode 100644 index 00000000000..cca9f9a486a --- /dev/null +++ b/Build/source/utils/asymptote/LspCpp/LibLsp/JsonRpc/threaded_queue.h @@ -0,0 +1,249 @@ +#pragma once + +#include <boost/optional/optional.hpp> +#include <algorithm> +#include <atomic> +#include <condition_variable> +#include <deque> +#include <memory> +#include <mutex> +#include <tuple> +#include <utility> +#include <vector> + + +struct MultiQueueWaiter; + +struct BaseThreadQueue { + virtual ~BaseThreadQueue() = default; + + virtual bool IsEmpty() = 0; + + std::shared_ptr<MultiQueueWaiter> waiter; +}; + +// std::lock accepts two or more arguments. We define an overload for one +// argument. +namespace std { +template <typename Lockable> +void lock(Lockable& l) { + l.lock(); +} +} // namespace std + +template <typename... Queue> +struct MultiQueueLock { + MultiQueueLock(Queue... lockable) : tuple_{lockable...} { lock(); } + ~MultiQueueLock() { unlock(); } + void lock() { lock_impl(typename std::index_sequence_for<Queue...>{}); } + void unlock() { unlock_impl(typename std::index_sequence_for<Queue...>{}); } + + private: + template <size_t... Is> + void lock_impl(std::index_sequence<Is...>) { + std::lock(std::get<Is>(tuple_)->mutex...); + } + + template <size_t... Is> + void unlock_impl(std::index_sequence<Is...>) { + (void)std::initializer_list<int>{ + (std::get<Is>(tuple_)->mutex.unlock(), 0)...}; + } + + std::tuple<Queue...> tuple_; +}; + +struct MultiQueueWaiter { + static bool HasState(std::initializer_list<BaseThreadQueue*> queues); + + bool ValidateWaiter(std::initializer_list<BaseThreadQueue*> queues); + + template <typename... BaseThreadQueue> + bool Wait(std::atomic<bool>& quit, BaseThreadQueue... queues) { + MultiQueueLock<BaseThreadQueue...> l(queues...); + while (!quit.load(std::memory_order_relaxed)) { + if (HasState({ queues... })) + return false; + cv.wait(l); + } + return true; + } + template <typename... BaseThreadQueue> + void WaitUntil(std::chrono::steady_clock::time_point t, + BaseThreadQueue... queues) { + MultiQueueLock<BaseThreadQueue...> l(queues...); + if (!HasState({ queues... })) + cv.wait_until(l, t); + } + template <typename... BaseThreadQueue> + void Wait(BaseThreadQueue... queues) { + assert(ValidateWaiter({queues...})); + + MultiQueueLock<BaseThreadQueue...> l(queues...); + while (!HasState({queues...})) + cv.wait(l); + } + + std::condition_variable_any cv; +}; + +// A threadsafe-queue. http://stackoverflow.com/a/16075550 +template <class T> +struct ThreadedQueue : public BaseThreadQueue { + public: + ThreadedQueue() : ThreadedQueue(std::make_shared<MultiQueueWaiter>()) {} + + explicit ThreadedQueue(std::shared_ptr<MultiQueueWaiter> waiter) + : total_count_(0) { + this->waiter = waiter; + } + + // Returns the number of elements in the queue. This is lock-free. + size_t Size() const { return total_count_; } + + // Add an element to the queue. + void Enqueue(T&& t, bool priority) { + { + std::lock_guard<std::mutex> lock(mutex); + if (priority) + priority_.push_back(std::move(t)); + else + queue_.push_back(std::move(t)); + ++total_count_; + } + waiter->cv.notify_one(); + } + + // Add a set of elements to the queue. + void EnqueueAll(std::vector<T>&& elements, bool priority) { + if (elements.empty()) + return; + + { + std::lock_guard<std::mutex> lock(mutex); + total_count_ += elements.size(); + for (T& element : elements) { + if (priority) + priority_.push_back(std::move(element)); + else + queue_.push_back(std::move(element)); + } + elements.clear(); + } + + waiter->cv.notify_all(); + } + + // Returns true if the queue is empty. This is lock-free. + bool IsEmpty() { return total_count_ == 0; } + + // Get the first element from the queue. Blocks until one is available. + T Dequeue() { + std::unique_lock<std::mutex> lock(mutex); + waiter->cv.wait(lock, + [&]() { return !priority_.empty() || !queue_.empty(); }); + + auto execute = [&](std::deque<T>* q) { + auto val = std::move(q->front()); + q->pop_front(); + --total_count_; + return std::move(val); + }; + if (!priority_.empty()) + return execute(&priority_); + return execute(&queue_); + } + + // Get the first element from the queue without blocking. Returns a null + // value if the queue is empty. + boost::optional<T> TryDequeue(bool priority) { + std::lock_guard<std::mutex> lock(mutex); + + auto pop = [&](std::deque<T>* q) { + auto val = std::move(q->front()); + q->pop_front(); + --total_count_; + return std::move(val); + }; + + auto get_result = [&](std::deque<T>* first, + std::deque<T>* second) -> boost::optional<T> { + if (!first->empty()) + return pop(first); + if (!second->empty()) + return pop(second); + return {}; + }; + + if (priority) + return get_result(&priority_, &queue_); + return get_result(&queue_, &priority_); + } + // Return all elements in the queue. + std::vector<T> DequeueAll() { + std::lock_guard<std::mutex> lock(mutex); + + total_count_ = 0; + + std::vector<T> result; + result.reserve(priority_.size() + queue_.size()); + while (!priority_.empty()) { + result.emplace_back(std::move(priority_.front())); + priority_.pop_front(); + } + while (!queue_.empty()) { + result.emplace_back(std::move(queue_.front())); + queue_.pop_front(); + } + + return result; + } + std::vector<T> TryDequeueSome(size_t num) { + std::lock_guard<std::mutex> lock(mutex); + + std::vector<T> result; + num = std::min(num, priority_.size() + queue_.size()); + total_count_ -= num; + result.reserve(num); + while (num) + { + if(!priority_.empty()) { + result.emplace_back(std::move(priority_.front())); + priority_.pop_front(); + } + else + { + break; + } + num -= 1; + } + while (num) + { + if (!queue_.empty()) { + result.emplace_back(std::move(queue_.front())); + queue_.pop_front(); + } + else + { + break; + } + num -= 1; + } + return result; + } + template <typename Fn> + void Iterate(Fn fn) { + std::lock_guard<std::mutex> lock(mutex); + for (auto& entry : priority_) + fn(entry); + for (auto& entry : queue_) + fn(entry); + } + + mutable std::mutex mutex; + + private: + std::atomic<int> total_count_; + std::deque<T> priority_; + std::deque<T> queue_; +}; diff --git a/Build/source/utils/asymptote/LspCpp/LibLsp/JsonRpc/traits.h b/Build/source/utils/asymptote/LspCpp/LibLsp/JsonRpc/traits.h new file mode 100644 index 00000000000..ce8905a8405 --- /dev/null +++ b/Build/source/utils/asymptote/LspCpp/LibLsp/JsonRpc/traits.h @@ -0,0 +1,158 @@ +// Copyright 2021 Google LLC +// +// Licensed under the Apache License, Version 2.0 (the "License"); +// you may not use this file except in compliance with the License. +// You may obtain a copy of the License at +// +// https://www.apache.org/licenses/LICENSE-2.0 +// +// Unless required by applicable law or agreed to in writing, software +// distributed under the License is distributed on an "AS IS" BASIS, +// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +// See the License for the specific language governing permissions and +// limitations under the License. + +#pragma once + + +#include <tuple> +#include <type_traits> + +namespace lsp { +namespace traits { + +// NthTypeOf returns the `N`th type in `Types` +template <int N, typename... Types> +using NthTypeOf = typename std::tuple_element<N, std::tuple<Types...>>::type; + +// `IsTypeOrDerived<BASE, T>::value` is true iff `T` is of type `BASE`, or +// derives from `BASE`. +template <typename BASE, typename T> +using IsTypeOrDerived = std::integral_constant< + bool, + std::is_base_of<BASE, typename std::decay<T>::type>::value || + std::is_same<BASE, typename std::decay<T>::type>::value>; + +// `EachIsTypeOrDerived<N, BASES, TYPES>::value` is true iff all of the types in +// the std::tuple `TYPES` is of, or derives from the corresponding indexed type +// in the std::tuple `BASES`. +// `N` must be equal to the number of types in both the std::tuple `BASES` and +// `TYPES`. +template <int N, typename BASES, typename TYPES> +struct EachIsTypeOrDerived { + using base = typename std::tuple_element<N - 1, BASES>::type; + using type = typename std::tuple_element<N - 1, TYPES>::type; + using last_matches = IsTypeOrDerived<base, type>; + using others_match = EachIsTypeOrDerived<N - 1, BASES, TYPES>; + static constexpr bool value = last_matches::value && others_match::value; +}; + +// EachIsTypeOrDerived specialization for N = 1 +template <typename BASES, typename TYPES> +struct EachIsTypeOrDerived<1, BASES, TYPES> { + using base = typename std::tuple_element<0, BASES>::type; + using type = typename std::tuple_element<0, TYPES>::type; + static constexpr bool value = IsTypeOrDerived<base, type>::value; +}; + +// EachIsTypeOrDerived specialization for N = 0 +template <typename BASES, typename TYPES> +struct EachIsTypeOrDerived<0, BASES, TYPES> { + static constexpr bool value = true; +}; + +// Signature describes the signature of a function. +template <typename RETURN, typename... PARAMETERS> +struct Signature { + // The return type of the function signature + using ret = RETURN; + // The parameters of the function signature held in a std::tuple + using parameters = std::tuple<PARAMETERS...>; + // The type of the Nth parameter of function signature + template <std::size_t N> + using parameter = NthTypeOf<N, PARAMETERS...>; + // The total number of parameters + static constexpr std::size_t parameter_count = sizeof...(PARAMETERS); +}; + +// SignatureOf is a traits helper that infers the signature of the function, +// method, static method, lambda, or function-like object `F`. +template <typename F> +struct SignatureOf { + // The signature of the function-like object `F` + using type = typename SignatureOf<decltype(&F::operator())>::type; +}; + +// SignatureOf specialization for a regular function or static method. +template <typename R, typename... ARGS> +struct SignatureOf<R (*)(ARGS...)> { + // The signature of the function-like object `F` + using type = Signature<typename std::decay<R>::type, + typename std::decay<ARGS>::type...>; +}; + +// SignatureOf specialization for a non-static method. +template <typename R, typename C, typename... ARGS> +struct SignatureOf<R (C::*)(ARGS...)> { + // The signature of the function-like object `F` + using type = Signature<typename std::decay<R>::type, + typename std::decay<ARGS>::type...>; +}; + +// SignatureOf specialization for a non-static, const method. +template <typename R, typename C, typename... ARGS> +struct SignatureOf<R (C::*)(ARGS...) const> { + // The signature of the function-like object `F` + using type = Signature<typename std::decay<R>::type, + typename std::decay<ARGS>::type...>; +}; + +// SignatureOfT is an alias to `typename SignatureOf<F>::type`. +template <typename F> +using SignatureOfT = typename SignatureOf<F>::type; + +// ParameterType is an alias to `typename SignatureOf<F>::type::parameter<N>`. +template <typename F, std::size_t N> +using ParameterType = typename SignatureOfT<F>::template parameter<N>; + +// `HasSignature<F, S>::value` is true iff the function-like `F` has a matching +// signature to the function-like `S`. +template <typename F, typename S> +using HasSignature = std::integral_constant< + bool, + std::is_same<SignatureOfT<F>, SignatureOfT<S>>::value>; + +// `Min<A, B>::value` resolves to the smaller value of A and B. +template <std::size_t A, std::size_t B> +using Min = std::integral_constant<std::size_t, (A < B ? A : B)>; + +// `CompatibleWith<F, S>::value` is true iff the function-like `F` +// can be called with the argument types of the function-like `S`. Return type +// of the two functions are not considered. +template <typename F, typename S> +using CompatibleWith = std::integral_constant< + bool, + (SignatureOfT<S>::parameter_count == SignatureOfT<F>::parameter_count) && + EachIsTypeOrDerived<Min<SignatureOfT<S>::parameter_count, + SignatureOfT<F>::parameter_count>::value, + typename SignatureOfT<S>::parameters, + typename SignatureOfT<F>::parameters>::value>; + +// If `CONDITION` is true then EnableIf resolves to type T, otherwise an +// invalid type. +template <bool CONDITION, typename T = void> +using EnableIf = typename std::enable_if<CONDITION, T>::type; + +// If `BASE` is a base of `T` then EnableIfIsType resolves to type `TRUE`, +// otherwise an invalid type. +template <typename BASE, typename T, typename TRUE_ = void> +using EnableIfIsType = EnableIf<IsTypeOrDerived<BASE, T>::value, TRUE_>; + +// If the function-like `F` has a matching signature to the function-like `S` +// then EnableIfHasSignature resolves to type `TRUE`, otherwise an invalid type. +template <typename F, typename S, typename TRUE_ = void> +using EnableIfHasSignature = EnableIf<HasSignature<F, S>::value, TRUE_>; + +} // namespace traits +} // namespace lsp + diff --git a/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/AbsolutePath.h b/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/AbsolutePath.h new file mode 100644 index 00000000000..ef1ee438603 --- /dev/null +++ b/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/AbsolutePath.h @@ -0,0 +1,27 @@ +#pragma once + +#include <LibLsp/JsonRpc/serializer.h> +#include <string> + +struct AbsolutePath { + static AbsolutePath BuildDoNotUse(const std::string& path); + + // Try not to use this. + AbsolutePath(); + + // Provide implicit conversions to std::string for the time being. + AbsolutePath(const std::string& path, bool validate = true); + operator std::string() const; + + bool operator==(const AbsolutePath& rhs) const; + bool operator!=(const AbsolutePath& rhs) const; + bool operator<(const AbsolutePath& rhs) const; + bool operator>(const AbsolutePath& rhs) const; + std::string path; + bool qualify = true; +}; + + +void Reflect(Reader& visitor, AbsolutePath& value); +void Reflect(Writer& visitor, AbsolutePath& value); + diff --git a/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/ClientPreferences.h b/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/ClientPreferences.h new file mode 100644 index 00000000000..7adf557f83a --- /dev/null +++ b/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/ClientPreferences.h @@ -0,0 +1,306 @@ +#pragma once +#include <LibLsp/lsp/general/lsClientCapabilities.h> +#include <LibLsp/lsp/utils.h> +#include <memory> +#include <vector> +#include <string> + +class ClientPreferences +{ +public: + + std::shared_ptr<lsWorkspaceClientCapabilites> workspace; + lsTextDocumentClientCapabilities textDocument ; + + ClientPreferences(const lsClientCapabilities& capabilities) + { + v3supported = capabilities.textDocument.has_value(); + if (v3supported) + textDocument = capabilities.textDocument.value(); + if(capabilities.workspace) + { + workspace = std::make_shared<lsWorkspaceClientCapabilites>(capabilities.workspace.value()); + } + } + + bool v3supported=false; + + bool isSignatureHelpSupported() { + + return v3supported && (textDocument.signatureHelp); + } + bool isWorkspaceDidChangeConfigurationSupported() const + { + return workspace && isDynamicRegistrationSupported(workspace->didChangeConfiguration); + } + bool isWorkspaceFoldersSupported() { + return workspace != nullptr && isTrue(workspace->workspaceFolders); + } + + bool isCompletionDynamicRegistered() { + return v3supported && isDynamicRegistrationSupported(textDocument.completion); + } + + bool isCompletionSnippetsSupported() { + //@formatter:off + if(!v3supported || !textDocument.completion) + { + return false; + } + const auto& completion = textDocument.completion.value(); + if(completion.completionItem) + { + return isTrue(completion.completionItem.value().snippetSupport); + } + return false; + } + + bool isV3Supported() { + return v3supported; + } + + bool isFormattingDynamicRegistrationSupported() { + return v3supported && isDynamicRegistrationSupported(textDocument.formatting); + } + + bool isRangeFormattingDynamicRegistrationSupported() { + return v3supported && isDynamicRegistrationSupported(textDocument.rangeFormatting); + } + + bool isOnTypeFormattingDynamicRegistrationSupported() { + return v3supported && isDynamicRegistrationSupported(textDocument.onTypeFormatting); + } + + bool isCodeLensDynamicRegistrationSupported() { + return v3supported && isDynamicRegistrationSupported(textDocument.codeLens); + } + + bool isSignatureHelpDynamicRegistrationSupported() { + return v3supported && isDynamicRegistrationSupported(textDocument.signatureHelp); + } + template<typename T> + static bool isDynamicRegistrationSupported(boost::optional<T>& capability) + { + if(capability) + return (capability.value().dynamicRegistration.value()); + return false; + } + + bool isTrue(const boost::optional<bool>& value) + { + return value.get_value_or(false); + } + + bool isRenameDynamicRegistrationSupported() { + return v3supported && isDynamicRegistrationSupported(textDocument.rename); + } + + bool isExecuteCommandDynamicRegistrationSupported() { + return v3supported && workspace != nullptr && isDynamicRegistrationSupported(workspace->executeCommand); + } + + bool isWorkspaceSymbolDynamicRegistered() { + return v3supported && workspace != nullptr && isDynamicRegistrationSupported(workspace->symbol); + } + + bool isWorkspaceChangeWatchedFilesDynamicRegistered() { + return v3supported && workspace != nullptr && isDynamicRegistrationSupported(workspace->didChangeWatchedFiles); + } + + bool isDocumentSymbolDynamicRegistered() { + return v3supported && isDynamicRegistrationSupported(textDocument.documentSymbol); + } + + bool isCodeActionDynamicRegistered() { + return v3supported && isDynamicRegistrationSupported(textDocument.codeAction); + } + + bool isDefinitionDynamicRegistered() { + return v3supported && isDynamicRegistrationSupported(textDocument.definition); + } + + bool isTypeDefinitionDynamicRegistered() { + return v3supported && isDynamicRegistrationSupported(textDocument.typeDefinition); + } + + bool isHoverDynamicRegistered() { + return v3supported && isDynamicRegistrationSupported(textDocument.hover); + } + + bool isReferencesDynamicRegistered() { + return v3supported && isDynamicRegistrationSupported(textDocument.references); + } + + bool isDocumentHighlightDynamicRegistered() { + return v3supported && isDynamicRegistrationSupported(textDocument.documentHighlight); + } + + bool isFoldgingRangeDynamicRegistered() { + return v3supported && isDynamicRegistrationSupported(textDocument.foldingRange); + } + + bool isImplementationDynamicRegistered() { + return v3supported && isDynamicRegistrationSupported(textDocument.implementation); + } + + bool isSelectionRangeDynamicRegistered() { + return v3supported && isDynamicRegistrationSupported(textDocument.selectionRange); + } + + bool isWillSaveRegistered() { + return v3supported && isTrue(textDocument.synchronization.willSave); + } + + bool isWillSaveWaitUntilRegistered() { + return v3supported && isTrue(textDocument.synchronization.willSaveWaitUntil); + } + + bool isWorkspaceApplyEditSupported() { + return workspace != nullptr && isTrue(workspace->applyEdit); + } + + bool isSupportsCompletionDocumentationMarkdown() { + + if (!v3supported || !textDocument.completion) + { + return false; + } + const auto& completion = textDocument.completion.value(); + if (completion.completionItem) + { + auto& documentationFormat = completion.completionItem.value().documentationFormat; + if(documentationFormat) + { + auto& data = documentationFormat.value(); + for(auto& it : data) + { + if(it == "markdown") + { + return true; + } + } + } + } + return false; + + } + + + bool isWorkspaceEditResourceChangesSupported() { + if(!workspace) return false; + + if(workspace->workspaceEdit) + { + return isTrue(workspace->workspaceEdit.value().resourceChanges); + } + return false; + } + static bool contains(const std::vector<std::string>& v, const std::string& target) + { + for(auto& it : v) + { + if(it == target) return true; + } + return false; + } + bool isResourceOperationSupported() const + { + if (!workspace) return false; + if (!workspace->workspaceEdit) + { + return false; + } + auto& it = (workspace->workspaceEdit.value()); + if(!it.resourceOperations) return false; + const auto& resourceOperations = it.resourceOperations.value(); + return contains(resourceOperations, "create") && contains(resourceOperations, "rename") && contains(resourceOperations, "delete"); + + } + + /** + * {@code true} if the client has explicitly set the + * {@code textDocument.documentSymbol.hierarchicalDocumentSymbolSupport} to + * {@code true} when initializing the LS. Otherwise, {@code false}. + */ + bool isHierarchicalDocumentSymbolSupported() { + if(!v3supported || !textDocument.documentSymbol) return false; + return isTrue(textDocument.documentSymbol.value().hierarchicalDocumentSymbolSupport); + + } + + bool isSemanticHighlightingSupported() { + //@formatter:off + if (!v3supported || !textDocument.semanticHighlightingCapabilities) return false; + return isTrue(textDocument.semanticHighlightingCapabilities.value().semanticHighlighting); + //@formatter:on + } + + /** + * {@code true} if the client has explicitly set the + * {@code textDocument.codeAction.codeActionLiteralSupport.codeActionKind.valueSet} + * value. Otherwise, {@code false}. + */ + bool isSupportedCodeActionKind(const std::string& kind) { + if (!v3supported || !textDocument.codeAction) return false; + //@formatter:off + const auto& codeAction = textDocument.codeAction.value(); + if(codeAction.codeActionLiteralSupport) + { + const auto& codeActionKind = codeAction.codeActionLiteralSupport.value().codeActionKind; + if(codeActionKind) + { + const auto& valueSet = codeActionKind.value().valueSet; + if(valueSet) + { + for(auto& k : valueSet.value()) + { + if(lsp::StartsWith(kind,k)) + { + return true; + } + } + } + } + } + return false; + + //@formatter:on + } + + /** + * {@code true} if the client has explicitly set the + * {@code textDocument.publishDiagnostics.tagSupport} to + * {@code true} when initializing the LS. Otherwise, {@code false}. + */ + bool isDiagnosticTagSupported() { + if (!v3supported || !textDocument.publishDiagnostics) return false; + const auto& publishDiagnostics = textDocument.publishDiagnostics.value(); + if(publishDiagnostics.tagSupport) + { + isTagSupported(publishDiagnostics.tagSupport); + } + return false; + } + + bool isTagSupported(const boost::optional < std::pair<boost::optional<bool>, + boost::optional<DiagnosticsTagSupport> > >& tagSupport) { + if(tagSupport) + { + auto &v = tagSupport.value(); + if (v.first) + { + return v.first.value(); + } + if (v.second) { + return !v.second.value().valueSet.empty(); + } + } + return false; + } + + bool isCallHierarchyDynamicRegistered() { + return v3supported && isDynamicRegistrationSupported(textDocument.callHierarchy); + } + +}; + diff --git a/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/CodeActionParams.h b/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/CodeActionParams.h new file mode 100644 index 00000000000..a1e3f1dcc1e --- /dev/null +++ b/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/CodeActionParams.h @@ -0,0 +1,114 @@ +#pragma once +#include "LibLsp/lsp/method_type.h" +#include "LibLsp/JsonRpc/message.h" +#include "LibLsp/lsp/lsp_diagnostic.h" +#include "LibLsp/lsp/workspace/execute_command.h" +#include "LibLsp/lsp/lsTextDocumentIdentifier.h" +#include "LibLsp/lsp/lsCodeAction.h" +namespace JDT +{ + namespace CodeActionKind { + + + /** + * Base kind for quickfix actions: 'quickfix' + */ + extern const char* QuickFix; + + /** + * Base kind for refactoring actions: 'refactor' + */ + extern const char* Refactor; + + /** + * Base kind for refactoring extraction actions: 'refactor.extract' + * + * Example extract actions: + * + * - Extract method - Extract function - Extract variable - Extract interface + * from class - ... + */ + extern const char* RefactorExtract; + + /** + * Base kind for refactoring inline actions: 'refactor.inline' + * + * Example inline actions: + * + * - Inline function - Inline variable - Inline constant - ... + */ + extern const char* RefactorInline; + + /** + * Base kind for refactoring rewrite actions: 'refactor.rewrite' + * + * Example rewrite actions: + * + * - Convert JavaScript function to class - Add or remove parameter - + * Encapsulate field - Make method static - Move method to base class - ... + */ + extern const char* RefactorRewrite; + + /** + * Base kind for source actions: `source` + * + * Source code actions apply to the entire file. + */ + extern const char* Source ; + + /** + * Base kind for an organize imports source action: `source.organizeImports` + */ + extern const char* SourceOrganizeImports; + + extern const char* COMMAND_ID_APPLY_EDIT; + }; + + +} +struct lsCodeActionContext { + // An array of diagnostics. + std::vector<lsDiagnostic> diagnostics; + /** + * Requested kind of actions to return. + * + * Actions not of this kind are filtered out by the client before being shown. So servers + * can omit computing them. + * + * See {@link CodeActionKind} for allowed values. + */ + boost::optional<std::vector<std::string>> only; + + MAKE_SWAP_METHOD(lsCodeActionContext, + diagnostics, only); +}; +MAKE_REFLECT_STRUCT(lsCodeActionContext, + diagnostics, only); + + +// Params for the CodeActionRequest +struct lsCodeActionParams { + // The document in which the command was invoked. + lsTextDocumentIdentifier textDocument; + // The range for which the command was invoked. + lsRange range; + // Context carrying additional information. + lsCodeActionContext context; + + MAKE_SWAP_METHOD(lsCodeActionParams, + textDocument, + range, + context); +}; +MAKE_REFLECT_STRUCT(lsCodeActionParams, + textDocument, + range, + context); + + + + + + + + diff --git a/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/Directory.h b/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/Directory.h new file mode 100644 index 00000000000..93f2c0807d3 --- /dev/null +++ b/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/Directory.h @@ -0,0 +1,13 @@ +#pragma once +#include <string> + +struct AbsolutePath; + +struct Directory { + explicit Directory(const AbsolutePath& path); + + bool operator==(const Directory& rhs) const; + bool operator!=(const Directory& rhs) const; + + std::string path; +}; diff --git a/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/ExecuteCommandParams.h b/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/ExecuteCommandParams.h new file mode 100644 index 00000000000..c06eed4b1ce --- /dev/null +++ b/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/ExecuteCommandParams.h @@ -0,0 +1,20 @@ +#pragma once + +#include "lsAny.h" +struct ExecuteCommandParams { + /** + * The identifier of the actual command handler. + */ + + std::string command; + + /** + * Arguments that the command should be invoked with. + * The arguments are typically specified when a command is returned from the server to the client. + * Example requests that return a command are textDocument/codeAction or textDocument/codeLens. + */ + boost::optional<std::vector<lsp::Any>> arguments; + + MAKE_SWAP_METHOD(ExecuteCommandParams, command, arguments); +}; +MAKE_REFLECT_STRUCT(ExecuteCommandParams,command,arguments) diff --git a/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/IProgressMonitor.h b/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/IProgressMonitor.h new file mode 100644 index 00000000000..bf1337e44fe --- /dev/null +++ b/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/IProgressMonitor.h @@ -0,0 +1,145 @@ +#pragma once + + +#include <string> +namespace lsp { +/** + * The <code>IProgressMonitor</code> interface is implemented + * by objects that monitor the progress of an activity; the methods + * in this interface are invoked by code that performs the activity. + * <p> + * All activity is broken down into a linear sequence of tasks against + * which progress is reported. When a task begins, a <code>beginTask(const wstring&, int) + * </code> notification is reported, followed by any number and mixture of + * progress reports (<code>worked()</code>) and subtask notifications + * (<code>subTask(const wstring&)</code>). When the task is eventually completed, a + * <code>done()</code> notification is reported. After the <code>done()</code> + * notification, the progress monitor cannot be reused; i.e., <code> + * beginTask(const wstring&, int)</code> cannot be called again after the call to + * <code>done()</code>. + * </p> + * <p> + * A request to cancel an operation can be signaled using the + * <code>setCanceled</code> method. Operations taking a progress + * monitor are expected to poll the monitor (using <code>isCanceled</code>) + * periodically and abort at their earliest convenience. Operation can however + * choose to ignore cancelation requests. + * </p> + * <p> + * Since notification is synchronous with the activity itself, the listener should + * provide a fast and robust implementation. If the handling of notifications would + * involve blocking operations, or operations which might throw uncaught exceptions, + * the notifications should be queued, and the actual processing deferred (or perhaps + * delegated to a separate thread). + * </p> + * <p> + * Clients may implement this interface. + * </p> + */ + class IProgressMonitor { + public: + virtual ~IProgressMonitor() + { + } + + /** Constant indicating an unknown amount of work. + */ + + const static int UNKNOWN = -1; + + /** + * Notifies that the main task is beginning. This must only be called once + * on a given progress monitor instance. + * + * @param name the name (or description) of the main task + * @param totalWork the total number of work units into which + * the main task is been subdivided. If the value is <code>UNKNOWN</code> + * the implemenation is free to indicate progress in a way which + * doesn't require the total number of work units in advance. + */ + virtual void beginTask(void* , int totalWork) + { + + }; + /** + * Notifies that the work is done; that is, either the main task is completed + * or the user canceled it. This method may be called more than once + * (implementations should be prepared to handle this case). + */ + + virtual void endTask(void*, int totalWork) + { + + } + + virtual void done(void*) = 0; + + /** + * Internal method to handle scaling correctly. This method + * must not be called by a client. Clients should + * always use the method </code>worked(int)</code>. + */ + virtual void internalWorked(double work) + { + + } + /** + * Returns whether cancelation of current operation has been requested. + * Long-running operations should poll to see if cancelation + * has been requested. + * + * @return <code>true</code> if cancellation has been requested, + * and <code>false</code> otherwise + * @see #setCanceled + */ + virtual bool isCanceled() = 0; + /** + * Sets the cancel state to the given value. + * + * @param value <code>true</code> indicates that cancelation has + * been requested (but not necessarily acknowledged); + * <code>false</code> clears this flag + * + * @see #isCanceled + */ + virtual void setCanceled(bool value) = 0; + /** + * Sets the task name to the given value. This method is used to + * restore the task label after a nested operation was executed. + * Normally there is no need for clients to call this method. + * + * @param name the name (or description) of the main task + * @see #beginTask(java.lang.const wstring&, int) + */ + virtual void setTaskName(void*) + { + + }; + /** + * Notifies that a subtask of the main task is beginning. + * Subtasks are optional; the main task might not have subtasks. + * + * @param name the name (or description) of the subtask + */ + virtual void subTask(void* ) + { + + } + /** + * Notifies that a given number of work unit of the main task + * has been completed. Note that this amount represents an + * installment, as opposed to a cumulative amount of work done + * to date. + * + * @param work the number of work units just completed + */ + virtual void worked(int work) + { + + }; + + virtual void catch_exception(void*) = 0; + }; +} + + diff --git a/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/Markup/Markup.cpp b/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/Markup/Markup.cpp new file mode 100644 index 00000000000..f65f8ad3ceb --- /dev/null +++ b/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/Markup/Markup.cpp @@ -0,0 +1,942 @@ +//===--- Markup.cpp -----------------------------------------*- C++-*------===// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://lsp.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// +#include "Markup.h" + +#include <algorithm> +#include <cassert> +#include <cstddef> +#include <iterator> +#include <memory> +#include <string> +#include <vector> +#include <boost/algorithm/string.hpp> + +namespace lsp { + + /// hexdigit - Return the hexadecimal character for the + /// given number \p X (which should be less than 16). + inline char hexdigit(unsigned X, bool LowerCase = false) { + const char HexChar = LowerCase ? 'a' : 'A'; + return X < 10 ? '0' + X : HexChar + X - 10; + } + + /// Given an array of c-style strings terminated by a null pointer, construct + /// a vector of StringRefs representing the same strings without the terminating + /// null string. + inline std::vector< std::string_ref> toStringRefArray(const char* const* Strings) { + std::vector< std::string_ref> Result; + while (*Strings) + Result.push_back(*Strings++); + return Result; + } + + /// Construct a string ref from a boolean. + inline std::string_ref toStringRef(bool B) { return std::string_ref(B ? "true" : "false"); } + + /// Construct a string ref from an array ref of unsigned chars. + inline std::string_ref toStringRef(const std::vector<uint8_t>& Input) { + return std::string_ref(Input.begin(), Input.end()); + } + + /// Construct a string ref from an array ref of unsigned chars. + inline std::vector<uint8_t> arrayRefFromStringRef(const std::string_ref& Input) { + return { Input.begin(), Input.end() }; + } + + /// Interpret the given character \p C as a hexadecimal digit and return its + /// value. + /// + /// If \p C is not a valid hex digit, -1U is returned. + inline unsigned hexDigitValue(char C) { + struct HexTable { + unsigned LUT[255] = {}; + constexpr HexTable() { + // Default initialize everything to invalid. + for (int i = 0; i < 255; ++i) + LUT[i] = ~0U; + // Initialize `0`-`9`. + for (int i = 0; i < 10; ++i) + LUT['0' + i] = i; + // Initialize `A`-`F` and `a`-`f`. + for (int i = 0; i < 6; ++i) + LUT['A' + i] = LUT['a' + i] = 10 + i; + } + }; + constexpr HexTable Table; + return Table.LUT[static_cast<unsigned char>(C)]; + } + + /// Checks if character \p C is one of the 10 decimal digits. + inline bool isDigit(char C) { return C >= '0' && C <= '9'; } + + /// Checks if character \p C is a hexadecimal numeric character. + inline bool isHexDigit(char C) { return hexDigitValue(C) != ~0U; } + + /// Checks if character \p C is a valid letter as classified by "C" locale. + inline bool isAlpha(char C) { + return ('a' <= C && C <= 'z') || ('A' <= C && C <= 'Z'); + } + + /// Checks whether character \p C is either a decimal digit or an uppercase or + /// lowercase letter as classified by "C" locale. + inline bool isAlnum(char C) { return isAlpha(C) || isDigit(C); } + + /// Checks whether character \p C is valid ASCII (high bit is zero). + inline bool isASCII(char C) { return static_cast<unsigned char>(C) <= 127; } + + /// Checks whether all characters in S are ASCII. + inline bool isASCII(std::string_ref S) { + for (char C : S) + { + if(!isASCII(C))return true; + } + return true; + } + + /// Checks whether character \p C is printable. + /// + /// Locale-independent version of the C standard library isprint whose results + /// may differ on different platforms. + inline bool isPrint(char C) { + unsigned char UC = static_cast<unsigned char>(C); + return (0x20 <= UC) && (UC <= 0x7E); + } + + /// Checks whether character \p C is whitespace in the "C" locale. + /// + /// Locale-independent version of the C standard library isspace. + inline bool isSpace(char C) { + return C == ' ' || C == '\f' || C == '\n' || C == '\r' || C == '\t' || + C == '\v'; + } + + /// Returns the corresponding lowercase character if \p x is uppercase. + inline char toLower(char x) { + if (x >= 'A' && x <= 'Z') + return x - 'A' + 'a'; + return x; + } + + /// Returns the corresponding uppercase character if \p x is lowercase. + inline char toUpper(char x) { + if (x >= 'a' && x <= 'z') + return x - 'a' + 'A'; + return x; + } + + inline std::string utohexstr(uint64_t X, bool LowerCase = false) { + char Buffer[17]; + char* BufPtr = std::end(Buffer); + + if (X == 0) *--BufPtr = '0'; + + while (X) { + unsigned char Mod = static_cast<unsigned char>(X) & 15; + *--BufPtr = hexdigit(Mod, LowerCase); + X >>= 4; + } + + return std::string(BufPtr, std::end(Buffer)); + } + + /// Convert buffer \p Input to its hexadecimal representation. + /// The returned string is double the size of \p Input. + inline std::string toHex( std::string_ref Input, bool LowerCase = false) { + static const char* const LUT = "0123456789ABCDEF"; + const uint8_t Offset = LowerCase ? 32 : 0; + size_t Length = Input.size(); + + std::string Output; + Output.reserve(2 * Length); + for (size_t i = 0; i < Length; ++i) { + const unsigned char c = Input[i]; + Output.push_back(LUT[c >> 4] | Offset); + Output.push_back(LUT[c & 15] | Offset); + } + return Output; + } + + inline std::string toHex(std::vector<uint8_t> Input, bool LowerCase = false) { + return toHex(toStringRef(Input), LowerCase); + } + + /// Store the binary representation of the two provided values, \p MSB and + /// \p LSB, that make up the nibbles of a hexadecimal digit. If \p MSB or \p LSB + /// do not correspond to proper nibbles of a hexadecimal digit, this method + /// returns false. Otherwise, returns true. + inline bool tryGetHexFromNibbles(char MSB, char LSB, uint8_t& Hex) { + unsigned U1 = hexDigitValue(MSB); + unsigned U2 = hexDigitValue(LSB); + if (U1 == ~0U || U2 == ~0U) + return false; + + Hex = static_cast<uint8_t>((U1 << 4) | U2); + return true; + } + + /// Return the binary representation of the two provided values, \p MSB and + /// \p LSB, that make up the nibbles of a hexadecimal digit. + inline uint8_t hexFromNibbles(char MSB, char LSB) { + uint8_t Hex = 0; + bool GotHex = tryGetHexFromNibbles(MSB, LSB, Hex); + (void)GotHex; + assert(GotHex && "MSB and/or LSB do not correspond to hex digits"); + return Hex; + } + + /// Convert hexadecimal string \p Input to its binary representation and store + /// the result in \p Output. Returns true if the binary representation could be + /// converted from the hexadecimal string. Returns false if \p Input contains + /// non-hexadecimal digits. The output string is half the size of \p Input. + inline bool tryGetFromHex( std::string_ref Input, std::string& Output) { + if (Input.empty()) + return true; + + Output.reserve((Input.size() + 1) / 2); + if (Input.size() % 2 == 1) { + uint8_t Hex = 0; + if (!tryGetHexFromNibbles('0', Input.front(), Hex)) + return false; + + Output.push_back(Hex); + Input = Input.drop_front(); + } + + assert(Input.size() % 2 == 0); + while (!Input.empty()) { + uint8_t Hex = 0; + if (!tryGetHexFromNibbles(Input[0], Input[1], Hex)) + return false; + + Output.push_back(Hex); + Input = Input.drop_front(2); + } + return true; + } + + /// Convert hexadecimal string \p Input to its binary representation. + /// The return string is half the size of \p Input. + inline std::string fromHex( std::string_ref Input) { + std::string Hex; + bool GotHex = tryGetFromHex(Input, Hex); + (void)GotHex; + assert(GotHex && "Input contains non hex digits"); + return Hex; + } + + + + inline std::string utostr(uint64_t X, bool isNeg = false) { + char Buffer[21]; + char* BufPtr = std::end(Buffer); + + if (X == 0) *--BufPtr = '0'; // Handle special case... + + while (X) { + *--BufPtr = '0' + char(X % 10); + X /= 10; + } + + if (isNeg) *--BufPtr = '-'; // Add negative sign... + return std::string(BufPtr, std::end(Buffer)); + } + + inline std::string itostr(int64_t X) { + if (X < 0) + return utostr(static_cast<uint64_t>(1) + ~static_cast<uint64_t>(X), true); + else + return utostr(static_cast<uint64_t>(X)); + } + + /// StrInStrNoCase - Portable version of strcasestr. Locates the first + /// occurrence of string 's1' in string 's2', ignoring case. Returns + /// the offset of s2 in s1 or npos if s2 cannot be found. + std::string_ref::size_type StrInStrNoCase( std::string_ref s1, std::string_ref s2); + + /// getToken - This function extracts one token from source, ignoring any + /// leading characters that appear in the Delimiters string, and ending the + /// token at any of the characters that appear in the Delimiters string. If + /// there are no tokens in the source string, an empty string is returned. + /// The function returns a pair containing the extracted token and the + /// remaining tail string. + std::pair< std::string_ref, std::string_ref> getToken( std::string_ref Source, + std::string_ref Delimiters = " \t\n\v\f\r"); + + + + /// Returns the English suffix for an ordinal integer (-st, -nd, -rd, -th). + inline std::string_ref getOrdinalSuffix(unsigned Val) { + // It is critically important that we do this perfectly for + // user-written sequences with over 100 elements. + switch (Val % 100) { + case 11: + case 12: + case 13: + return "th"; + default: + switch (Val % 10) { + case 1: return "st"; + case 2: return "nd"; + case 3: return "rd"; + default: return "th"; + } + } + } + + namespace detail { + + template <typename IteratorT> + inline std::string join_impl(IteratorT Begin, IteratorT End, + std::string_ref Separator, std::input_iterator_tag) { + std::string S; + if (Begin == End) + return S; + + S += (*Begin); + while (++Begin != End) { + S += Separator; + S += (*Begin); + } + return S; + } + + template <typename IteratorT> + inline std::string join_impl(IteratorT Begin, IteratorT End, + std::string_ref Separator, std::forward_iterator_tag) { + std::string S; + if (Begin == End) + return S; + + size_t Len = (std::distance(Begin, End) - 1) * Separator.size(); + for (IteratorT I = Begin; I != End; ++I) + Len += (*I).size(); + S.reserve(Len); + size_t PrevCapacity = S.capacity(); + (void)PrevCapacity; + S += (*Begin); + while (++Begin != End) { + S += Separator; + S += (*Begin); + } + assert(PrevCapacity == S.capacity() && "String grew during building"); + return S; + } + + template <typename Sep> + inline void join_items_impl(std::string& Result, Sep Separator) {} + + template <typename Sep, typename Arg> + inline void join_items_impl(std::string& Result, Sep Separator, + const Arg& Item) { + Result += Item; + } + + template <typename Sep, typename Arg1, typename... Args> + inline void join_items_impl(std::string& Result, Sep Separator, const Arg1& A1, + Args &&... Items) { + Result += A1; + Result += Separator; + join_items_impl(Result, Separator, std::forward<Args>(Items)...); + } + + inline size_t join_one_item_size(char) { return 1; } + inline size_t join_one_item_size(const char* S) { return S ? ::strlen(S) : 0; } + + template <typename T> inline size_t join_one_item_size(const T& Str) { + return Str.size(); + } + + inline size_t join_items_size() { return 0; } + + template <typename A1> inline size_t join_items_size(const A1& A) { + return join_one_item_size(A); + } + template <typename A1, typename... Args> + inline size_t join_items_size(const A1& A, Args &&... Items) { + return join_one_item_size(A) + join_items_size(std::forward<Args>(Items)...); + } + + } // end namespace detail + + /// Joins the strings in the range [Begin, End), adding Separator between + /// the elements. + template <typename IteratorT> + inline std::string join(IteratorT Begin, IteratorT End, std::string_ref Separator) { + using tag = typename std::iterator_traits<IteratorT>::iterator_category; + return detail::join_impl(Begin, End, Separator, tag()); + } + + /// Joins the strings in the range [R.begin(), R.end()), adding Separator + /// between the elements. + template <typename Range> + inline std::string join(Range&& R, std::string_ref Separator) { + return join(R.begin(), R.end(), Separator); + } + + /// Joins the strings in the parameter pack \p Items, adding \p Separator + /// between the elements. All arguments must be implicitly convertible to + /// std::string, or there should be an overload of std::string::operator+=() + /// that accepts the argument explicitly. + template <typename Sep, typename... Args> + inline std::string join_items(Sep Separator, Args &&... Items) { + std::string Result; + if (sizeof...(Items) == 0) + return Result; + + size_t NS = detail::join_one_item_size(Separator); + size_t NI = detail::join_items_size(std::forward<Args>(Items)...); + Result.reserve(NI + (sizeof...(Items) - 1) * NS + 1); + detail::join_items_impl(Result, Separator, std::forward<Args>(Items)...); + return Result; + } + + /// A helper class to return the specified delimiter string after the first + /// invocation of operator std::string_ref(). Used to generate a comma-separated + /// list from a loop like so: + /// + /// \code + /// ListSeparator LS; + /// for (auto &I : C) + /// OS << LS << I.getName(); + /// \end + class ListSeparator { + bool First = true; + std::string_ref Separator; + + public: + ListSeparator( std::string_ref Separator = ", ") : Separator(Separator) {} + operator std::string_ref() { + if (First) { + First = false; + return {}; + } + return Separator; + } + }; + +} // end namespace lsp + +namespace lsp{ + +// Is <contents a plausible start to an HTML tag? +// Contents may not be the rest of the line, but it's the rest of the plain +// text, so we expect to see at least the tag name. +bool looksLikeTag(std::string_ref& Contents) { + if (Contents.empty()) + return false; + if (Contents.front() == '!' || Contents.front() == '?' || + Contents.front() == '/') + return true; + // Check the start of the tag name. + if (!lsp::isAlpha(Contents.front())) + return false; + // Drop rest of the tag name, and following whitespace. + Contents = Contents + .drop_while([](char C) { + return lsp::isAlnum(C) || C == '-' || C == '_' || C == ':'; + }) + .drop_while(lsp::isSpace); + // The rest of the tag consists of attributes, which have restrictive names. + // If we hit '=', all bets are off (attribute values can contain anything). + for (; !Contents.empty(); Contents = Contents.drop_front()) { + if (lsp::isAlnum(Contents.front()) || lsp::isSpace(Contents.front())) + continue; + if (Contents.front() == '>' || Contents.start_with("/>")) + return true; // May close the tag. + if (Contents.front() == '=') + return true; // Don't try to parse attribute values. + return false; // Random punctuation means this isn't a tag. + } + return true; // Potentially incomplete tag. +} + +// Tests whether C should be backslash-escaped in markdown. +// The string being escaped is Before + C + After. This is part of a paragraph. +// StartsLine indicates whether `Before` is the start of the line. +// After may not be everything until the end of the line. +// +// It's always safe to escape punctuation, but want minimal escaping. +// The strategy is to escape the first character of anything that might start +// a markdown grammar construct. +bool needsLeadingEscape(char C, std::string_ref Before, std::string_ref After, + bool StartsLine) { + + auto RulerLength = [&]() -> /*Length*/ unsigned { + if (!StartsLine || !Before.empty()) + return false; + std::string_ref A = After.trim_right(); + return std::all_of(A.begin(),A.end(), [C](char D) { return C == D; }) ? 1 + A.size() : 0; + }; + auto IsBullet = [&]() { + return StartsLine && Before.empty() && + (After.empty() || After.start_with(" ")); + }; + auto SpaceSurrounds = [&]() { + return (After.empty() || std::isspace(After.front())) && + (Before.empty() || std::isspace(Before.back())); + }; + + auto WordSurrounds = [&]() { + return (!After.empty() && std::isalnum(After.front())) && + (!Before.empty() && std::isalnum(Before.back())); + }; + + switch (C) { + case '\\': // Escaped character. + return true; + case '`': // Code block or inline code + // Any number of backticks can delimit an inline code block that can end + // anywhere (including on another line). We must escape them all. + return true; + case '~': // Code block + return StartsLine && Before.empty() && After.start_with("~~"); + case '#': { // ATX heading. + if (!StartsLine || !Before.empty()) + return false; + std::string_ref& Rest = After.trim_left(C); + return Rest.empty() || Rest.start_with(" "); + } + case ']': // Link or link reference. + // We escape ] rather than [ here, because it's more constrained: + // ](...) is an in-line link + // ]: is a link reference + // The following are only links if the link reference exists: + // ] by itself is a shortcut link + // ][...] is an out-of-line link + // Because we never emit link references, we don't need to handle these. + return After.start_with(":") || After.start_with("("); + case '=': // Setex heading. + return RulerLength() > 0; + case '_': // Horizontal ruler or matched delimiter. + if (RulerLength() >= 3) + return true; + // Not a delimiter if surrounded by space, or inside a word. + // (The rules at word boundaries are subtle). + return !(SpaceSurrounds() || WordSurrounds()); + case '-': // Setex heading, horizontal ruler, or bullet. + if (RulerLength() > 0) + return true; + return IsBullet(); + case '+': // Bullet list. + return IsBullet(); + case '*': // Bullet list, horizontal ruler, or delimiter. + return IsBullet() || RulerLength() >= 3 || !SpaceSurrounds(); + case '<': // HTML tag (or autolink, which we choose not to escape) + return looksLikeTag(After); + case '>': // Quote marker. Needs escaping at start of line. + return StartsLine && Before.empty(); + case '&': { // HTML entity reference + auto End = After.find(';'); + if (End == std::string_ref::npos) + return false; + std::string_ref Content = After.substr(0, End); + if (Content.consume_front("#")) + { + if (Content.consume_front("x") || Content.consume_front("X")) + { + return std::all_of(Content.begin(),Content.end(), lsp::isHexDigit); + } + + return std::all_of(Content.begin(), Content.end(), [](char c) + { + return lsp::isDigit(c); + }); + } + return std::all_of(Content.begin(), Content.end(), [](char c) + { + return lsp::isAlpha(c); + }); + } + case '.': // Numbered list indicator. Escape 12. -> 12\. at start of line. + case ')': + return StartsLine && !Before.empty() && + std::all_of(Before.begin(), Before.end(), [](char c) + { + return lsp::isDigit(c); + }) && After.start_with(" "); + default: + return false; + } +} + +/// Escape a markdown text block. Ensures the punctuation will not introduce +/// any of the markdown constructs. + std::string_ref renderText(const std::string_ref& Input, bool StartsLine) { + std::string_ref R; + for (unsigned I = 0; I < Input.size(); ++I) { + if (needsLeadingEscape(Input[I], Input.substr(0, I), Input.substr(I + 1), + StartsLine)) + R.push_back('\\'); + R.push_back(Input[I]); + } + return R; +} + +/// Renders \p Input as an inline block of code in markdown. The returned value +/// is surrounded by backticks and the inner contents are properly escaped. + std::string_ref renderInlineBlock(const std::string_ref& Input) { + std::string_ref R; + // Double all backticks to make sure we don't close the inline block early. + for (size_t From = 0; From < Input.size();) { + size_t Next = Input.find("`", From); + R += Input.substr(From, Next - From); + if (Next == std::string_ref::npos) + break; + R += "``"; // double the found backtick. + + From = Next + 1; + } + // If results starts with a backtick, add spaces on both sides. The spaces + // are ignored by markdown renderers. + if (std::string_ref(R).start_with("`") || std::string_ref(R).end_with("`")) + return "` " + std::move(R) + " `"; + // Markdown render should ignore first and last space if both are there. We + // add an extra pair of spaces in that case to make sure we render what the + // user intended. + if (std::string_ref(R).start_with(" ") && std::string_ref(R).end_with(" ")) + return "` " + std::move(R) + " `"; + return "`" + std::move(R) + "`"; +} + +/// Get marker required for \p Input to represent a markdown codeblock. It +/// consists of at least 3 backticks(`). Although markdown also allows to use +/// tilde(~) for code blocks, they are never used. + std::string_ref getMarkerForCodeBlock(const std::string_ref& Input) { + // Count the maximum number of consecutive backticks in \p Input. We need to + // start and end the code block with more. + unsigned MaxBackticks = 0; + unsigned Backticks = 0; + for (char C : Input) { + if (C == '`') { + ++Backticks; + continue; + } + MaxBackticks = std::max(MaxBackticks, Backticks); + Backticks = 0; + } + MaxBackticks = std::max(Backticks, MaxBackticks); + // Use the corresponding number of backticks to start and end a code block. + return std::string_ref(/*Repeat=*/std::max(3u, MaxBackticks + 1), '`'); +} + + /// SplitString - Split up the specified string according to the specified +/// delimiters, appending the result fragments to the output list. + void SplitString(const std::string& Source, + std::vector<std::string_ref>& OutFragments, + std::string Delimiters = " \t\n\v\f\r") +{ + boost::split(OutFragments, Source, boost::is_any_of(Delimiters)); +} + + +// Trims the input and concatenates whitespace blocks into a single ` `. + std::string_ref canonicalizeSpaces(const std::string_ref& Input) { + std::vector<std::string_ref> Words; + SplitString(Input, Words); + + return lsp::join(Words, " "); +} + + + std::string_ref renderBlocks( std::vector<Block*>&& Children, + void (Block::* RenderFunc)(std::ostringstream&) const) { + std::string_ref R; + std::ostringstream OS(R); + + std::vector<int> v{ 1, 2, 3 }; + + // Trim rulers. + Children.erase(std::remove_if(Children.begin(), Children.end(), [](const Block* C) + { + return C->isRuler(); + }), Children.end()); + + bool LastBlockWasRuler = true; + for (const auto& C : Children) { + if (C->isRuler() && LastBlockWasRuler) + continue; + LastBlockWasRuler = C->isRuler(); + ((*C).*RenderFunc)(OS); + } + + // Get rid of redundant empty lines introduced in plaintext while imitating + // padding in markdown. + std::string_ref AdjustedResult; + std::string_ref TrimmedText(OS.str()); + TrimmedText = TrimmedText.trim(); + + std::copy_if(TrimmedText.begin(), TrimmedText.end(), + std::back_inserter(AdjustedResult), + [&TrimmedText](const char& C) { + return !std::string_ref(TrimmedText.data(), + &C - TrimmedText.data() + 1) + // We allow at most two newlines. + .end_with("\n\n\n"); + }); + + return AdjustedResult; + }; + std::string_ref renderBlocks(const std::vector<std::unique_ptr<Block> >& children, + void (Block::* renderFunc)(std::ostringstream&) const) + { + std::vector<Block*> temp(children.size(), nullptr); + for(size_t i = 0 ; i < children.size() ; ++i) + { + temp[i]=(children[i].get()); + } + return renderBlocks(std::move(temp), renderFunc); + } +// Separates two blocks with extra spacing. Note that it might render strangely +// in vscode if the trailing block is a codeblock, see +// https://github.com/microsoft/vscode/issues/88416 for details. +class Ruler : public Block { +public: + void renderMarkdown(std::ostringstream &OS) const override { + // Note that we need an extra new line before the ruler, otherwise we might + // make previous block a title instead of introducing a ruler. + OS << "\n---\n"; + } + void renderPlainText(std::ostringstream &OS) const override { OS << '\n'; } + std::unique_ptr<Block> clone() const override { + return std::make_unique<Ruler>(*this); + } + bool isRuler() const override { return true; } +}; + +class CodeBlock : public Block { +public: + void renderMarkdown(std::ostringstream &OS) const override { + std::string_ref Marker = getMarkerForCodeBlock(Contents); + // No need to pad from previous blocks, as they should end with a new line. + OS << Marker << Language << '\n' << Contents << '\n' << Marker << '\n'; + } + + void renderPlainText(std::ostringstream &OS) const override { + // In plaintext we want one empty line before and after codeblocks. + OS << '\n' << Contents << "\n\n"; + } + + std::unique_ptr<Block> clone() const override { + return std::make_unique<CodeBlock>(*this); + } + + CodeBlock( std::string_ref Contents, std::string_ref Language) + : Contents(std::move(Contents)), Language(std::move(Language)) {} + +private: + + std::string_ref Contents; + std::string_ref Language; +}; + +// Inserts two spaces after each `\n` to indent each line. First line is not +// indented. + std::string_ref indentLines(const std::string_ref& Input) { + assert(!Input.end_with("\n") && "Input should've been trimmed."); + std::string_ref IndentedR; + // We'll add 2 spaces after each new line. + IndentedR.reserve(Input.size() + Input.count("\n") * 2); + for (char C : Input) { + IndentedR += C; + if (C == '\n') + IndentedR.append(" "); + } + return IndentedR; +} + +class Heading : public Paragraph { +public: + Heading(size_t Level) : Level(Level) {} + void renderMarkdown(std::ostringstream &OS) const override { + OS << std::string_ref(Level, '#') << ' '; + Paragraph::renderMarkdown(OS); + } + +private: + size_t Level; +}; + + + + + + std::string_ref Block::asMarkdown() const { + std::string_ref R; + std::ostringstream OS(R); + renderMarkdown(OS); + return std::string_ref(OS.str()).trim(); +} + + std::string_ref Block::asPlainText() const { + std::string_ref R; + std::ostringstream OS(R); + renderPlainText(OS); + return std::string_ref(OS.str()).trim().c_str(); +} + + void Paragraph::renderMarkdown(std::ostringstream& OS) const { + bool NeedsSpace = false; + bool HasChunks = false; + for (auto& C : Chunks) { + if (C.SpaceBefore || NeedsSpace) + OS << " "; + switch (C.Kind) { + case Chunk::PlainText: + OS << renderText(C.Contents, !HasChunks); + break; + case Chunk::InlineCode: + OS << renderInlineBlock(C.Contents); + break; + } + HasChunks = true; + NeedsSpace = C.SpaceAfter; + } + // Paragraphs are translated into markdown lines, not markdown paragraphs. + // Therefore it only has a single linebreak afterwards. + // VSCode requires two spaces at the end of line to start a new one. + OS << " \n"; + } + + std::unique_ptr<Block> Paragraph::clone() const { + return std::make_unique<Paragraph>(*this); + } + + /// Choose a marker to delimit `Text` from a prioritized list of options. + /// This is more readable than escaping for plain-text. + std::string_ref chooseMarker(std::vector<std::string_ref> Options, + const std::string_ref& Text) + { + // Prefer a delimiter whose characters don't appear in the text. + for (std::string_ref& S : Options) + if (Text.find_first_of(S) == std::string_ref::npos) + return S; + return Options.front(); + } + + void Paragraph::renderPlainText(std::ostringstream& OS) const { + bool NeedsSpace = false; + for (auto& C : Chunks) { + if (C.SpaceBefore || NeedsSpace) + OS << " "; + std::string_ref Marker = ""; + if (C.Preserve && C.Kind == Chunk::InlineCode) + Marker = chooseMarker({ "`", "'", "\"" }, C.Contents); + OS << Marker << C.Contents << Marker; + NeedsSpace = C.SpaceAfter; + } + OS << '\n'; + } + + void BulletList::renderMarkdown(std::ostringstream& OS) const { + for (auto& D : Items) { + // Instead of doing this we might prefer passing Indent to children to get + // rid of the copies, if it turns out to be a bottleneck. + + OS << "- "; + OS << indentLines(D.asMarkdown()) << '\n'; + } + // We need a new line after list to terminate it in markdown. + OS << '\n'; + } + + void BulletList::renderPlainText(std::ostringstream& OS) const { + for (auto& D : Items) { + // Instead of doing this we might prefer passing Indent to children to get + // rid of the copies, if it turns out to be a bottleneck. + OS << "- " << indentLines(D.asPlainText()) << '\n'; + } + } + + Paragraph& Paragraph::appendSpace() { + if (!Chunks.empty()) + Chunks.back().SpaceAfter = true; + return *this; + } + + Paragraph& Paragraph::appendText(const std::string_ref& Text) { + std::string_ref Norm = canonicalizeSpaces(Text); + if (Norm.empty()) + return *this; + Chunks.emplace_back(); + Chunk& C = Chunks.back(); + C.Contents = std::move(Norm); + C.Kind = Chunk::PlainText; + + C.SpaceBefore = std::isspace(Text.front()); + C.SpaceAfter = std::isspace(Text.back()); + return *this; + } + + Paragraph& Paragraph::appendCode(const std::string_ref& Code, bool Preserve) { + bool AdjacentCode = + !Chunks.empty() && Chunks.back().Kind == Chunk::InlineCode; + std::string_ref Norm = canonicalizeSpaces(Code); + if (Norm.empty()) + return *this; + Chunks.emplace_back(); + Chunk& C = Chunks.back(); + C.Contents = std::move(Norm); + C.Kind = Chunk::InlineCode; + C.Preserve = Preserve; + // Disallow adjacent code spans without spaces, markdown can't render them. + C.SpaceBefore = AdjacentCode; + return *this; + } + + std::unique_ptr<Block> BulletList::clone() const { + return std::make_unique<BulletList>(*this); + } + + class Document& BulletList::addItem() { + Items.emplace_back(); + return Items.back(); + } + + Document& Document::operator=(const Document& Other) { + Children.clear(); + for (const auto& C : Other.Children) + Children.push_back(C->clone()); + return *this; + } + + void Document::append(Document Other) { + std::move(Other.Children.begin(), Other.Children.end(), + std::back_inserter(Children)); + } + + Paragraph& Document::addParagraph() { + Children.push_back(std::make_unique<Paragraph>()); + return *static_cast<Paragraph*>(Children.back().get()); + } + + void Document::addRuler() { Children.push_back(std::make_unique<Ruler>()); } + + void Document::addCodeBlock(std::string_ref Code, std::string_ref Language) { + Children.emplace_back( + std::make_unique<CodeBlock>(std::move(Code), std::move(Language))); + } + + std::string_ref Document::asMarkdown() const { + return renderBlocks(Children, &Block::renderMarkdown); + } + + std::string_ref Document::asPlainText() const { + return renderBlocks(Children, &Block::renderPlainText); + } + + BulletList& Document::addBulletList() { + Children.emplace_back(std::make_unique<BulletList>()); + return *static_cast<BulletList*>(Children.back().get()); + } + + Paragraph& Document::addHeading(size_t Level) { + assert(Level > 0); + Children.emplace_back(std::make_unique<Heading>(Level)); + return *static_cast<Paragraph*>(Children.back().get()); + } + };
\ No newline at end of file diff --git a/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/Markup/Markup.h b/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/Markup/Markup.h new file mode 100644 index 00000000000..92d773db0cc --- /dev/null +++ b/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/Markup/Markup.h @@ -0,0 +1,119 @@ +#pragma once +#include <cctype> +#include <clocale> +#include <cstddef> +#include <memory> +#include <string> +#include <vector> +#include <sstream> + +#include "string_ref.h" + +namespace lsp +{ + +/// Holds text and knows how to lay it out. Multiple blocks can be grouped to +/// form a document. Blocks include their own trailing newlines, std::string_ref +/// should trim them if need be. +class Block { +public: + virtual void renderMarkdown(std::ostringstream &OS) const = 0; + virtual void renderPlainText(std::ostringstream &OS) const = 0; + virtual std::unique_ptr<Block> clone() const = 0; + std::string_ref asMarkdown() const; + std::string_ref asPlainText() const; + + virtual bool isRuler() const { return false; } + virtual ~Block() = default; +}; + +/// Represents parts of the markup that can contain strings, like inline code, +/// code block or plain text. +/// One must introduce different paragraphs to create separate blocks. +class Paragraph : public Block { +public: + void renderMarkdown(std::ostringstream &OS) const override; + void renderPlainText(std::ostringstream &OS) const override; + std::unique_ptr<Block> clone() const override; + + /// Append plain text to the end of the string. + Paragraph &appendText(const std::string_ref& Text); + + /// Append inline code, this translates to the ` block in markdown. + /// \p Preserve indicates the code span must be apparent even in plaintext. + Paragraph &appendCode(const std::string_ref& Code, bool Preserve = false); + + /// Ensure there is space between the surrounding chunks. + /// Has no effect at the beginning or end of a paragraph. + Paragraph &appendSpace(); + +private: + struct Chunk { + enum { + PlainText, + InlineCode, + } Kind = PlainText; + // Preserve chunk markers in plaintext. + bool Preserve = false; + std::string_ref Contents; + // Whether this chunk should be surrounded by whitespace. + // Consecutive SpaceAfter and SpaceBefore will be collapsed into one space. + // Code spans don't usually set this: their spaces belong "inside" the span. + bool SpaceBefore = false; + bool SpaceAfter = false; + }; + std::vector<Chunk> Chunks; +}; + +/// Represents a sequence of one or more documents. Knows how to print them in a +/// list like format, e.g. by prepending with "- " and indentation. +class BulletList : public Block { +public: + void renderMarkdown(std::ostringstream &OS) const override; + void renderPlainText(std::ostringstream &OS) const override; + std::unique_ptr<Block> clone() const override; + + class Document &addItem(); + +private: + std::vector<class Document> Items; +}; + +/// A format-agnostic representation for structured text. Allows rendering into +/// markdown and plaintext. +class Document { +public: + Document() = default; + Document(const Document &Other) { *this = Other; } + Document &operator=(const Document &); + Document(Document &&) = default; + Document &operator=(Document &&) = default; + + void append(Document Other); + + /// Adds a semantical block that will be separate from others. + Paragraph &addParagraph(); + /// Inserts a horizontal separator to the document. + void addRuler(); + /// Adds a block of code. This translates to a ``` block in markdown. In plain + /// text representation, the code block will be surrounded by newlines. + void addCodeBlock( std::string_ref Code, std::string_ref Language = "cpp"); + /// Heading is a special type of paragraph that will be prepended with \p + /// Level many '#'s in markdown. + Paragraph &addHeading(size_t Level); + + BulletList &addBulletList(); + + /// Doesn't contain any trailing newlines. + /// We try to make the markdown human-readable, e.g. avoid extra escaping. + /// At least one client (coc.nvim) displays the markdown verbatim! + std::string_ref asMarkdown() const; + /// Doesn't contain any trailing newlines. + std::string_ref asPlainText() const; + +private: + std::vector<std::unique_ptr<Block>> Children; +}; + + +} diff --git a/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/Markup/string_ref.h b/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/Markup/string_ref.h new file mode 100644 index 00000000000..d7ee423944e --- /dev/null +++ b/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/Markup/string_ref.h @@ -0,0 +1,1059 @@ + +#pragma once +#include <algorithm> +#include <string> +#include <vector> +#include <stdarg.h> +#include<functional> + +#ifndef _WIN32 +#include <cstring> +#endif +namespace std +{ + + /** + * An extension of STL's string providing additional functionality that is often availiable in + * higher-level languages such as Python. + */ + class string_ref : public string + { + public: + + //static unsigned GetAutoSenseRadix(string_ref& Str) { + // if (Str.empty()) + // return 10; + + // if (Str.start_with("0x") || Str.start_with("0X")) { + // Str = Str.substr(2); + // return 16; + // } + + // if (Str.start_with("0b") || Str.start_with("0B")) { + // Str = Str.substr(2); + // return 2; + // } + + // if (Str.start_with("0o")) { + // Str = Str.substr(2); + // return 8; + // } + + // if (Str[0] == '0' && Str.size() > 1 && std::isdigit(Str[1])) { + // Str = Str.substr(1); + // return 8; + // } + + // return 10; + //} + + //static bool consumeUnsignedInteger(string_ref& Str, unsigned Radix, + // unsigned long long& Result) { + // // Autosense radix if not specified. + // if (Radix == 0) + // Radix = GetAutoSenseRadix(Str); + + // // Empty strings (after the radix autosense) are invalid. + // if (Str.empty()) return true; + + // // Parse all the bytes of the string given this radix. Watch for overflow. + // string_ref Str2 = Str; + // Result = 0; + // while (!Str2.empty()) { + // unsigned CharVal; + // if (Str2[0] >= '0' && Str2[0] <= '9') + // CharVal = Str2[0] - '0'; + // else if (Str2[0] >= 'a' && Str2[0] <= 'z') + // CharVal = Str2[0] - 'a' + 10; + // else if (Str2[0] >= 'A' && Str2[0] <= 'Z') + // CharVal = Str2[0] - 'A' + 10; + // else + // break; + + // // If the parsed value is larger than the integer radix, we cannot + // // consume any more characters. + // if (CharVal >= Radix) + // break; + + // // Add in this character. + // unsigned long long PrevResult = Result; + // Result = Result * Radix + CharVal; + + // // Check for overflow by shifting back and seeing if bits were lost. + // if (Result / Radix < PrevResult) + // return true; + + // Str2 = Str2.substr(1); + // } + + // // We consider the operation a failure if no characters were consumed + // // successfully. + // if (Str.size() == Str2.size()) + // return true; + + // Str = Str2; + // return false; + //} + + //static bool consumeSignedInteger(string_ref& Str, unsigned Radix, + // long long& Result) { + // unsigned long long ULLVal; + + // // Handle positive strings first. + // if (Str.empty() || Str.front() != '-') { + // if (consumeUnsignedInteger(Str, Radix, ULLVal) || + // // Check for value so large it overflows a signed value. + // (long long)ULLVal < 0) + // return true; + // Result = ULLVal; + // return false; + // } + + // // Get the positive part of the value. + // string_ref Str2 = Str.drop_front(1); + // if (consumeUnsignedInteger(Str2, Radix, ULLVal) || + // // Reject values so large they'd overflow as negative signed, but allow + // // "-0". This negates the unsigned so that the negative isn't undefined + // // on signed overflow. + // (long long)-ULLVal > 0) + // return true; + + // Str = Str2; + // Result = -ULLVal; + // return false; + //} + + ///// GetAsUnsignedInteger - Workhorse method that converts a integer character + ///// sequence of radix up to 36 to an unsigned long long value. + //static bool getAsUnsignedInteger(string_ref Str, unsigned Radix, + // unsigned long long& Result) { + // if (consumeUnsignedInteger(Str, Radix, Result)) + // return true; + + // // For getAsUnsignedInteger, we require the whole string to be consumed or + // // else we consider it a failure. + // return !Str.empty(); + //} + + //static bool getAsSignedInteger(string_ref Str, unsigned Radix, + // long long& Result) { + // if (consumeSignedInteger(Str, Radix, Result)) + // return true; + + // // For getAsSignedInteger, we require the whole string to be consumed or else + // // we consider it a failure. + // return !Str.empty(); + //} + + + ///// Parse the current string as an integer of the specified radix. If + ///// \p Radix is specified as zero, this does radix autosensing using + ///// extended C rules: 0 is octal, 0x is hex, 0b is binary. + ///// + ///// If the string is invalid or if only a subset of the string is valid, + ///// this returns true to signify the error. The string is considered + ///// erroneous if empty or if it overflows T. + //template <typename T> + //std::enable_if_t<std::numeric_limits<T>::is_signed, bool> + // getAsInteger(unsigned Radix, T& Result) const { + // long long LLVal; + // if (getAsSignedInteger(*this, Radix, LLVal) || + // static_cast<T>(LLVal) != LLVal) + // return true; + // Result = LLVal; + // return false; + //} + + //template <typename T> + //std::enable_if_t<!std::numeric_limits<T>::is_signed, bool> + // getAsInteger(unsigned Radix, T& Result) const { + // unsigned long long ULLVal; + // // The additional cast to unsigned long long is required to avoid the + // // Visual C++ warning C4805: '!=' : unsafe mix of type 'bool' and type + // // 'unsigned __int64' when instantiating getAsInteger with T = bool. + // if (getAsUnsignedInteger(*this, Radix, ULLVal) || + // static_cast<unsigned long long>(static_cast<T>(ULLVal)) != ULLVal) + // return true; + // Result = ULLVal; + // return false; + //} + + + + /**` + * Default constructor + * + * Constructs an empty string_ref ("") + */ + string_ref() : string() { } + + /** + * Duplicate the STL string copy constructor + * + * @param[in] s The string to copy + * @param[in] pos The starting position in the string to copy from + * @param[in] n The number of characters to copy + */ + string_ref(const string &s, size_type pos = 0, size_type n = npos) : string(s, pos, npos) { } + + /** + * Construct an string_ref from a null-terminated character array + * + * @param[in] s The character array to copy into the new string + */ + string_ref(const value_type *s) : string(s) { } + + /** + * Construct an string_ref from a character array and a length + * + * @param[in] s The character array to copy into the new string + * @param[in] n The number of characters to copy + */ + string_ref(const value_type *s, size_type n) : string(s, n) { } + + /** + * Create an string_ref with @p n copies of @p c + * + * @param[in] n The number of copies + * @param[in] c The character to copy @p n times + */ + string_ref(size_type n, value_type c) : string(n, c) { } + + /** + * Create a string from a range + * + * @param[in] first The first element to copy in + * @param[in] last The last element to copy in + */ + template <class InputIterator> + string_ref(InputIterator first, InputIterator last) : string(first, last) { } + + /** + * The destructor + */ + ~string_ref() { } + + /** + * Split a string by whitespace + * + * @return A vector of strings, each of which is a substring of the string + */ + vector<string_ref> split(size_type limit = npos) const + { + vector<string_ref> v; + + const_iterator + i = begin(), + last = i; + for (; i != end(); i++) + { + if (*i == ' ' || *i == '\n' || *i == '\t' || *i == '\r') + { + if (i + 1 != end() && (i[1] == ' ' || i[1] == '\n' || i[1] == '\t' || i[1] == '\r')) + continue; + v.push_back(string_ref(last, i)); + last = i + 1; + if (v.size() >= limit - 1) + { + v.push_back(string_ref(last, end())); + return v; + } + } + } + + if (last != i) + v.push_back(string_ref(last, i)); + + return v; + } + + /** + * Split a string by a character + * + * Returns a vector of ext_strings, each of which is a substring of the string formed by splitting + * it on boundaries formed by the character @p separator. If @p limit is set, the returned vector + * will contain a maximum of @p limit elements with the last element containing the rest of + * the string. + * + * If @p separator is not found in the string, a single element will be returned in the vector + * containing the entire string. + * + * The separators are removed from the output + * + * @param[in] separator The character separator to split the string on + * @param[in] limit The maximum number of output elements + * @return A vector of strings, each of which is a substring of the string + * + * @section split_ex Example + * @code + * std::string_ref s("This|is|a|test."); + * std::vector<std::string_ref> v = s.split('|'); + * std::copy(v.begin(), v.end(), std::ostream_iterator<std::string_ref>(std::cout, "\n")); + * + * This + * is + * a + * test. + * @endcode + */ + vector<string_ref> split(value_type separator, size_type limit = npos) const + { + vector<string_ref> v; + + const_iterator + i = begin(), + last = i; + for (; i != end(); i++) + { + if (*i == separator) + { + v.push_back(string_ref(last, i)); + last = i + 1; + if (v.size() >= limit - 1) + { + v.push_back(string_ref(last, end())); + return v; + } + } + } + + if (last != i) + v.push_back(string_ref(last, i)); + + return v; + } + + /** + * Split a string by another string + * + * Returns a vector of ext_strings, each of which is a substring of the string formed by + * splitting it on boundaries formed by the string @p separator. If @p limit is set, the + * returned vector will contain a maximum of @p limit elements with the last element + * containing the rest of the string. + * + * If @p separator is not found in the string, a single element will be returned in the + * vector containing the entire string. + * + * The separators are removed from the output + * + * @param[in] separator The string separator to split the string on + * @param[in] limit The maximum number of output elements + * @return A vector of strings, each of which is a substring of the string + * + * @ref split_ex + */ + vector<string_ref> split(const string &separator, size_type limit = npos) const + { + vector<string_ref> v; + + const_iterator + i = begin(), + last = i; + for (; i != end(); i++) + { + if (string(i, i + separator.length()) == separator) + { + v.push_back(string_ref(last, i)); + last = i + separator.length(); + + if (v.size() >= limit - 1) + { + v.push_back(string_ref(last, end())); + return v; + } + } + } + + if (last != i) + v.push_back(string_ref(last, i)); + + return v; + } + + /** + * Convert a string into an integer + * + * Convert the initial portion of a string into a signed integer. Once a non-numeric + * character is reached, the remainder of @p string is ignored and the integer that was + * read returned. + * + * @param s The string to convert + * @return The integer converted from @p string + */ + static long int integer(const string &s) + { + long int retval = 0; + bool neg = false; + + for (const_iterator i = s.begin(); i != s.end(); i++) + { + if (i == s.begin()) + { + if (*i == '-') + { + neg = true; + continue; + } + else if (*i == '+') + continue; + } + if (*i >= '0' && *i <= '9') + { + retval *= 10; + retval += *i - '0'; + } + else + break; + } + + if (neg) + retval *= -1; + + return retval; + } + + /** + * Convert the string to an integer + * + * Convert the initial portion of the string into a signed integer. Once a non-numeric + * character is reached, the remainder of the string is ignored and the integer that had + * been read thus far is returned. + * + * @return The integer converted from the string + */ + long int integer() const + { + return integer(*this); + } + + /** + * Split a string into chunks of size @p chunklen. Returns a vector of strings. + * + * Splits a string into chunks of the given size. The final chunk may not fill its + * entire allocated number of characters. + * + * @param[in] chunklen The number of characters per chunk + * @return A vector of strings, each of length <= chunklen + * + * @section chunk_split-ex Example + * @code + * std::string_ref s("abcdefghijk"); + * std::vector<std::string_ref> v = s.chunk_split(3); + * std::copy(v.begin(), v.end(), ostream_iterator<std::string_ref>(cout, " ")); + * + * abc def ghi jk + * @endcode + */ + vector<string_ref> chunk_split(size_type chunklen) const + { + vector<string_ref> retval; + retval.reserve(size() / chunklen + 1); + + size_type count = 0; + const_iterator + i = begin(), + last = i; + for (; i != end(); i++, count++) + { + if (count == chunklen) + { + count = 0; + retval.push_back(string_ref(last, i)); + last = i; + } + } + + if (last != i) + retval.push_back(string_ref(last, i)); + + return retval; + } + + /** + * Join a sequence of strings by some glue to create a new string + * + * Glue is not added to the end of the string. + * + * @pre [first, last) is a valid range + * @pre InputIterator is a model of STL's Input Iterator + * @pre InputIterator must point to a string type (std::string, std::string_ref, char *) + * + * @param[in] glue The glue to join strings with + * @param[in] first The beginning of the range to join + * @param[in] last The end of the range to join + * @return A string constructed of each element of the range connected together with @p glue + * + * @section join_ex Example + * @code + * std::vector<std::string_ref> v; + * v.push_back("This"); + * v.push_back("is"); + * v.push_back("a"); + * v.push_back("test."); + * std::cout << std::string_ref::join("|", v.begin(), v.end()) << std::endl; + * + * This|is|a|test. + * @endcode + */ + template <class InputIterator> + static string_ref join(const string &glue, InputIterator first, InputIterator last) + { + string_ref retval; + + for (; first != last; ++first) + { + retval.append(*first); + retval.append(glue); + } + retval.erase(retval.length() - glue.length()); + + return retval; + } + + /** + * Join a sequence of strings by some glue to create a new string + * + * @copydoc join + * @ref join_ex + */ + template <class InputIterator> + static string_ref join(value_type glue, InputIterator first, InputIterator last) + { + string_ref retval; + + for (; first != last; ++first) + { + retval.append(*first); + retval.append(1, glue); + } + retval.erase(retval.length() - 1); + + return retval; + } + + /** + * Search for any instances of @p needle and replace them with @p s + * + * @param[in] needle The string to replace + * @param[in] s The replacement string + * @return *this + * @post All instances of @p needle in the string are replaced with @p s + * + * @section replace-ex Example + * @code + * std::string_ref s("This is a test."); + * s.replace("is", "ere"); + * std::cout << s << std::endl; + * + * There ere a test. + * @endcode + */ + string_ref &replace(const string &needle, const string &s) + { + size_type + lastpos = 0, + thispos; + + while ((thispos = find(needle, lastpos)) != npos) + { + string::replace(thispos, needle.length(), s); + lastpos = thispos + 1; + } + return *this; + } + string_ref &replace_first(const string &needle, const string &s) + { + size_type + lastpos = 0, + thispos; + + if ((thispos = find(needle, lastpos)) != npos) + { + string::replace(thispos, needle.length(), s); + lastpos = thispos + 1; + } + return *this; + } + /** + * Search of any instances of @p needle and replace them with @p c + * + * @param[in] needle The character to replace + * @param[in] c The replacement character + * @return *this + * @post All instances of @p needle in the string are replaced with @p c + * + * @ref replace-ex + */ + string_ref &replace(value_type needle, value_type c) + { + for (iterator i = begin(); i != end(); i++) + if (*i == needle) + *i = c; + + return *this; + } + + /** + * Repeat a string @p n times + * + * @param[in] n The number of times to repeat the string + * @return string_ref containing @p n copies of the string + * + * @section repeat-ex Example + * @code + * std::string_ref s("123"); + * s = s * 3; + * std::cout << s << std::endl; + * + * 123123123 + * @endcode + */ + string_ref operator*(size_type n) + { + string_ref retval; + for (size_type i = 0; i < n; i++) + retval.append(*this); + + return retval; + } + + /** + * Convert the string to lowercase + * + * @return *this + * @post The string is converted to lowercase + */ + string_ref &tolower() + { + for (iterator i = begin(); i != end(); i++) + if (*i >= 'A' && *i <= 'Z') + *i = (*i) + ('a' - 'A'); + return *this; + } + + /** + * Convert the string to uppercase + * + * @return *this + * @post The string is converted to uppercase + */ + string_ref &toupper() + { + for (iterator i = begin(); i != end(); i++) + if (*i >= 'a' && *i <= 'z') + *i = (*i) - ('a' - 'A'); + return *this; + } + + /** + * Count the occurances of @p str in the string. + * + * @return The count of substrings @p str in the string + */ + size_type count(const string &str) const + { + size_type + count = 0, + last = 0, + cur = 0; + + while ((cur = find(str, last + 1)) != npos) + { + count++; + last = cur; + } + + return count; + } + + /** + * Determine if the string is alphanumeric + * + * @return true if the string contains only characters between a-z, A-Z and 0-9 and + * contains at least one character, else false + */ + bool is_alnum() const + { + if (length() == 0) + return false; + + for (const_iterator i = begin(); i != end(); i++) + { + if (*i < 'A' || *i > 'Z') + if (*i < '0' || *i > '9') + if (*i < 'a' || *i > 'z') + return false; + } + + return true; + } + + /** + * Determine if the string is alphabetic only + * + * @return true of the string contains only characters between a-z and A-Z and contains at + * least one character, else false + */ + bool is_alpha() const + { + if (length() == 0) + return false; + + for (const_iterator i = begin(); i != end(); i++) + if (*i < 'A' || (*i > 'Z' && (*i < 'a' || *i > 'z'))) + return false; + + return true; + } + + /** + * Determine if the string is numeric only + * + * @return true if the string contains only characters between 0-9 and contains at least + * one character, else false + */ + bool is_numeric() const + { + if (length() == 0) + return false; + + for (const_iterator i = begin(); i != end(); i++) + if (*i < '0' || *i > '9') + return false; + + return true; + } + + /** + * Determine if a string is all lower case + * + * @return true if there is at least one character, and all characters are lowercase + * letters, else false + */ + bool is_lower() const + { + if (length() == 0) + return false; + + for (const_iterator i = begin(); i != end(); i++) + if (*i < 'a' || *i < 'z') + return false; + + return true; + } + + /** + * Determine if a string is all upper case + * + * @return true if there is at least one character, and all characters are uppercase + * letters, else false + */ + bool is_upper() const + { + if (length() == 0) + return false; + + for (const_iterator i = begin(); i != end(); i++) + if (*i < 'A' || *i > 'Z') + return false; + + return true; + } + + /** + * Swap the case of a string + * + * @post Converts all uppercase to lowercase, and all lowercase to uppercase in the string + * @return *this + */ + string_ref &swapcase() + { + for (iterator i = begin(); i != end(); i++) + if (*i >= 'A' && *i <= 'Z') + *i += ('a' - 'A'); + else if (*i >= 'a' && *i <= 'z') + *i -= ('a' - 'A'); + + return *this; + } + + /******************************************************************************* + Function: std::string_ref::start_with + Access: public + Qualifier: const + Parameter: const string & str + Returns: bool + + Purpose: is the string start with str + *******************************************************************************/ + bool start_with(const string& str) const + { + return ( this->find(str) == 0 ); + } + + /// Return a string_ref equal to 'this' but with only the last \p N + /// elements remaining. If \p N is greater than the length of the + /// string, the entire string is returned. + + string_ref take_back(size_t N = 1) const { + if (N >= size()) + return *this; + return drop_front(size() - N); + } + /// Return a string_ref equal to 'this' but with the first \p N elements + /// dropped. + + string_ref drop_front(size_t N = 1) const { + //assert(size() >= N && "Dropping more elements than exist"); + return substr(N); + } + + + + /// Return a string_ref equal to 'this' but with the last \p N elements + /// dropped. + + string_ref drop_back(size_t N = 1) const { + + return substr(0, size() - N); + } + + /// Return a string_ref equal to 'this', but with all characters satisfying + /// the given predicate dropped from the beginning of the string. + + string_ref drop_while(std::function<bool(char)> F) const { + return substr(std::find_if_not(begin(),end(),F)-begin()); + } + + /// Return a string_ref equal to 'this', but with all characters not + /// satisfying the given predicate dropped from the beginning of the string. + + string_ref drop_until(std::function<bool(char)> F) const { + return substr(std::find_if(begin(), end(), F) - begin()); + } + + /// Returns true if this string_ref has the given prefix and removes that + /// prefix. + bool consume_front(string_ref Prefix) { + if (!start_with(Prefix)) + return false; + + *this = drop_front(Prefix.size()); + return true; + } + + /// Returns true if this string_ref has the given suffix and removes that + /// suffix. + bool consume_back(string_ref Suffix) { + if (!end_with(Suffix)) + return false; + + *this = drop_back(Suffix.size()); + return true; + } + + /******************************************************************************* + Function: std::string_ref::end_with + Access: public + Qualifier: const + Parameter: const string & str + Returns: bool + + Purpose: is the string end with str + *******************************************************************************/ + bool end_with(const string& str) const + { + if (str.length() > this->length()) + { + return false; + } + size_type off = this->length() - str.length(); + return ( find(str, off) == off); + } + + /******************************************************************************* + Function: hl_lib::string_ref::format + Access: public + Qualifier: + Parameter: const char * format_string + Parameter: ... + Returns: string_ref& + + Purpose: format the string + *******************************************************************************/ + string_ref& format(const char* format_string, ...) + { + if (format_string == 0) + { + return *this; + } + + va_list argList; + char* pbuf = 0; + va_start( argList, format_string ); +#ifdef _WIN32 + int len = _vscprintf( format_string, argList ); +#else + int len = vsnprintf(nullptr, 0, format_string, argList); +#endif + pbuf = new char[len + 1]; + if (pbuf != 0) + { +#ifdef _WIN32 + vsprintf_s( pbuf, len + 1, format_string, argList ); +#else + vsprintf(pbuf, format_string, argList); +#endif + *this = pbuf; + } + delete[] pbuf; + va_end( argList ); + + return *this; + } + + /******************************************************************************* + Function: hl_lib::string_ref::trim_left + Access: public + Qualifier: + Parameter: value_type ch + Returns: string_ref& + + Purpose: delete all char which is ch at the left of the string + *******************************************************************************/ + string_ref& trim_left(value_type ch = ' ') + { + size_type off = this->find_first_not_of(ch); + if (off != string::npos) + { + this->erase(0, off); + } + return *this; + } + + /******************************************************************************* + Function: hl_lib::string_ref::trim_right + Access: public + Qualifier: + Parameter: value_type ch + Returns: string_ref& + + Purpose: delete all char which is ch at the right of the string + *******************************************************************************/ + string_ref& trim_right(value_type ch = ' ') + { + size_type off = this->find_last_not_of(ch); + if (off == string::npos) + { + off = 0; + } + else + { + off++; + } + this->erase(off, length() - off); + return *this; + } + + /******************************************************************************* + Function: hl_lib::string_ref::trim + Access: public + Qualifier: + Parameter: value_type ch + Returns: string_ref& + + Purpose: delete all char which is ch at the left and right of the string + *******************************************************************************/ + string_ref& trim(value_type ch = ' ') + { + trim_left(ch); + trim_right(ch); + return *this; + } + + /******************************************************************************* + Function: hl_lib::string_ref::float_num + Access: public static + Qualifier: + Parameter: const string & str + Returns: double + + Purpose: parse str to a float number + *******************************************************************************/ + static double float_num(const string& str) + { + return atof(str.c_str()); + } + + /******************************************************************************* + Function: hl_lib::string_ref::float_num + Access: public static + Qualifier: + Returns: double + + Purpose: parse this to a float number + *******************************************************************************/ + double float_num() const + { + return float_num(*this); + } + + /******************************************************************************* + Function: hl_lib::string_ref::compare_nocase + Access: public + Qualifier: const + Parameter: const string & str + Returns: int + + Purpose: compare string no case + *******************************************************************************/ + int compare_nocase(const string& str) const + { +#ifdef _WIN32 + return _stricmp(this->c_str(), str.c_str()); +#else + return strcasecmp(this->c_str(), str.c_str()); +#endif + } + + /******************************************************************************* + Function: hl_lib::string_ref::compare_nocase + Access: public + Qualifier: const + Parameter: size_type index + Parameter: size_type length + Parameter: const string & str + Returns: int + + Purpose: compare substring no case + *******************************************************************************/ + int compare_nocase( size_type index, size_type length, const string &str ) const + { + string_ref temp = this->substr(index, length); + return temp.compare_nocase(str); + } + + /******************************************************************************* + Function: hl_lib::string_ref::compare_nocase + Access: public + Qualifier: const + Parameter: size_type index + Parameter: size_type length + Parameter: const string & str + Parameter: size_type index2 + Parameter: size_type length2 + Returns: int + + Purpose: compare two substring no case + *******************************************************************************/ + int compare_nocase( size_type index, size_type length, const string &str, size_type index2, size_type length2) const + { + string_ref temp1 = this->substr(index, length); + string_ref temp2 = str.substr(index2, length2); + return temp1.compare_nocase(temp2); + } + + }; + +} + diff --git a/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/ParentProcessWatcher.cpp b/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/ParentProcessWatcher.cpp new file mode 100644 index 00000000000..6769f5112d0 --- /dev/null +++ b/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/ParentProcessWatcher.cpp @@ -0,0 +1,106 @@ +#include "ParentProcessWatcher.h" +#include <boost/process.hpp> + +#ifdef _WIN32 +#include <boost/process/windows.hpp> +#endif + +#include <boost/filesystem.hpp> +#include <boost/asio.hpp> +#include <iostream> + +#include "ProcessIoService.h" +#include "SimpleTimer.h" + + +using namespace boost::asio::ip; +using namespace std; + +struct ParentProcessWatcher::ParentProcessWatcherData : std::enable_shared_from_this<ParentProcessWatcherData> +{ + std::unique_ptr<SimpleTimer<boost::posix_time::seconds>> timer; + lsp::Log& _log; + std::function<void()> on_exit; + lsp::ProcessIoService asio_io; + std::shared_ptr < boost::process::opstream> write_to_service; + std::shared_ptr< boost::process::ipstream > read_from_service; + int pid; + const int _poll_delay_secs /*= 10*/; + std::string command; + std::shared_ptr<boost::process::child> c; + + ParentProcessWatcherData(lsp::Log& log, int _pid, + const std::function<void()>&& callback, uint32_t poll_delay_secs) : + _log(log), on_exit(callback), pid(_pid), _poll_delay_secs(poll_delay_secs) + { +#ifdef _WIN32 + command = "cmd /c \"tasklist /FI \"PID eq " + std::to_string(pid) + "\" | findstr " + + std::to_string(pid) + "\""; +#else + command = "ps -p " + std::to_string(pid); +#endif + + } + + void run() + { + write_to_service = std::make_shared<boost::process::opstream>(); + read_from_service = std::make_shared<boost::process::ipstream>(); + +// const uint32_t POLL_DELAY_SECS = _poll_delay_secs; + auto self(shared_from_this()); + std::error_code ec; + namespace bp = boost::process; + c = std::make_shared<bp::child>(asio_io.getIOService(), command, + ec, +#ifdef _WIN32 + bp::windows::hide, +#endif + bp::std_out > *read_from_service, + bp::std_in < *write_to_service, + bp::on_exit([self](int exit_code, const std::error_code& ec_in) { + // the tasklist command should return 0 (parent process exists) or 1 (parent process doesn't exist) + if (exit_code == 1)// + { + if (self->on_exit) + { + + std::thread([=]() + { + std::this_thread::sleep_for(std::chrono::seconds(3)); + self->on_exit(); + }).detach(); + } + } + else + { + if (exit_code > 1) + { + self->_log.log(lsp::Log::Level::WARNING, "The tasklist command: '" + self->command + "' returns " + std::to_string(exit_code)); + } + + self->timer = std::make_unique<SimpleTimer<boost::posix_time::seconds>>(self->_poll_delay_secs, [=]() { + self->run(); + }); + } + + })); + if (ec) + { + // fail + _log.log(lsp::Log::Level::SEVERE, "Start parent process watcher failed."); + } + } +}; + +ParentProcessWatcher::ParentProcessWatcher(lsp::Log& log, int pid, + const std::function<void()>&& callback, uint32_t poll_delay_secs) : d_ptr(new ParentProcessWatcherData(log, pid, std::move(callback), poll_delay_secs)) +{ + d_ptr->run(); +} + +ParentProcessWatcher::~ParentProcessWatcher() +{ + if (d_ptr->timer) + d_ptr->timer->Stop(); +} diff --git a/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/ParentProcessWatcher.h b/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/ParentProcessWatcher.h new file mode 100644 index 00000000000..fa84e4109a5 --- /dev/null +++ b/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/ParentProcessWatcher.h @@ -0,0 +1,17 @@ +#pragma once + +#include "LibLsp/JsonRpc/MessageIssue.h" +#include <memory> + +class ParentProcessWatcher +{ +public: + struct ParentProcessWatcherData; + + ParentProcessWatcher(lsp::Log& log, int pid, const std::function<void()>&& callback, uint32_t poll_delay_secs = 10); + + ~ParentProcessWatcher(); + + std::shared_ptr<ParentProcessWatcherData> d_ptr; +}; + diff --git a/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/ProcessIoService.h b/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/ProcessIoService.h new file mode 100644 index 00000000000..1389a1d5b7d --- /dev/null +++ b/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/ProcessIoService.h @@ -0,0 +1,48 @@ +#pragma once +#include <boost/asio.hpp> +#include <iostream> + +namespace lsp +{ + class ProcessIoService + { + public: + using IOService = boost::asio::io_service; + using Work = boost::asio::io_service::work; + using WorkPtr = std::unique_ptr<Work>; + + ProcessIoService() { + + work_ = std::unique_ptr<Work>(new Work(ioService_)); + auto temp_thread_ = new std::thread([this] + { + ioService_.run(); + }); + thread_ = std::unique_ptr<std::thread>(temp_thread_); + } + + ProcessIoService(const ProcessIoService&) = delete; + ProcessIoService& operator=(const ProcessIoService&) = delete; + + boost::asio::io_service& getIOService() + { + return ioService_; + } + + void stop() + { + + work_.reset(); + + thread_->join(); + + } + + private: + IOService ioService_; + WorkPtr work_; + std::unique_ptr<std::thread> thread_; + + }; + +} diff --git a/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/ProtocolJsonHandler.cpp b/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/ProtocolJsonHandler.cpp new file mode 100644 index 00000000000..90e3fcda086 --- /dev/null +++ b/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/ProtocolJsonHandler.cpp @@ -0,0 +1,716 @@ +#include "ProtocolJsonHandler.h" +#include "general/initialize.h" +#include "general/shutdown.h" +#include "textDocument/code_action.h" +#include "textDocument/code_lens.h" +#include "textDocument/completion.h" + + +#include "textDocument/did_close.h" + +#include "textDocument/highlight.h" +#include "textDocument/document_link.h" +#include "textDocument/formatting.h" +#include "textDocument/hover.h" +#include "textDocument/implementation.h" +#include "textDocument/range_formatting.h" +#include "textDocument/references.h" +#include "textDocument/rename.h" +#include "textDocument/signature_help.h" +#include "textDocument/type_definition.h" +#include "workspace/symbol.h" +#include "textDocument/typeHierarchy.h" +#include "out_list.h" +#include "extention/jdtls/codeActionResult.h" +#include "textDocument/declaration_definition.h" +#include "textDocument/resolveCompletionItem.h" +#include "textDocument/resolveCodeLens.h" +#include "textDocument/colorPresentation.h" +#include "textDocument/foldingRange.h" +#include "textDocument/prepareRename.h" +#include "textDocument/resolveTypeHierarchy.h" +#include "textDocument/callHierarchy.h" +#include "textDocument/selectionRange.h" +#include "extention/jdtls/classFileContents.h" +#include "extention/jdtls/buildWorkspace.h" +#include "extention/jdtls/listOverridableMethods.h" +#include "extention/jdtls/addOverridableMethods.h" +#include "extention/jdtls/checkHashCodeEqualsStatus.h" +#include "extention/jdtls/checkConstructorsStatus.h" +#include "extention/jdtls/checkDelegateMethodsStatus.h" +#include "extention/jdtls/checkToStringStatus.h" +#include "extention/jdtls/executeCommand.h" +#include "extention/jdtls/findLinks.h" +#include "extention/jdtls/generateAccessors.h" +#include "extention/jdtls/generateConstructors.h" +#include "extention/jdtls/generateDelegateMethods.h" +#include "extention/jdtls/generateHashCodeEquals.h" +#include "extention/jdtls/generateToString.h" +#include "extention/jdtls/getMoveDestinations.h" +#include "extention/jdtls/Move.h" +#include "extention/jdtls/organizeImports.h" +#include "general/exit.h" +#include "general/initialized.h" +#include "extention/jdtls/projectConfigurationUpdate.h" +#include "textDocument/did_change.h" +#include "textDocument/did_open.h" +#include "textDocument/did_save.h" +#include "textDocument/publishDiagnostics.h" +#include "textDocument/willSave.h" + +#include "workspace/didChangeWorkspaceFolders.h" +#include "workspace/did_change_configuration.h" +#include "workspace/did_change_watched_files.h" +#include "windows/MessageNotify.h" +#include "language/language.h" +#include "client/registerCapability.h" +#include "client/unregisterCapability.h" +#include "LibLsp/JsonRpc/Cancellation.h" +#include "textDocument/didRenameFiles.h" +#include "textDocument/semanticHighlighting.h" +#include "workspace/configuration.h" + + +void AddStadardResponseJsonRpcMethod(MessageJsonHandler& handler) +{ + + handler.method2response[td_initialize::request::kMethodInfo] = [](Reader& visitor) + { + if(visitor.HasMember("error")) + return Rsp_Error::ReflectReader(visitor); + + return td_initialize::response::ReflectReader(visitor); + }; + + handler.method2response[td_shutdown::request::kMethodInfo] = [](Reader& visitor) + { + if (visitor.HasMember("error")) + return Rsp_Error::ReflectReader(visitor); + return td_shutdown::response::ReflectReader(visitor); + }; + handler.method2response[td_codeAction::request::kMethodInfo] = [](Reader& visitor) + { + if (visitor.HasMember("error")) + return Rsp_Error::ReflectReader(visitor); + + return td_codeAction::response::ReflectReader(visitor); + }; + handler.method2response[td_codeLens::request::kMethodInfo] = [](Reader& visitor) + { + if (visitor.HasMember("error")) + return Rsp_Error::ReflectReader(visitor); + return td_codeLens::response::ReflectReader(visitor); + }; + handler.method2response[td_completion::request::kMethodInfo] = [](Reader& visitor) + { + if (visitor.HasMember("error")) + return Rsp_Error::ReflectReader(visitor); + return td_completion::response::ReflectReader(visitor); + }; + + handler.method2response[td_definition::request::kMethodInfo] = [](Reader& visitor) + { + if (visitor.HasMember("error")) + return Rsp_Error::ReflectReader(visitor); + return td_definition::response::ReflectReader(visitor); + }; + handler.method2response[td_declaration::request::kMethodInfo] = [](Reader& visitor) + { + if (visitor.HasMember("error")) + return Rsp_Error::ReflectReader(visitor); + return td_declaration::response::ReflectReader(visitor); + }; + handler.method2response[td_willSaveWaitUntil::request::kMethodInfo] = [](Reader& visitor) + { + if (visitor.HasMember("error")) + return Rsp_Error::ReflectReader(visitor); + return td_willSaveWaitUntil::response::ReflectReader(visitor); + }; + + handler.method2response[td_highlight::request::kMethodInfo] = [](Reader& visitor) + { + if (visitor.HasMember("error")) + return Rsp_Error::ReflectReader(visitor); + return td_highlight::response::ReflectReader(visitor); + }; + + handler.method2response[td_links::request::kMethodInfo] = [](Reader& visitor) + { + if (visitor.HasMember("error")) + return Rsp_Error::ReflectReader(visitor); + return td_links::response::ReflectReader(visitor); + }; + + handler.method2response[td_linkResolve::request::kMethodInfo] = [](Reader& visitor) + { + if (visitor.HasMember("error")) + return Rsp_Error::ReflectReader(visitor); + return td_linkResolve::response::ReflectReader(visitor); + }; + + handler.method2response[td_symbol::request::kMethodInfo] = [](Reader& visitor) + { + if (visitor.HasMember("error")) + return Rsp_Error::ReflectReader(visitor); + return td_symbol::response::ReflectReader(visitor); + }; + + handler.method2response[td_formatting::request::kMethodInfo] = [](Reader& visitor) + { + if (visitor.HasMember("error")) + return Rsp_Error::ReflectReader(visitor); + return td_formatting::response::ReflectReader(visitor); + }; + + handler.method2response[td_hover::request::kMethodInfo] = [](Reader& visitor) + { + if (visitor.HasMember("error")) + return Rsp_Error::ReflectReader(visitor); + return td_hover::response::ReflectReader(visitor); + + }; + + handler.method2response[td_implementation::request::kMethodInfo] = [](Reader& visitor) + { + if (visitor.HasMember("error")) + return Rsp_Error::ReflectReader(visitor); + return td_implementation::response::ReflectReader(visitor); + }; + + handler.method2response[td_rangeFormatting::request::kMethodInfo] = [](Reader& visitor) + { + if (visitor.HasMember("error")) + return Rsp_Error::ReflectReader(visitor); + return td_rangeFormatting::response::ReflectReader(visitor); + }; + + handler.method2response[td_references::request::kMethodInfo] = [](Reader& visitor) + { + if (visitor.HasMember("error")) + return Rsp_Error::ReflectReader(visitor); + return td_references::response::ReflectReader(visitor); + }; + + handler.method2response[td_rename::request::kMethodInfo] = [](Reader& visitor) + { + if (visitor.HasMember("error")) + return Rsp_Error::ReflectReader(visitor); + return td_rename::response::ReflectReader(visitor); + }; + + + handler.method2response[td_signatureHelp::request::kMethodInfo] = [](Reader& visitor) + { + if (visitor.HasMember("error")) + return Rsp_Error::ReflectReader(visitor); + return td_signatureHelp::response::ReflectReader(visitor); + }; + + handler.method2response[td_typeDefinition::request::kMethodInfo] = [](Reader& visitor) + { + if (visitor.HasMember("error")) + return Rsp_Error::ReflectReader(visitor); + return td_typeDefinition::response::ReflectReader(visitor); + }; + + handler.method2response[wp_executeCommand::request::kMethodInfo] = [](Reader& visitor) + { + if (visitor.HasMember("error")) + return Rsp_Error::ReflectReader(visitor); + return wp_executeCommand::response::ReflectReader(visitor); + }; + + handler.method2response[wp_symbol::request::kMethodInfo] = [](Reader& visitor) + { + if (visitor.HasMember("error")) + return Rsp_Error::ReflectReader(visitor); + return wp_symbol::response::ReflectReader(visitor); + }; + handler.method2response[td_typeHierarchy::request::kMethodInfo] = [](Reader& visitor) + { + if (visitor.HasMember("error")) + return Rsp_Error::ReflectReader(visitor); + return td_typeHierarchy::response::ReflectReader(visitor); + }; + handler.method2response[completionItem_resolve::request::kMethodInfo] = [](Reader& visitor) + { + if (visitor.HasMember("error")) + return Rsp_Error::ReflectReader(visitor); + return completionItem_resolve::response::ReflectReader(visitor); + }; + + handler.method2response[codeLens_resolve::request::kMethodInfo] = [](Reader& visitor) + { + if (visitor.HasMember("error")) + return Rsp_Error::ReflectReader(visitor); + + return codeLens_resolve::response::ReflectReader(visitor); + + }; + + handler.method2response[td_colorPresentation::request::kMethodInfo] = [](Reader& visitor) + { + if (visitor.HasMember("error")) + return Rsp_Error::ReflectReader(visitor); + + return td_colorPresentation::response::ReflectReader(visitor); + + }; + handler.method2response[td_documentColor::request::kMethodInfo] = [](Reader& visitor) + { + if (visitor.HasMember("error")) + return Rsp_Error::ReflectReader(visitor); + + return td_documentColor::response::ReflectReader(visitor); + + }; + handler.method2response[td_foldingRange::request::kMethodInfo] = [](Reader& visitor) + { + if (visitor.HasMember("error")) + return Rsp_Error::ReflectReader(visitor); + + return td_foldingRange::response::ReflectReader(visitor); + + }; + handler.method2response[td_prepareRename::request::kMethodInfo] = [](Reader& visitor) + { + if (visitor.HasMember("error")) + return Rsp_Error::ReflectReader(visitor); + + return td_prepareRename::response::ReflectReader(visitor); + + }; + handler.method2response[typeHierarchy_resolve::request::kMethodInfo] = [](Reader& visitor) + { + if (visitor.HasMember("error")) + return Rsp_Error::ReflectReader(visitor); + + return typeHierarchy_resolve::response::ReflectReader(visitor); + + }; + + handler.method2response[td_selectionRange::request::kMethodInfo] = [](Reader& visitor) + { + if (visitor.HasMember("error")) + return Rsp_Error::ReflectReader(visitor); + + return td_selectionRange::response::ReflectReader(visitor); + + }; + handler.method2response[td_didRenameFiles::request::kMethodInfo] = [](Reader& visitor) + { + if (visitor.HasMember("error")) + return Rsp_Error::ReflectReader(visitor); + + return td_didRenameFiles::response::ReflectReader(visitor); + + }; + handler.method2response[td_willRenameFiles::request::kMethodInfo] = [](Reader& visitor) + { + if (visitor.HasMember("error")) + return Rsp_Error::ReflectReader(visitor); + + return td_willRenameFiles::response::ReflectReader(visitor); + + }; + +} + + +void AddJavaExtentionResponseJsonRpcMethod(MessageJsonHandler& handler) +{ + handler.method2response[java_classFileContents::request::kMethodInfo] = [](Reader& visitor) + { + if (visitor.HasMember("error")) + return Rsp_Error::ReflectReader(visitor); + + return java_classFileContents::response::ReflectReader(visitor); + }; + handler.method2response[java_buildWorkspace::request::kMethodInfo] = [](Reader& visitor) + { + if (visitor.HasMember("error")) + return Rsp_Error::ReflectReader(visitor); + + return java_buildWorkspace::response::ReflectReader(visitor); + }; + handler.method2response[java_listOverridableMethods::request::kMethodInfo] = [](Reader& visitor) + { + if (visitor.HasMember("error")) + return Rsp_Error::ReflectReader(visitor); + + return java_listOverridableMethods::response::ReflectReader(visitor); + }; + handler.method2response[java_listOverridableMethods::request::kMethodInfo] = [](Reader& visitor) + { + if (visitor.HasMember("error")) + return Rsp_Error::ReflectReader(visitor); + + return java_listOverridableMethods::response::ReflectReader(visitor); + }; + + handler.method2response[java_checkHashCodeEqualsStatus::request::kMethodInfo] = [](Reader& visitor) + { + if (visitor.HasMember("error")) + return Rsp_Error::ReflectReader(visitor); + + return java_checkHashCodeEqualsStatus::response::ReflectReader(visitor); + }; + + + handler.method2response[java_addOverridableMethods::request::kMethodInfo] = [](Reader& visitor) + { + if (visitor.HasMember("error")) + return Rsp_Error::ReflectReader(visitor); + + return java_addOverridableMethods::response::ReflectReader(visitor); + }; + + handler.method2response[java_checkConstructorsStatus::request::kMethodInfo] = [](Reader& visitor) + { + if (visitor.HasMember("error")) + return Rsp_Error::ReflectReader(visitor); + + return java_checkConstructorsStatus::response::ReflectReader(visitor); + }; + + + handler.method2response[java_checkDelegateMethodsStatus::request::kMethodInfo] = [](Reader& visitor) + { + if (visitor.HasMember("error")) + return Rsp_Error::ReflectReader(visitor); + + return java_checkDelegateMethodsStatus::response::ReflectReader(visitor); + }; + handler.method2response[java_checkToStringStatus::request::kMethodInfo] = [](Reader& visitor) + { + if (visitor.HasMember("error")) + return Rsp_Error::ReflectReader(visitor); + + return java_checkToStringStatus::response::ReflectReader(visitor); + }; + + + handler.method2response[java_generateAccessors::request::kMethodInfo] = [](Reader& visitor) + { + if (visitor.HasMember("error")) + return Rsp_Error::ReflectReader(visitor); + + return java_generateAccessors::response::ReflectReader(visitor); + }; + handler.method2response[java_generateConstructors::request::kMethodInfo] = [](Reader& visitor) + { + if (visitor.HasMember("error")) + return Rsp_Error::ReflectReader(visitor); + + return java_generateConstructors::response::ReflectReader(visitor); + }; + handler.method2response[java_generateDelegateMethods::request::kMethodInfo] = [](Reader& visitor) + { + if (visitor.HasMember("error")) + return Rsp_Error::ReflectReader(visitor); + + return java_generateDelegateMethods::response::ReflectReader(visitor); + }; + + handler.method2response[java_generateHashCodeEquals::request::kMethodInfo] = [](Reader& visitor) + { + if (visitor.HasMember("error")) + return Rsp_Error::ReflectReader(visitor); + + return java_generateHashCodeEquals::response::ReflectReader(visitor); + }; + handler.method2response[java_generateToString::request::kMethodInfo] = [](Reader& visitor) + { + if (visitor.HasMember("error")) + return Rsp_Error::ReflectReader(visitor); + + return java_generateToString::response::ReflectReader(visitor); + }; + + handler.method2response[java_generateToString::request::kMethodInfo] = [](Reader& visitor) + { + if (visitor.HasMember("error")) + return Rsp_Error::ReflectReader(visitor); + + return java_generateToString::response::ReflectReader(visitor); + }; + + handler.method2response[java_getMoveDestinations::request::kMethodInfo] = [](Reader& visitor) + { + if (visitor.HasMember("error")) + return Rsp_Error::ReflectReader(visitor); + + return java_getMoveDestinations::response::ReflectReader(visitor); + }; + + handler.method2response[java_getRefactorEdit::request::kMethodInfo] = [](Reader& visitor) + { + if (visitor.HasMember("error")) + return Rsp_Error::ReflectReader(visitor); + + return java_getRefactorEdit::response::ReflectReader(visitor); + }; + + handler.method2response[java_move::request::kMethodInfo] = [](Reader& visitor) + { + if (visitor.HasMember("error")) + return Rsp_Error::ReflectReader(visitor); + + return java_move::response ::ReflectReader(visitor); + }; + + handler.method2response[java_organizeImports::request::kMethodInfo] = [](Reader& visitor) + { + if (visitor.HasMember("error")) + return Rsp_Error::ReflectReader(visitor); + + return java_organizeImports::response::ReflectReader(visitor); + }; + + handler.method2response[java_resolveUnimplementedAccessors::request::kMethodInfo] = [](Reader& visitor) + { + if (visitor.HasMember("error")) + return Rsp_Error::ReflectReader(visitor); + + return java_resolveUnimplementedAccessors::response::ReflectReader(visitor); + }; + + handler.method2response[java_searchSymbols::request::kMethodInfo] = [](Reader& visitor) + { + if (visitor.HasMember("error")) + return Rsp_Error::ReflectReader(visitor); + + return java_searchSymbols::response::ReflectReader(visitor); + }; + + handler.method2request[WorkspaceConfiguration::request::kMethodInfo] = [](Reader& visitor) + { + return WorkspaceConfiguration::request::ReflectReader(visitor); + }; + handler.method2request[WorkspaceFolders::request::kMethodInfo] = [](Reader& visitor) + { + return WorkspaceFolders::request::ReflectReader(visitor); + }; + +} + +void AddNotifyJsonRpcMethod(MessageJsonHandler& handler) +{ + + handler.method2notification[Notify_Exit::notify::kMethodInfo] = [](Reader& visitor) + { + return Notify_Exit::notify::ReflectReader(visitor); + }; + handler.method2notification[Notify_InitializedNotification::notify::kMethodInfo] = [](Reader& visitor) + { + return Notify_InitializedNotification::notify::ReflectReader(visitor); + }; + + handler.method2notification[java_projectConfigurationUpdate::notify::kMethodInfo] = [](Reader& visitor) + { + return java_projectConfigurationUpdate::notify::ReflectReader(visitor); + }; + + handler.method2notification[Notify_TextDocumentDidChange::notify::kMethodInfo] = [](Reader& visitor) + { + return Notify_TextDocumentDidChange::notify::ReflectReader(visitor); + }; + + handler.method2notification[Notify_TextDocumentDidClose::notify::kMethodInfo] = [](Reader& visitor) + { + return Notify_TextDocumentDidClose::notify::ReflectReader(visitor); + }; + + + handler.method2notification[Notify_TextDocumentDidOpen::notify::kMethodInfo] = [](Reader& visitor) + { + return Notify_TextDocumentDidOpen::notify::ReflectReader(visitor); + }; + + handler.method2notification[Notify_TextDocumentDidSave::notify::kMethodInfo] = [](Reader& visitor) + { + return Notify_TextDocumentDidSave::notify::ReflectReader(visitor); + }; + + handler.method2notification[Notify_TextDocumentPublishDiagnostics::notify::kMethodInfo] = [](Reader& visitor) + { + return Notify_TextDocumentPublishDiagnostics::notify::ReflectReader(visitor); + }; + handler.method2notification[Notify_semanticHighlighting::notify::kMethodInfo] = [](Reader& visitor) + { + return Notify_semanticHighlighting::notify::ReflectReader(visitor); + }; + handler.method2notification[td_willSave::notify::kMethodInfo] = [](Reader& visitor) + { + return td_willSave::notify::ReflectReader(visitor); + }; + + handler.method2notification[Notify_LogMessage::notify::kMethodInfo] = [](Reader& visitor) + { + return Notify_LogMessage::notify::ReflectReader(visitor); + }; + handler.method2notification[Notify_ShowMessage::notify::kMethodInfo] = [](Reader& visitor) + { + return Notify_ShowMessage::notify::ReflectReader(visitor); + }; + handler.method2notification[Notify_WorkspaceDidChangeWorkspaceFolders::notify::kMethodInfo] = [](Reader& visitor) + { + return Notify_WorkspaceDidChangeWorkspaceFolders::notify::ReflectReader(visitor); + }; + + handler.method2notification[Notify_WorkspaceDidChangeConfiguration::notify::kMethodInfo] = [](Reader& visitor) + { + return Notify_WorkspaceDidChangeConfiguration::notify::ReflectReader(visitor); + }; + + + handler.method2notification[Notify_WorkspaceDidChangeWatchedFiles::notify::kMethodInfo] = [](Reader& visitor) + { + return Notify_WorkspaceDidChangeWatchedFiles::notify::ReflectReader(visitor); + }; + + handler.method2notification[Notify_sendNotification::notify::kMethodInfo] = [](Reader& visitor) + { + return Notify_sendNotification::notify::ReflectReader(visitor); + }; + handler.method2notification[lang_status::notify::kMethodInfo] = [](Reader& visitor) + { + return lang_status::notify::ReflectReader(visitor); + }; + handler.method2notification[lang_actionableNotification::notify::kMethodInfo] = [](Reader& visitor) + { + return lang_actionableNotification::notify::ReflectReader(visitor); + }; + handler.method2notification[lang_progressReport::notify::kMethodInfo] = [](Reader& visitor) + { + return lang_progressReport::notify::ReflectReader(visitor); + }; + handler.method2notification[lang_eventNotification::notify::kMethodInfo] = [](Reader& visitor) + { + return lang_eventNotification::notify::ReflectReader(visitor); + }; +} + +void AddRequstJsonRpcMethod(MessageJsonHandler& handler) +{ + handler.method2request[Req_ClientRegisterCapability::request::kMethodInfo]= [](Reader& visitor) + { + + return Req_ClientRegisterCapability::request::ReflectReader(visitor); + }; + handler.method2request[Req_ClientUnregisterCapability::request::kMethodInfo] = [](Reader& visitor) + { + + return Req_ClientUnregisterCapability::request::ReflectReader(visitor); + }; +} + +void AddStandardRequestJsonRpcMethod(MessageJsonHandler& handler) +{ + + handler.method2request[td_initialize::request::kMethodInfo] = [](Reader& visitor) + { + + return td_initialize::request::ReflectReader(visitor); + }; + handler.method2request[td_shutdown::request::kMethodInfo] = [](Reader& visitor) + { + + return td_shutdown::request::ReflectReader(visitor); + }; + handler.method2request[td_codeAction::request::kMethodInfo] = [](Reader& visitor) + { + + + return td_codeAction::request::ReflectReader(visitor); + }; + handler.method2request[td_codeLens::request::kMethodInfo] = [](Reader& visitor) + { + + return td_codeLens::request::ReflectReader(visitor); + }; + handler.method2request[td_completion::request::kMethodInfo] = [](Reader& visitor) + { + + return td_completion::request::ReflectReader(visitor); + }; + + handler.method2request[td_definition::request::kMethodInfo] = [](Reader& visitor) + { + + return td_definition::request::ReflectReader(visitor); + }; + handler.method2request[td_declaration::request::kMethodInfo] = [](Reader& visitor) + { + + return td_declaration::request::ReflectReader(visitor); + }; + handler.method2request[td_willSaveWaitUntil::request::kMethodInfo] = [](Reader& visitor) + { + if (visitor.HasMember("error")) + return Rsp_Error::ReflectReader(visitor); + return td_willSaveWaitUntil::request::ReflectReader(visitor); + }; + + handler.method2request[td_highlight::request::kMethodInfo] = [](Reader& visitor) + { + + return td_highlight::request::ReflectReader(visitor); + }; + + handler.method2request[td_links::request::kMethodInfo] = [](Reader& visitor) + { + + return td_links::request::ReflectReader(visitor); + }; + + handler.method2request[td_linkResolve::request::kMethodInfo] = [](Reader& visitor) + { + + return td_linkResolve::request::ReflectReader(visitor); + }; + + handler.method2request[td_symbol::request::kMethodInfo] = [](Reader& visitor) + { + + return td_symbol::request::ReflectReader(visitor); + }; + + handler.method2request[td_formatting::request::kMethodInfo] = [](Reader& visitor) + { + + return td_formatting::request::ReflectReader(visitor); + }; + + handler.method2request[td_hover::request::kMethodInfo] = [](Reader& visitor) + { + return td_hover::request::ReflectReader(visitor); + }; + + handler.method2request[td_implementation::request::kMethodInfo] = [](Reader& visitor) + { + + return td_implementation::request::ReflectReader(visitor); + }; + + handler.method2request[td_didRenameFiles::request::kMethodInfo] = [](Reader& visitor) + { + + return td_didRenameFiles::request::ReflectReader(visitor); + }; + + handler.method2request[td_willRenameFiles::request::kMethodInfo] = [](Reader& visitor) + { + return td_willRenameFiles::request::ReflectReader(visitor); + }; +} + + +lsp::ProtocolJsonHandler::ProtocolJsonHandler() +{ + AddStadardResponseJsonRpcMethod(*this); + AddJavaExtentionResponseJsonRpcMethod(*this); + AddNotifyJsonRpcMethod(*this); + AddStandardRequestJsonRpcMethod(*this); + AddRequstJsonRpcMethod(*this); +} diff --git a/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/ProtocolJsonHandler.h b/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/ProtocolJsonHandler.h new file mode 100644 index 00000000000..b563f810d2a --- /dev/null +++ b/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/ProtocolJsonHandler.h @@ -0,0 +1,11 @@ +#pragma once + +#include "LibLsp/JsonRpc/MessageJsonHandler.h" +namespace lsp { + class ProtocolJsonHandler : public MessageJsonHandler + { + public: + ProtocolJsonHandler(); + }; + +} diff --git a/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/ResourceOperation.h b/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/ResourceOperation.h new file mode 100644 index 00000000000..caf2ea5d5fd --- /dev/null +++ b/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/ResourceOperation.h @@ -0,0 +1,121 @@ +#pragma once + +#include "LibLsp/JsonRpc/serializer.h" +#include <vector> +#include "lsDocumentUri.h" +#include "LibLsp/lsp/lsAny.h" +#include "LibLsp/lsp/lsTextEdit.h" +struct ResourceOperation { + std::string kind; + virtual ~ResourceOperation() = default; + + MAKE_SWAP_METHOD(ResourceOperation, kind); +}; +MAKE_REFLECT_STRUCT(ResourceOperation, kind); +extern void Reflect(Writer& visitor, ResourceOperation* value); +struct CreateFileOptions{ + + /** + * Overwrite existing file. Overwrite wins over `ignoreIfExists` + */ + boost::optional<bool> overwrite = false; + + /** + * Ignore if exists. + */ + boost::optional< bool> ignoreIfExists =false; + + MAKE_SWAP_METHOD(CreateFileOptions, overwrite, ignoreIfExists) +}; +MAKE_REFLECT_STRUCT(CreateFileOptions, overwrite, ignoreIfExists) +struct lsCreateFile :public ResourceOperation { + + /** + * The resource to create. + */ + lsCreateFile(); + lsDocumentUri uri; + + /** + * Additional options + */ + boost::optional<CreateFileOptions> options; + + + /** + * An optional annotation identifer describing the operation. + * + * @since 3.16.0 + */ + boost::optional<lsChangeAnnotationIdentifier> annotationId; + + MAKE_SWAP_METHOD(lsCreateFile, kind, uri, options, annotationId) +}; +MAKE_REFLECT_STRUCT(lsCreateFile, kind, uri,options, annotationId) + + +struct DeleteFileOptions { + /** + * Delete the content recursively if a folder is denoted. + */ + boost::optional<bool> recursive = false; + + /** + * Ignore the operation if the file doesn't exist. + */ + boost::optional<bool> ignoreIfNotExists = false; + + + MAKE_SWAP_METHOD(DeleteFileOptions, recursive, ignoreIfNotExists); +}; + +MAKE_REFLECT_STRUCT(DeleteFileOptions, recursive, ignoreIfNotExists) + +struct lsDeleteFile :public ResourceOperation { + /** + * The file to delete. + */ + lsDeleteFile(); + lsDocumentUri uri; + + /** + * Delete options. + */ + boost::optional<DeleteFileOptions> options; + + MAKE_SWAP_METHOD(lsDeleteFile, kind, uri, options); +}; +MAKE_REFLECT_STRUCT(lsDeleteFile, kind, uri,options); + +typedef CreateFileOptions RenameFileOptions; +struct lsRenameFile :public ResourceOperation { + /** + * The old (existing) location. + */ + lsRenameFile(); + lsDocumentUri oldUri; + + /** + * The new location. + */ + + lsDocumentUri newUri; + + /** + * Rename options. + */ + boost::optional<RenameFileOptions> options; + + /** + * An optional annotation identifer describing the operation. + * + * @since 3.16.0 + */ + boost::optional<lsChangeAnnotationIdentifier> annotationId; + + MAKE_SWAP_METHOD(lsRenameFile, kind, oldUri, newUri, options, annotationId) +}; +MAKE_REFLECT_STRUCT(lsRenameFile, kind, oldUri, newUri, options, annotationId); + + +extern ResourceOperation* GetResourceOperation(lsp::Any& lspAny);
\ No newline at end of file diff --git a/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/SimpleTimer.h b/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/SimpleTimer.h new file mode 100644 index 00000000000..0a2707979da --- /dev/null +++ b/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/SimpleTimer.h @@ -0,0 +1,49 @@ +#pragma once +#include <thread> +#include <atomic> +#include <functional> +#include <boost/asio.hpp> + +template<typename Duration = boost::posix_time::milliseconds> +class SimpleTimer +{ +public: + SimpleTimer(unsigned int duration,const std::function<void()>& _call_back) + :is_running_(true), call_back(_call_back), _deadline_timer(_ios, Duration(duration)) + { + _deadline_timer.async_wait([&](const boost::system::error_code& e) + { + if (e.value() == boost::asio::error::operation_aborted) + { + return; + } + if(is_running_.load(std::memory_order_relaxed)) + { + call_back(); + } + + }); + _thread = std::thread([this] { _ios.run(); }); + } + ~SimpleTimer() + { + Stop(); + } + void Stop() + { + is_running_.store(false, std::memory_order_relaxed); + _ios.stop(); + if (_thread.joinable()) + { + _thread.join(); + } + } +private: + std::atomic_bool is_running_; + std::function<void()> call_back; + boost::asio::io_service _ios; + boost::asio::deadline_timer _deadline_timer; + std::thread _thread; + + +}; diff --git a/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/client/registerCapability.h b/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/client/registerCapability.h new file mode 100644 index 00000000000..fa5d1114037 --- /dev/null +++ b/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/client/registerCapability.h @@ -0,0 +1,49 @@ +#pragma once +#include "LibLsp/JsonRpc/message.h" +#include "LibLsp/lsp/lsDocumentUri.h" + +/** + * General parameters to register for a capability. + */ + +struct Registration { + static Registration Create(const std::string& method); + /** + * The id used to register the request. The id can be used to deregister + * the request again. + */ + std::string id; + + /** + * The method / capability to register for. + */ + + std::string method; + + MAKE_SWAP_METHOD(Registration, id, method); +}; + + +MAKE_REFLECT_STRUCT(Registration, id, method); + +/** + * The client/registerCapability request is sent from the server to the client to register + * for a new capability on the client side. Not all clients need to support dynamic + * capability registration. A client opts in via the dynamicRegistration property on the + * specific client capabilities. A client can even provide dynamic registration for + * capability A but not for capability B (see TextDocumentClientCapabilities as an example). + */ +struct RegistrationParams +{ + std::vector<Registration> registrations; + MAKE_SWAP_METHOD(RegistrationParams, registrations); +}; +/** + * The client/registerCapability request is sent from the server to the client + * to register for a new capability on the client side. + * Not all clients need to support dynamic capability registration. + * A client opts in via the ClientCapabilities.dynamicRegistration property + */ +MAKE_REFLECT_STRUCT(RegistrationParams, registrations); + +DEFINE_REQUEST_RESPONSE_TYPE(Req_ClientRegisterCapability, RegistrationParams,JsonNull, "client/registerCapability");
\ No newline at end of file diff --git a/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/client/unregisterCapability.h b/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/client/unregisterCapability.h new file mode 100644 index 00000000000..aa51d7efeee --- /dev/null +++ b/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/client/unregisterCapability.h @@ -0,0 +1,41 @@ +#pragma once + +#include "LibLsp/lsp/lsDocumentUri.h" + +#include "LibLsp/JsonRpc/RequestInMessage.h" +#include "LibLsp/JsonRpc/lsResponseMessage.h" + +/** + * General parameters to unregister a capability. + */ + +struct Unregistration { + /** + * The id used to unregister the request or notification. Usually an id + * provided during the register request. + */ + + std::string id; + + /** + * The method / capability to unregister for. + */ + + std::string method; + + MAKE_SWAP_METHOD(Unregistration, id, method); +}; +MAKE_REFLECT_STRUCT(Unregistration, id, method); +/** + * The client/unregisterCapability request is sent from the server to the client to unregister + * a previously registered capability. + */ +struct UnregistrationParams +{ + std::vector<Unregistration> unregisterations; + MAKE_SWAP_METHOD(UnregistrationParams, unregisterations); +}; + +MAKE_REFLECT_STRUCT(UnregistrationParams, unregisterations); + +DEFINE_REQUEST_RESPONSE_TYPE(Req_ClientUnregisterCapability, UnregistrationParams,JsonNull, "client/unregisterCapability");
\ No newline at end of file diff --git a/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/extention/jdtls/Move.h b/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/extention/jdtls/Move.h new file mode 100644 index 00000000000..c0beb625f2b --- /dev/null +++ b/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/extention/jdtls/Move.h @@ -0,0 +1,14 @@ +#pragma once + +#include "LibLsp/JsonRpc/RequestInMessage.h" +#include "LibLsp/JsonRpc/lsResponseMessage.h" +#include <string> +#include "LibLsp/lsp/CodeActionParams.h" +#include "getMoveDestinations.h" +#include "getRefactorEdit.h" + + +DEFINE_REQUEST_RESPONSE_TYPE(java_move, MoveParams, RefactorWorkspaceEdit, "java/move"); + + + diff --git a/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/extention/jdtls/OverridableMethod.h b/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/extention/jdtls/OverridableMethod.h new file mode 100644 index 00000000000..cfb17fdf34d --- /dev/null +++ b/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/extention/jdtls/OverridableMethod.h @@ -0,0 +1,34 @@ +#pragma once + +#include "LibLsp/JsonRpc/serializer.h" +#include <string> +struct OverridableMethod +{ + std::string bindingKey; + std::string name; + std::vector<std::string> parameters; + bool unimplemented = false; + std::string declaringClass; + std::string declaringClassType; + + void swap(OverridableMethod& arg) noexcept + { + bindingKey.swap(arg.bindingKey); + name.swap(arg.name); + parameters.swap(arg.parameters); + declaringClass.swap(arg.declaringClass); + declaringClassType.swap(arg.declaringClassType); + std::swap(unimplemented, arg.unimplemented); + } +}; +MAKE_REFLECT_STRUCT(OverridableMethod, bindingKey, name, parameters, unimplemented, declaringClass, declaringClassType); + +struct OverridableMethodsResponse +{ + std::string type; + std::vector<OverridableMethod> methods; + + MAKE_SWAP_METHOD(OverridableMethodsResponse, type, methods) +}; + +MAKE_REFLECT_STRUCT(OverridableMethodsResponse, type, methods) diff --git a/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/extention/jdtls/WorkspaceSymbolParams.h b/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/extention/jdtls/WorkspaceSymbolParams.h new file mode 100644 index 00000000000..c7faa94d6c9 --- /dev/null +++ b/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/extention/jdtls/WorkspaceSymbolParams.h @@ -0,0 +1,13 @@ +#pragma once + +#include "LibLsp/JsonRpc/serializer.h" +#include <string> + + +struct WorkspaceSymbolParams +{ + std::string query; + MAKE_SWAP_METHOD(WorkspaceSymbolParams, query); +}; +MAKE_REFLECT_STRUCT(WorkspaceSymbolParams, query); + diff --git a/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/extention/jdtls/addOverridableMethods.h b/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/extention/jdtls/addOverridableMethods.h new file mode 100644 index 00000000000..5da14a452a7 --- /dev/null +++ b/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/extention/jdtls/addOverridableMethods.h @@ -0,0 +1,19 @@ +#pragma once + +#include "LibLsp/JsonRpc/message.h" +#include "OverridableMethod.h" +#include "LibLsp/lsp/CodeActionParams.h" +#include "LibLsp/JsonRpc/RequestInMessage.h" +#include "LibLsp/JsonRpc/lsResponseMessage.h" +struct AddOverridableMethodParams { + lsCodeActionParams context; + std::vector<OverridableMethod> overridableMethods; + + MAKE_SWAP_METHOD(AddOverridableMethodParams, context, overridableMethods); +}; + +MAKE_REFLECT_STRUCT(AddOverridableMethodParams, context, overridableMethods); + +DEFINE_REQUEST_RESPONSE_TYPE(java_addOverridableMethods, AddOverridableMethodParams, lsWorkspaceEdit, "java/addOverridableMethods"); + + diff --git a/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/extention/jdtls/buildWorkspace.h b/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/extention/jdtls/buildWorkspace.h new file mode 100644 index 00000000000..a2c2c062ccf --- /dev/null +++ b/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/extention/jdtls/buildWorkspace.h @@ -0,0 +1,17 @@ +#pragma once + +#include "WorkspaceSymbolParams.h" +#include "LibLsp/JsonRpc/RequestInMessage.h" +#include "LibLsp/JsonRpc/lsResponseMessage.h" + + + + + +enum class BuildWorkspaceStatus : uint8_t{ + + FAILED, SUCCEED, WITH_ERROR, CANCELLED, +}; +MAKE_REFLECT_TYPE_PROXY(BuildWorkspaceStatus) + +DEFINE_REQUEST_RESPONSE_TYPE(java_buildWorkspace, bool, BuildWorkspaceStatus, "java/buildWorkspace");
\ No newline at end of file diff --git a/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/extention/jdtls/checkConstructorsStatus.h b/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/extention/jdtls/checkConstructorsStatus.h new file mode 100644 index 00000000000..261a0cc5516 --- /dev/null +++ b/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/extention/jdtls/checkConstructorsStatus.h @@ -0,0 +1,29 @@ +#pragma once + +#include "LibLsp/JsonRpc/RequestInMessage.h" +#include "LibLsp/JsonRpc/lsResponseMessage.h" +#include "LibLsp/lsp/CodeActionParams.h" +#include "checkHashCodeEqualsStatus.h" + +struct LspMethodBinding { + std::string bindingKey; + std::string name; + std::vector< std::string> parameters; + + MAKE_SWAP_METHOD(LspMethodBinding, bindingKey, name, parameters); +}; +MAKE_REFLECT_STRUCT(LspMethodBinding, bindingKey, name, parameters); + + +struct CheckConstructorsResponse { + std::vector<LspMethodBinding> constructors; + std::vector<LspVariableBinding> fields; + MAKE_SWAP_METHOD(CheckConstructorsResponse, constructors, fields) +}; +MAKE_REFLECT_STRUCT(CheckConstructorsResponse, constructors,fields) + +DEFINE_REQUEST_RESPONSE_TYPE(java_checkConstructorsStatus, lsCodeActionParams, CheckConstructorsResponse,"java/checkConstructorsStatus") + + + + diff --git a/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/extention/jdtls/checkDelegateMethodsStatus.h b/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/extention/jdtls/checkDelegateMethodsStatus.h new file mode 100644 index 00000000000..729639eafa5 --- /dev/null +++ b/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/extention/jdtls/checkDelegateMethodsStatus.h @@ -0,0 +1,29 @@ +#pragma once + +#include "LibLsp/JsonRpc/RequestInMessage.h" +#include "LibLsp/JsonRpc/lsResponseMessage.h" + +#include "LibLsp/lsp/CodeActionParams.h" +#include "checkHashCodeEqualsStatus.h" +#include "checkConstructorsStatus.h" + +struct LspDelegateField { + LspVariableBinding field; + std::vector<LspMethodBinding> delegateMethods; + + MAKE_SWAP_METHOD(LspDelegateField, field, delegateMethods); +}; +MAKE_REFLECT_STRUCT(LspDelegateField, field, delegateMethods); + + +struct CheckDelegateMethodsResponse { + std::vector<LspDelegateField> delegateFields; + + MAKE_SWAP_METHOD(CheckDelegateMethodsResponse, delegateFields) +}; +MAKE_REFLECT_STRUCT(CheckDelegateMethodsResponse, delegateFields) + +DEFINE_REQUEST_RESPONSE_TYPE(java_checkDelegateMethodsStatus, + lsCodeActionParams, CheckDelegateMethodsResponse, "java/checkDelegateMethodsStatus"); + + diff --git a/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/extention/jdtls/checkHashCodeEqualsStatus.h b/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/extention/jdtls/checkHashCodeEqualsStatus.h new file mode 100644 index 00000000000..1d9652dd442 --- /dev/null +++ b/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/extention/jdtls/checkHashCodeEqualsStatus.h @@ -0,0 +1,36 @@ +#pragma once + +#include "LibLsp/JsonRpc/RequestInMessage.h" +#include "LibLsp/JsonRpc/lsResponseMessage.h" + +#include <LibLsp/lsp/lsCodeAction.h> + +#include "LibLsp/lsp/CodeActionParams.h" + +struct LspVariableBinding { + std::string bindingKey; + std::string name; + std::string type; + bool isField; + void swap(LspVariableBinding& arg) noexcept + { + bindingKey.swap(arg.bindingKey); + name.swap(arg.name); + type.swap(arg.type); + std::swap(isField, arg.isField); + } +}; +MAKE_REFLECT_STRUCT(LspVariableBinding, bindingKey, name, type, isField) + +struct CheckHashCodeEqualsResponse { + std::string type; + std::vector<LspVariableBinding> fields; + std::vector<std::string> existingMethods; + MAKE_SWAP_METHOD(CheckHashCodeEqualsResponse, type, fields, type, existingMethods) +}; +MAKE_REFLECT_STRUCT(CheckHashCodeEqualsResponse, type, fields, type, existingMethods) + +DEFINE_REQUEST_RESPONSE_TYPE(java_checkHashCodeEqualsStatus, + lsCodeActionParams, CheckHashCodeEqualsResponse, "java/checkHashCodeEqualsStatus") + + diff --git a/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/extention/jdtls/checkToStringStatus.h b/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/extention/jdtls/checkToStringStatus.h new file mode 100644 index 00000000000..24580d94c07 --- /dev/null +++ b/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/extention/jdtls/checkToStringStatus.h @@ -0,0 +1,24 @@ +#pragma once + +#include "LibLsp/JsonRpc/RequestInMessage.h" +#include "LibLsp/JsonRpc/lsResponseMessage.h" + +#include "LibLsp/lsp/CodeActionParams.h" +#include "checkHashCodeEqualsStatus.h" +struct CheckToStringResponse { + std::string type; + std::vector<LspVariableBinding> fields; + bool exists; + void swap(CheckToStringResponse& arg) noexcept + { + type.swap(arg.type); + fields.swap(arg.fields); + std::swap(exists, arg.exists); + } +}; +MAKE_REFLECT_STRUCT(CheckToStringResponse,type,fields,exists) + +DEFINE_REQUEST_RESPONSE_TYPE(java_checkToStringStatus, + lsCodeActionParams, CheckToStringResponse ,"java/checkToStringStatus") + + diff --git a/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/extention/jdtls/classFileContents.h b/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/extention/jdtls/classFileContents.h new file mode 100644 index 00000000000..70eb121b998 --- /dev/null +++ b/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/extention/jdtls/classFileContents.h @@ -0,0 +1,10 @@ +#pragma once + +#include "LibLsp/JsonRpc/RequestInMessage.h" +#include "LibLsp/JsonRpc/lsResponseMessage.h" + +#include <string> +#include "LibLsp/lsp/lsTextDocumentIdentifier.h" + +DEFINE_REQUEST_RESPONSE_TYPE(java_classFileContents, lsTextDocumentIdentifier, std::string ,"java/classFileContents"); + diff --git a/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/extention/jdtls/codeActionResult.h b/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/extention/jdtls/codeActionResult.h new file mode 100644 index 00000000000..02024e3d931 --- /dev/null +++ b/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/extention/jdtls/codeActionResult.h @@ -0,0 +1,22 @@ +#pragma once + +#include "LibLsp/JsonRpc/serializer.h" +#include "LibLsp/JsonRpc/message.h" +#include "LibLsp/lsp/lsCodeAction.h" +#include "LibLsp/lsp/workspace/execute_command.h" +#include <set> +#include "LibLsp/lsp/textDocument/code_action.h" + +namespace SourceAssistProcessor { + + /*std::set<std::string> UNSUPPORTED_RESOURCES = { "module-info.java", "package-info.java" + };*/ + +// static const char* COMMAND_ID_ACTION_OVERRIDEMETHODSPROMPT = "java.action.overrideMethodsPrompt"; +// static const char* COMMAND_ID_ACTION_HASHCODEEQUALSPROMPT = "java.action.hashCodeEqualsPrompt"; +// static const char* COMMAND_ID_ACTION_ORGANIZEIMPORTS = "java.action.organizeImports"; +// static const char* COMMAND_ID_ACTION_GENERATETOSTRINGPROMPT = "java.action.generateToStringPrompt"; +// static const char* COMMAND_ID_ACTION_GENERATEACCESSORSPROMPT = "java.action.generateAccessorsPrompt"; +// static const char* COMMAND_ID_ACTION_GENERATECONSTRUCTORSPROMPT = "java.action.generateConstructorsPrompt"; +// static const char* COMMAND_ID_ACTION_GENERATEDELEGATEMETHODSPROMPT = "java.action.generateDelegateMethodsPrompt"; +}; diff --git a/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/extention/jdtls/executeCommand.h b/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/extention/jdtls/executeCommand.h new file mode 100644 index 00000000000..92d4a3627bf --- /dev/null +++ b/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/extention/jdtls/executeCommand.h @@ -0,0 +1,29 @@ +#pragma once +#include "LibLsp/JsonRpc/RequestInMessage.h" +#include "LibLsp/JsonRpc/lsResponseMessage.h" +#include <string> +#include "LibLsp/lsp/lsWorkspaceEdit.h" +#include "LibLsp/lsp/ExecuteCommandParams.h" +namespace buildpath +{ +// static const char* EDIT_ORGNIZEIMPORTS = "java.edit.organizeImports"; +// static const char* RESOLVE_SOURCE_ATTACHMENT = "java.project.resolveSourceAttachment"; + +// static const char* UPDATE_SOURCE_ATTACHMENT = "java.project.updateSourceAttachment"; + +// static const char* ADD_TO_SOURCEPATH = "java.project.addToSourcePath"; + +// static const char* REMOVE_FROM_SOURCEPATH = "java.project.removeFromSourcePath"; + +// static const char* LIST_SOURCEPATHS = "java.project.listSourcePaths"; + struct Result { + bool status; + std::string message; + }; + + + +} + + +DEFINE_REQUEST_RESPONSE_TYPE(java_executeCommand, ExecuteCommandParams, lsWorkspaceEdit, "java/executeCommand"); diff --git a/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/extention/jdtls/findLinks.h b/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/extention/jdtls/findLinks.h new file mode 100644 index 00000000000..d184c675d83 --- /dev/null +++ b/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/extention/jdtls/findLinks.h @@ -0,0 +1,22 @@ +#pragma once + +#include "LibLsp/JsonRpc/RequestInMessage.h" +#include "LibLsp/JsonRpc/lsResponseMessage.h" +#include <string> +#include "LibLsp/lsp/CodeActionParams.h" +#include "getRefactorEdit.h" +#include "LibLsp/lsp/lsTextDocumentPositionParams.h" + +struct FindLinksParams { + // Supported link types: superImplementation + std::string type; + lsTextDocumentPositionParams position; + + MAKE_SWAP_METHOD(FindLinksParams, type, position) +}; +MAKE_REFLECT_STRUCT(FindLinksParams,type,position) + +DEFINE_REQUEST_RESPONSE_TYPE(java_findLinks, FindLinksParams,lsp::Any, "java/findLinks"); + + + diff --git a/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/extention/jdtls/generateAccessors.h b/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/extention/jdtls/generateAccessors.h new file mode 100644 index 00000000000..200d840e940 --- /dev/null +++ b/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/extention/jdtls/generateAccessors.h @@ -0,0 +1,19 @@ +#pragma once + +#include "LibLsp/JsonRpc/RequestInMessage.h" +#include "LibLsp/JsonRpc/lsResponseMessage.h" +#include <string> +#include "checkHashCodeEqualsStatus.h" +#include "resolveUnimplementedAccessors.h" + + +struct GenerateAccessorsParams { + lsCodeActionParams context; + std::vector<AccessorField> accessors; + + + MAKE_SWAP_METHOD(GenerateAccessorsParams, context, accessors) +}; +MAKE_REFLECT_STRUCT(GenerateAccessorsParams, context, accessors) + +DEFINE_REQUEST_RESPONSE_TYPE(java_generateAccessors, GenerateAccessorsParams, lsWorkspaceEdit, "java/generateAccessors"); diff --git a/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/extention/jdtls/generateConstructors.h b/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/extention/jdtls/generateConstructors.h new file mode 100644 index 00000000000..77c49a66a29 --- /dev/null +++ b/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/extention/jdtls/generateConstructors.h @@ -0,0 +1,19 @@ +#pragma once + +#include "LibLsp/JsonRpc/RequestInMessage.h" +#include "LibLsp/JsonRpc/lsResponseMessage.h" +#include <string> +#include "checkHashCodeEqualsStatus.h" +#include "checkConstructorsStatus.h" + + +struct GenerateConstructorsParams { + lsCodeActionParams context; + std::vector<LspMethodBinding> constructors; + std::vector< LspVariableBinding >fields; + MAKE_SWAP_METHOD(GenerateConstructorsParams, context, fields) +}; +MAKE_REFLECT_STRUCT(GenerateConstructorsParams, context, fields) + +DEFINE_REQUEST_RESPONSE_TYPE(java_generateConstructors, GenerateConstructorsParams, lsWorkspaceEdit, "java/generateConstructors"); + diff --git a/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/extention/jdtls/generateDelegateMethods.h b/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/extention/jdtls/generateDelegateMethods.h new file mode 100644 index 00000000000..8958ae4d7ed --- /dev/null +++ b/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/extention/jdtls/generateDelegateMethods.h @@ -0,0 +1,25 @@ +#pragma once + +#include "LibLsp/JsonRpc/RequestInMessage.h" +#include "LibLsp/JsonRpc/lsResponseMessage.h" +#include <string> +#include "checkHashCodeEqualsStatus.h" +#include "checkConstructorsStatus.h" + +struct LspDelegateEntry { + LspVariableBinding field; + LspMethodBinding delegateMethod; + MAKE_SWAP_METHOD(LspDelegateEntry, field, delegateMethod); +}; +MAKE_REFLECT_STRUCT(LspDelegateEntry, field, delegateMethod); + + +struct GenerateDelegateMethodsParams { + lsCodeActionParams context; + std::vector<LspDelegateEntry> delegateEntries; + MAKE_SWAP_METHOD(GenerateDelegateMethodsParams, context, delegateEntries) +}; +MAKE_REFLECT_STRUCT(GenerateDelegateMethodsParams, context, delegateEntries) + +DEFINE_REQUEST_RESPONSE_TYPE(java_generateDelegateMethods, GenerateDelegateMethodsParams, lsWorkspaceEdit, "java/generateDelegateMethods"); + diff --git a/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/extention/jdtls/generateHashCodeEquals.h b/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/extention/jdtls/generateHashCodeEquals.h new file mode 100644 index 00000000000..937c3587338 --- /dev/null +++ b/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/extention/jdtls/generateHashCodeEquals.h @@ -0,0 +1,25 @@ +#pragma once + +#include "LibLsp/JsonRpc/RequestInMessage.h" +#include "LibLsp/JsonRpc/lsResponseMessage.h" +#include <LibLsp/lsp/lsCodeAction.h> + +#include "LibLsp/lsp/CodeActionParams.h" +#include "checkHashCodeEqualsStatus.h" + +struct GenerateHashCodeEqualsParams { + lsCodeActionParams context; + std::vector<LspVariableBinding> fields; + bool regenerate= false; + void swap(GenerateHashCodeEqualsParams& arg) noexcept + { + context.swap(arg.context); + fields.swap(arg.fields); + std::swap(regenerate, arg.regenerate); + } +}; +MAKE_REFLECT_STRUCT(GenerateHashCodeEqualsParams, context, fields, regenerate); + +DEFINE_REQUEST_RESPONSE_TYPE(java_generateHashCodeEquals, GenerateHashCodeEqualsParams, lsWorkspaceEdit, "java/generateHashCodeEquals") + + diff --git a/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/extention/jdtls/generateToString.h b/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/extention/jdtls/generateToString.h new file mode 100644 index 00000000000..1f8ccc73b87 --- /dev/null +++ b/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/extention/jdtls/generateToString.h @@ -0,0 +1,18 @@ +#pragma once + +#include "LibLsp/JsonRpc/RequestInMessage.h" +#include "LibLsp/JsonRpc/lsResponseMessage.h" +#include <string> +#include "checkHashCodeEqualsStatus.h" + + +struct GenerateToStringParams { + lsCodeActionParams context; + std::vector< LspVariableBinding >fields; + + MAKE_SWAP_METHOD(GenerateToStringParams, context, fields) + +}; +MAKE_REFLECT_STRUCT(GenerateToStringParams, context, fields) + +DEFINE_REQUEST_RESPONSE_TYPE(java_generateToString, GenerateToStringParams, lsWorkspaceEdit, "java/generateToString"); diff --git a/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/extention/jdtls/getMoveDestinations.h b/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/extention/jdtls/getMoveDestinations.h new file mode 100644 index 00000000000..bcbf6f8c2ba --- /dev/null +++ b/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/extention/jdtls/getMoveDestinations.h @@ -0,0 +1,65 @@ +#pragma once + +#include "LibLsp/JsonRpc/RequestInMessage.h" +#include "LibLsp/JsonRpc/lsResponseMessage.h" +#include <string> +#include "LibLsp/lsp/lsAny.h" +#include "LibLsp/lsp/CodeActionParams.h" + +struct MoveKindInfo +{ + static std::string moveResource() + { + return "moveResource"; + } + static std::string moveInstanceMethod() + { + return "moveInstanceMethod"; + } + static std::string moveStaticMember() + { + return "moveStaticMember"; + } +}; + +struct MoveParams { + /** + * The supported move kind: moveResource, moveInstanceMethod, moveStaticMember, + * moveTypeToNewFile. + */ + std::string moveKind; + /** + * The selected resource uris when the move operation is triggered. + */ + std::vector<std::string> sourceUris; + /** + * The code action params when the move operation is triggered. + */ + boost::optional<lsCodeActionParams> params; + /** + * The possible destination: a folder/package, class, instanceDeclaration. + */ + lsp::Any destination; + bool updateReferences; + void swap(MoveParams& arg) noexcept + { + moveKind.swap(arg.moveKind); + sourceUris.swap(arg.sourceUris); + params.swap(arg.params); + destination.swap(arg.destination); + std::swap(updateReferences, arg.updateReferences); + } +}; +MAKE_REFLECT_STRUCT(MoveParams, moveKind, sourceUris, params, destination, updateReferences); + +struct MoveDestinationsResponse { + std::string errorMessage; + std::vector<lsp::Any > destinations; + MAKE_SWAP_METHOD(MoveDestinationsResponse, errorMessage, destinations); +}; +MAKE_REFLECT_STRUCT(MoveDestinationsResponse, errorMessage, destinations); + +DEFINE_REQUEST_RESPONSE_TYPE(java_getMoveDestinations, MoveParams, MoveDestinationsResponse, "java/getMoveDestinations"); + + + diff --git a/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/extention/jdtls/getRefactorEdit.h b/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/extention/jdtls/getRefactorEdit.h new file mode 100644 index 00000000000..e46327075a5 --- /dev/null +++ b/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/extention/jdtls/getRefactorEdit.h @@ -0,0 +1,77 @@ +#pragma once + +#include "LibLsp/JsonRpc/RequestInMessage.h" +#include "LibLsp/JsonRpc/lsResponseMessage.h" + + + +#include <string> +#include <vector> +#include "WorkspaceSymbolParams.h" +#include "LibLsp/lsp/method_type.h" +#include "LibLsp/lsp/textDocument/code_action.h" +#include "LibLsp/lsp/lsFormattingOptions.h" + +namespace +RefactorProposalUtility +{ + extern const char* APPLY_REFACTORING_COMMAND_ID; + extern const char* EXTRACT_VARIABLE_ALL_OCCURRENCE_COMMAND; + extern const char* EXTRACT_VARIABLE_COMMAND; + extern const char* EXTRACT_CONSTANT_COMMAND; + extern const char* EXTRACT_METHOD_COMMAND; + extern const char* EXTRACT_FIELD_COMMAND; + extern const char* CONVERT_VARIABLE_TO_FIELD_COMMAND; + extern const char* MOVE_FILE_COMMAND; + extern const char* MOVE_INSTANCE_METHOD_COMMAND; + extern const char* MOVE_STATIC_MEMBER_COMMAND; + extern const char* MOVE_TYPE_COMMAND; +}; + + +struct RenamePosition { + lsDocumentUri uri; + int offset = 0; + int length = 0; + void swap(RenamePosition& arg) noexcept + { + uri.swap(arg.uri); + std::swap(offset, arg.offset); + std::swap(length, arg.length); + } +}; +MAKE_REFLECT_STRUCT(RenamePosition, uri, offset, length); + +struct GetRefactorEditParams +{ + std::string command; + std::vector<lsp::Any> commandArguments; + lsCodeActionParams context; + boost::optional<lsFormattingOptions> options; + MAKE_SWAP_METHOD(GetRefactorEditParams, command, context, options); +}; +MAKE_REFLECT_STRUCT(GetRefactorEditParams, command, context, options); + + + + +struct RefactorWorkspaceEdit { + /** + * The workspace edit this code action performs. + */ + lsWorkspaceEdit edit; + /** + * A command this code action executes. If a code action provides a edit and a + * command, first the edit is executed and then the command. + */ + + boost::optional<std::string> errorMessage; + + boost::optional < lsCommandWithAny > command; + + MAKE_SWAP_METHOD(RefactorWorkspaceEdit, edit, command, errorMessage) +}; +MAKE_REFLECT_STRUCT(RefactorWorkspaceEdit,edit,command,errorMessage) + +DEFINE_REQUEST_RESPONSE_TYPE(java_getRefactorEdit, GetRefactorEditParams, RefactorWorkspaceEdit, "java/getRefactorEdit"); + diff --git a/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/extention/jdtls/listOverridableMethods.h b/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/extention/jdtls/listOverridableMethods.h new file mode 100644 index 00000000000..13b73ce5c28 --- /dev/null +++ b/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/extention/jdtls/listOverridableMethods.h @@ -0,0 +1,17 @@ +#pragma once + +#include "LibLsp/JsonRpc/RequestInMessage.h" +#include "LibLsp/JsonRpc/lsResponseMessage.h" + +#include "LibLsp/lsp/CodeActionParams.h" +#include "OverridableMethod.h" + + + + + +DEFINE_REQUEST_RESPONSE_TYPE(java_listOverridableMethods, lsCodeActionParams, OverridableMethodsResponse, "java/listOverridableMethods"); + + + + diff --git a/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/extention/jdtls/organizeImports.h b/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/extention/jdtls/organizeImports.h new file mode 100644 index 00000000000..817d52d32b8 --- /dev/null +++ b/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/extention/jdtls/organizeImports.h @@ -0,0 +1,12 @@ +#pragma once +#include "LibLsp/JsonRpc/RequestInMessage.h" +#include "LibLsp/JsonRpc/lsResponseMessage.h" +#include <LibLsp/lsp/lsCodeAction.h> + +#include "LibLsp/lsp/CodeActionParams.h" + + + +DEFINE_REQUEST_RESPONSE_TYPE(java_organizeImports, lsCodeActionParams, lsWorkspaceEdit, "java/organizeImports"); + + diff --git a/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/extention/jdtls/projectConfigurationUpdate.h b/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/extention/jdtls/projectConfigurationUpdate.h new file mode 100644 index 00000000000..342d167093a --- /dev/null +++ b/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/extention/jdtls/projectConfigurationUpdate.h @@ -0,0 +1,13 @@ +#pragma once + +#include "LibLsp/JsonRpc/NotificationInMessage.h" + + +#include <string> +#include <vector> +#include "WorkspaceSymbolParams.h" + +#include "LibLsp/lsp/lsTextDocumentIdentifier.h" + +DEFINE_NOTIFICATION_TYPE(java_projectConfigurationUpdate, lsTextDocumentIdentifier, "java/projectConfigurationUpdate"); + diff --git a/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/extention/jdtls/resolveUnimplementedAccessors.h b/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/extention/jdtls/resolveUnimplementedAccessors.h new file mode 100644 index 00000000000..ba77041474f --- /dev/null +++ b/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/extention/jdtls/resolveUnimplementedAccessors.h @@ -0,0 +1,24 @@ +#pragma once + +#include "LibLsp/JsonRpc/RequestInMessage.h" +#include "LibLsp/JsonRpc/lsResponseMessage.h" +#include <string> +#include "checkHashCodeEqualsStatus.h" + + +struct AccessorField { + std::string fieldName; + bool isStatic =false; + bool generateGetter = false; + bool generateSetter = false; + void swap(AccessorField& arg) noexcept{ + fieldName.swap(arg.fieldName); + std::swap(isStatic, arg.isStatic); + std::swap(generateGetter, arg.generateGetter); + std::swap(generateSetter, arg.generateSetter); + } +}; + +MAKE_REFLECT_STRUCT(AccessorField, fieldName,isStatic,generateGetter,generateSetter) + +DEFINE_REQUEST_RESPONSE_TYPE(java_resolveUnimplementedAccessors, lsCodeActionParams, std::vector<AccessorField>, "java/resolveUnimplementedAccessors"); diff --git a/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/extention/jdtls/searchSymbols.h b/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/extention/jdtls/searchSymbols.h new file mode 100644 index 00000000000..ac8a2419f62 --- /dev/null +++ b/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/extention/jdtls/searchSymbols.h @@ -0,0 +1,27 @@ +#pragma once + +#include "LibLsp/JsonRpc/RequestInMessage.h" +#include "LibLsp/JsonRpc/lsResponseMessage.h" + + +#include <string> +#include <vector> +#include "WorkspaceSymbolParams.h" +#include "LibLsp/lsp/method_type.h" +#include "LibLsp/lsp/symbol.h" + + +struct SearchSymbolParams :public WorkspaceSymbolParams +{ + boost::optional<std::string> projectName; + boost::optional< bool >sourceOnly; + boost::optional< int> maxResults; + MAKE_SWAP_METHOD(SearchSymbolParams, query, projectName, sourceOnly, maxResults); +}; +MAKE_REFLECT_STRUCT(SearchSymbolParams, query, projectName, sourceOnly, maxResults); + + +DEFINE_REQUEST_RESPONSE_TYPE(java_searchSymbols, SearchSymbolParams, std::vector<lsSymbolInformation>, "java/searchSymbols"); + + + diff --git a/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/extention/sct/SCTConfig.h b/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/extention/sct/SCTConfig.h new file mode 100644 index 00000000000..7b41118c0ab --- /dev/null +++ b/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/extention/sct/SCTConfig.h @@ -0,0 +1,37 @@ +#pragma once +#include <string> +#include <vector> +#include <LibLsp/JsonRpc/serializer.h> +using namespace std; + + +struct TCP_option +{ + std::string host = "127.0.0.1"; + int port = 8889; + +}; +MAKE_REFLECT_STRUCT(TCP_option,host,port) + + +struct SCTConfig +{ + static SCTConfig* newInstance(const string& file_path,string& error); + std::string version; + std::string file_name; + + boost::optional<bool> start_by_jcide; + + boost::optional<TCP_option> tcp; + boost::optional<vector<string>> args; + + // internal using + bool broken = false; + std::string error; +}; + + +MAKE_REFLECT_STRUCT(SCTConfig, version,file_name, tcp, args, start_by_jcide); + + + diff --git a/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/extention/sct/protocol.h b/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/extention/sct/protocol.h new file mode 100644 index 00000000000..1f227a61105 --- /dev/null +++ b/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/extention/sct/protocol.h @@ -0,0 +1,222 @@ +#pragma once +#include "LibLsp/JsonRpc/RequestInMessage.h" +#include "LibLsp/lsp/lsDocumentUri.h" +#include "LibLsp/lsp/lsAny.h" +#include "LibLsp/JsonRpc/NotificationInMessage.h" + +struct DownLoadCapFileParams +{ + lsDocumentUri uri; + MAKE_SWAP_METHOD(DownLoadCapFileParams, uri); +}; +MAKE_REFLECT_STRUCT(DownLoadCapFileParams, uri); + +struct NormalActionResult +{ + bool state = false; + boost::optional<std::vector<uint8_t>> data; + boost::optional<std::string> info; + MAKE_SWAP_METHOD(NormalActionResult, state, data, info); +}; +MAKE_REFLECT_STRUCT(NormalActionResult, data, state, info) + +DEFINE_REQUEST_RESPONSE_TYPE(sct_DownLoadCapFile, DownLoadCapFileParams, NormalActionResult, "sct/download_cap"); + + + + +enum class SctProtocol :uint8_t +{ + T01 = 0, T0 = 1, T1 = 2, +}; +MAKE_REFLECT_TYPE_PROXY(SctProtocol); + +struct ConnectParams +{ + + SctProtocol protocol= SctProtocol::T01; + boost::optional<std::string> reader; + boost::optional<lsp::Any> data; + MAKE_SWAP_METHOD(ConnectParams, reader, protocol,data); +}; +MAKE_REFLECT_STRUCT(ConnectParams, reader, protocol, data); +DEFINE_REQUEST_RESPONSE_TYPE(sct_Connect, ConnectParams, NormalActionResult, "sct/connect"); + + + +struct SetProtocolParams +{ + + SctProtocol protocol = SctProtocol::T01; + +}; +MAKE_REFLECT_STRUCT(SetProtocolParams, protocol); + +DEFINE_REQUEST_RESPONSE_TYPE(sct_SetProtocol, SetProtocolParams, NormalActionResult, "sct/set_protocol"); + +struct GPAuthParams +{ + boost::optional < std::string> scp; + boost::optional < std::string > key; + boost::optional < lsp::Any > option; + MAKE_SWAP_METHOD(GPAuthParams, key, scp, option); +}; +MAKE_REFLECT_STRUCT(GPAuthParams, key, scp, option); +DEFINE_REQUEST_RESPONSE_TYPE(sct_gp_auth, GPAuthParams, NormalActionResult ,"sct/gp_auth"); + + + +struct InstallAppletParams +{ + std::vector<uint8_t> package_aid; + std::vector<uint8_t> applet_aid; + boost::optional < std::vector<uint8_t>> instance_aid; + boost::optional<std::vector<uint8_t>> authority; + boost::optional<std::vector<uint8_t>> parameters; + MAKE_SWAP_METHOD(InstallAppletParams, package_aid, applet_aid, instance_aid, authority, parameters); +}; +MAKE_REFLECT_STRUCT(InstallAppletParams, package_aid, applet_aid, instance_aid, authority, parameters); +DEFINE_REQUEST_RESPONSE_TYPE(sct_InstalllApplet, InstallAppletParams, NormalActionResult, "sct/install_applet"); + + +struct TransmitParams +{ + std::vector<unsigned char> command; + MAKE_SWAP_METHOD(TransmitParams, command); +}; +MAKE_REFLECT_STRUCT(TransmitParams, command); + +DEFINE_REQUEST_RESPONSE_TYPE(sct_Transmit, TransmitParams, NormalActionResult,"sct/transmit"); + +DEFINE_NOTIFICATION_TYPE(sct_Disconnect,JsonNull, "sct/disconnect") + + +struct SetWindowPosParams{ + int X = 0; + int Y = 0; + int cx = 100; + int cy = 100; + + MAKE_SWAP_METHOD(SetWindowPosParams, X, Y, cx, cy); +}; +MAKE_REFLECT_STRUCT(SetWindowPosParams, X, Y, cx, cy); +DEFINE_NOTIFICATION_TYPE(sct_SetWindowsPos, SetWindowPosParams, "sct/set_windows_pos") + +struct SetWindowVisibleParams +{ + static const int HIDE = 0; + static const int MINSIZE = 1; + static const int MAXSIZE = 2; + static const int NORMAL = 3; + int state = NORMAL; + MAKE_SWAP_METHOD(SetWindowVisibleParams, state); +}; +MAKE_REFLECT_STRUCT(SetWindowVisibleParams, state); +DEFINE_NOTIFICATION_TYPE(sct_SetWindowsVisible, SetWindowVisibleParams, "sct/set_windows_visible") + + + +enum CardInfoType:uint32_t +{ + ATR_TYPE = 0, + ATS_TYPE = 1, +}; +MAKE_REFLECT_TYPE_PROXY(CardInfoType); + + +struct GetCardInfoParams +{ + CardInfoType type_; +}; +MAKE_REFLECT_STRUCT(GetCardInfoParams, type_); + +DEFINE_REQUEST_RESPONSE_TYPE(sct_GetCardInfo, GetCardInfoParams, NormalActionResult, "sct/get_card_info"); + + +struct JdwpInfo +{ + std::string host="127.0.0.1"; + uint32_t jdwp_port = 9075; + +}; + +MAKE_REFLECT_STRUCT(JdwpInfo, host, jdwp_port); + +struct LaunchResult +{ + bool state; + boost::optional<JdwpInfo> info; + boost::optional<std::string> error; + MAKE_SWAP_METHOD(LaunchResult, state, info, error); +}; +MAKE_REFLECT_STRUCT(LaunchResult, state, info, error); + + +struct JcvmOutputParams +{ + std::string data; + MAKE_SWAP_METHOD(JcvmOutputParams, data); +}; +MAKE_REFLECT_STRUCT(JcvmOutputParams, data); + +DEFINE_NOTIFICATION_TYPE(sct_NotifyJcvmOutput, JcvmOutputParams,"sct/notify_jcvm_output"); + + +struct LaunchParam +{ + enum + { + LAUNCH_FOR_DEBUG = 0, + LAUNCH_FOR_RUN = 1 + }; + boost::optional<uint32_t> launch_for_what; + +}; +MAKE_REFLECT_STRUCT(LaunchParam, launch_for_what); + + +DEFINE_REQUEST_RESPONSE_TYPE(sct_Launch, LaunchParam, LaunchResult , "sct/launch"); + + +DEFINE_REQUEST_RESPONSE_TYPE(sct_CheckBeforeLaunch, JsonNull, NormalActionResult, "sct/check_before_launch"); + + + +DEFINE_NOTIFICATION_TYPE(sct_NotifyDisconnect, JsonNull,"sct/notify_disconnect"); + + +DEFINE_NOTIFICATION_TYPE(sct_TerminateLaunch, JsonNull, "sct/terminate_launch"); + + + + +struct sctInitializeParams { + // The process Id of the parent process that started + // the server. Is null if the process has not been started by another process. + // If the parent process is not alive then the server should exit (see exit + // notification) its process. + boost::optional<int> processId; + + // User provided initialization options. + boost::optional<lsp::Any> initializationOptions; + boost::optional<int> version; + +}; +MAKE_REFLECT_STRUCT(sctInitializeParams,processId,initializationOptions, version); + +struct sctServerCapabilities { + bool gp_auth = false; + bool gp_key = false; + boost::optional<int> version; + MAKE_SWAP_METHOD(sctServerCapabilities, gp_auth, gp_key, version); +}; +MAKE_REFLECT_STRUCT(sctServerCapabilities, gp_auth, gp_key, version); + + +struct stcInitializeResult +{ + sctServerCapabilities capabilities; +}; +MAKE_REFLECT_STRUCT(stcInitializeResult, capabilities); + +DEFINE_REQUEST_RESPONSE_TYPE(sct_initialize, sctInitializeParams, stcInitializeResult, "sct/initialize"); diff --git a/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/extention/sct/sct.cpp b/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/extention/sct/sct.cpp new file mode 100644 index 00000000000..25c21ecddc4 --- /dev/null +++ b/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/extention/sct/sct.cpp @@ -0,0 +1,743 @@ + +#include <deque> +#include "sct.h" +#include "SCTConfig.h" +#include <rapidjson/document.h> +#include <rapidjson/istreamwrapper.h> +#include <fstream> +#include <boost/filesystem.hpp> +#include "LibLsp/lsp/general/exit.h" +#include "LibLsp/lsp/general/initialized.h" +#include "LibLsp/lsp/windows/MessageNotify.h" +#include "LibLsp/lsp/language/language.h" +#include "LibLsp/JsonRpc/Condition.h" +#include "LibLsp/lsp/workspace/execute_command.h" +#include "LibLsp/JsonRpc/json.h" + +namespace lsp { + class Log; +} + +using namespace std; +using lsp::Log; + + +// +//MethodType sct_DownLoadCapFile::request::kMethodInfo = "sct/download_cap"; +// +//MethodType sct_Transmit::request::kMethodInfo = "sct/transmit"; +// +//MethodType sct_Connect::request::kMethodInfo = "sct/connect"; +// +//MethodType sct_Disconnect::request::kMethodInfo = "sct/disconnect"; +// +//MethodType sct_InstalllApplet::request::kMethodInfo = "sct/install_applet"; +// +//MethodType sct_gp_auth::request::kMethodInfo = "sct/gp_auth"; +// +//MethodType sct_SetWindowsPos::request::kMethodInfo = "sct/set_windows_pos"; +// +//MethodType sct_SetWindowsVisible::request::kMethodInfo = "sct/set_windows_visible"; +// +// +//MethodType sct_NotifyJcvmOutput::request::kMethodInfo = "sct/notify_jcvm_output"; +// +//MethodType sct_Launch::request::kMethodInfo = "sct/launch"; +// +//MethodType sct_SetProtocol::request::kMethodInfo = "sct/set_protocol"; +// +//MethodType sct_CheckBeforeLaunch::request::kMethodInfo = "sct/check_before_launch"; +// +//MethodType sct_GetCardInfo::request::kMethodInfo = "sct/get_card_info"; +// +//MethodType sct_NotifyDisconnect::request::kMethodInfo = "sct/notify_disconnect"; +//MethodType sct_TerminateLaunch::request::kMethodInfo = "sct/terminate_launch"; +//MethodType sct_initialize::request::kMethodInfo = "sct/initialize"; + + + SCTConfig* SCTConfig::newInstance(const string& file_path, string& error) +{ + if(!boost::filesystem::exists(file_path)) + { + error = "file no exists."; + return nullptr; + } + using namespace rapidjson; + using namespace std; + std::unique_ptr<SCTConfig> sct = std::make_unique<SCTConfig>(); + try + { + std::wifstream ifs(file_path); + WIStreamWrapper isw(ifs); + + Document d; + d.ParseStream(isw); + if(!d.HasParseError()) + { + JsonReader reader{ &d }; + Reflect(reader, *sct.get()); + } + } + catch (std::exception& e) + { + string temp = "Reflect failed. exception info:"; + + temp += e.what(); + error = temp; + sct.get()->broken = true; + sct.get()->error = temp; + } + return sct.release(); +} + + +SmartCardTool::SmartCardTool(): m_jdwpPort(0), m_curProtocol(SctProtocol::T01), log(nullptr) +{ + m_ipAddr = "127.0.0.1"; +} + +void AddNotifyJsonRpcMethod(sct::ProtocolJsonHandler& handler) +{ + handler.method2notification[Notify_Exit::notify::kMethodInfo] = [](Reader& visitor) + { + return Notify_Exit::notify::ReflectReader(visitor); + }; + handler.method2notification[Notify_InitializedNotification::notify::kMethodInfo] = [](Reader& visitor) + { + return Notify_InitializedNotification::notify::ReflectReader(visitor); + }; + + + handler.method2notification[Notify_LogMessage::notify::kMethodInfo] = [](Reader& visitor) + { + return Notify_LogMessage::notify::ReflectReader(visitor); + }; + handler.method2notification[Notify_ShowMessage::notify::kMethodInfo] = [](Reader& visitor) + { + return Notify_ShowMessage::notify::ReflectReader(visitor); + }; + + handler.method2notification[Notify_sendNotification::notify::kMethodInfo] = [](Reader& visitor) + { + return Notify_sendNotification::notify::ReflectReader(visitor); + }; + + handler.method2notification[lang_actionableNotification::notify::kMethodInfo] = [](Reader& visitor) + { + return lang_actionableNotification::notify::ReflectReader(visitor); + }; + handler.method2notification[lang_progressReport::notify::kMethodInfo] = [](Reader& visitor) + { + return lang_progressReport::notify::ReflectReader(visitor); + }; + + + handler.method2notification[sct_NotifyJcvmOutput::notify::kMethodInfo] = [](Reader& visitor) + { + return sct_NotifyJcvmOutput::notify::ReflectReader(visitor); + }; + handler.method2notification[sct_NotifyDisconnect::notify::kMethodInfo] = [](Reader& visitor) + { + return sct_NotifyDisconnect::notify::ReflectReader(visitor); + }; + +} + +sct::ProtocolJsonHandler::ProtocolJsonHandler() +{ + AddNotifyJsonRpcMethod(*this); + + method2response[sct_DownLoadCapFile::request::kMethodInfo ] = [](Reader& visitor) + { + if (visitor.HasMember("error")) + return Rsp_Error::ReflectReader(visitor); + + return sct_DownLoadCapFile::response::ReflectReader(visitor); + }; + method2response[sct_Connect::request::kMethodInfo] = [](Reader& visitor) + { + if (visitor.HasMember("error")) + return Rsp_Error::ReflectReader(visitor); + + return sct_Connect::response::ReflectReader(visitor); + }; + method2response[sct_SetProtocol::request::kMethodInfo] = [](Reader& visitor) + { + if (visitor.HasMember("error")) + return Rsp_Error::ReflectReader(visitor); + + return sct_SetProtocol::response::ReflectReader(visitor); + }; + method2response[sct_gp_auth::request::kMethodInfo] = [](Reader& visitor) + { + if (visitor.HasMember("error")) + return Rsp_Error::ReflectReader(visitor); + + return sct_gp_auth::response::ReflectReader(visitor); + }; + method2response[sct_InstalllApplet::request::kMethodInfo] = [](Reader& visitor) + { + if (visitor.HasMember("error")) + return Rsp_Error::ReflectReader(visitor); + + return sct_InstalllApplet::response::ReflectReader(visitor); + }; + method2response[sct_Transmit::request::kMethodInfo] = [](Reader& visitor) + { + if (visitor.HasMember("error")) + return Rsp_Error::ReflectReader(visitor); + + return sct_Transmit::response::ReflectReader(visitor); + }; + + method2response[sct_GetCardInfo::request::kMethodInfo] = [](Reader& visitor) + { + if (visitor.HasMember("error")) + return Rsp_Error::ReflectReader(visitor); + + return sct_GetCardInfo::response::ReflectReader(visitor); + }; + + method2response[sct_Launch::request::kMethodInfo] = [](Reader& visitor) + { + if (visitor.HasMember("error")) + return Rsp_Error::ReflectReader(visitor); + + return sct_Launch::response::ReflectReader(visitor); + }; + method2response[sct_CheckBeforeLaunch::request::kMethodInfo] = [](Reader& visitor) + { + if (visitor.HasMember("error")) + return Rsp_Error::ReflectReader(visitor); + + return sct_CheckBeforeLaunch::response::ReflectReader(visitor); + }; + + + method2response[sct_initialize::request::kMethodInfo] = [](Reader& visitor) + { + if (visitor.HasMember("error")) + return Rsp_Error::ReflectReader(visitor); + + return sct_initialize::response::ReflectReader(visitor); + }; + +} +bool SmartCardTool::check_sct_alive() +{ + if (sct) + { + return true; + } + if(log) + { + wstring strPrompt = L"sct is not alvie."; + log->log(Log::Level::SEVERE, strPrompt); + } + return false; +} + +bool SmartCardTool::initialize(int processId, int version) +{ + + if(!check_sct_alive()) + { + return false; + } + sct_initialize::request request; + request.params.processId = processId; + request.params.version = version; + + auto msg = sct->waitResponse(request, 100000); + + if (!msg) + { + return false; + } + + if (msg->is_error) + { + auto error = &msg->error; + log->error( error->error.ToString()); + return false; + } + auto result = &msg->response; + _lsServerCapabilities.swap(result->result.capabilities); + return true; +} + + + +SmartCardTool::~SmartCardTool() +{ + + +} + +bool SmartCardTool::GetCardInfo(CardInfoType type_, std::vector<unsigned char>& out) +{ + if (!check_sct_alive()) + { + return false; + } + sct_GetCardInfo::request request; + request.params.type_ = type_; + + auto data = sct->waitResponse(request, 40000); + + if (!data) + { + if (log) + { + wstring strPrompt = L"GetCardInfo request timeout."; + log->log(Log::Level::SEVERE, strPrompt); + } + return false; + } + + if (data->is_error) + { + if (log) + { + string strPrompt = "GetCardInfo request error." + data->error.ToJson(); + log->log(Log::Level::SEVERE, strPrompt); + } + return false; + } + auto rsp = &data->response; + if (rsp->result.state) + { + out.swap(rsp->result.data.value()); + return true; + } + + if (log) + { + string strPrompt = "GetCardInfo failed. Reason:"; + strPrompt += rsp->result.info.value(); + log->log(Log::Level::SEVERE, strPrompt); + } + return false; +} + + + +bool SmartCardTool::Launch(bool for_debug) +{ + if (!check_sct_alive()) + { + return false; + } + sct_Launch::request request; + if(for_debug) + { + request.params.launch_for_what = LaunchParam::LAUNCH_FOR_DEBUG; + } + else + { + request.params.launch_for_what = LaunchParam::LAUNCH_FOR_RUN; + } + auto data = sct->waitResponse(request, 100000); + + if (!data) + { + if (log) + { + wstring strPrompt = L"Launch request timeout."; + log->log(Log::Level::SEVERE, strPrompt); + } + return false; + } + + if (data->is_error) + { + if (log) + { + string strPrompt = "Launch request error." + data->error.ToJson(); + + log->log(Log::Level::SEVERE, strPrompt); + } + return false; + } + auto rsp = &data->response; + if (rsp->result.state) + { + if (log) + { + log->log(Log::Level::INFO, L"Launch successfully"); + } + if(rsp->result.info) + { + m_ipAddr.swap(rsp->result.info.value().host); + m_jdwpPort = rsp->result.info.value().jdwp_port; + + } + } + else + { + if (log) + { + string strPrompt = "Launch failed. Reason:"; + strPrompt += rsp->result.error.value(); + log->log(Log::Level::SEVERE, strPrompt); + } + return false; + } + return true; +} + +void SmartCardTool::TerminateLaunch() +{ + if (!check_sct_alive()) + { + return ; + } + sct_TerminateLaunch::notify notify; + sct->send(notify); + connect_state = false; + return ; +} + +void SmartCardTool::show_message(lsMessageType type_, + const std::string& msg) +{ + if (!check_sct_alive()) + { + return ; + } + Notify_ShowMessage::notify notify; + notify.params.type = type_; + notify.params.message = msg; + sct->send(notify); +} + +bool SmartCardTool::CheckBeforeLaunch() +{ + if (!check_sct_alive()) + { + return false; + } + sct_CheckBeforeLaunch::request request; + auto data = sct->waitResponse(request, 50000); + + if (!data) + { + wstring strPrompt = L"CheckBeforeLaunch request timeout."; + if(log) + { + log->log(Log::Level::SEVERE, strPrompt); + } + + return false; + } + + if (data->is_error) + { + string strPrompt = "CheckBeforeLaunch request error." + data->error.ToJson(); + log->log(Log::Level::SEVERE, strPrompt); + return false; + } + auto rsp = &data->response; + if (rsp->result.state) + { + return true; + } + + + string strPrompt = "Check Before Launch JCVM failed. Reason:"; + strPrompt += rsp->result.info.value(); + log->log(Log::Level::SEVERE, strPrompt); + return false; + +} + + +bool SmartCardTool::Connect(SctProtocol protocol) +{ + if (!check_sct_alive()) + { + return false; + } + sct_Connect::request request; + + request.params.protocol = protocol; + + auto data = sct->waitResponse(request, 40000); + + if (!data) + { + wstring strPrompt = L"Connect request timeout."; + log->log(Log::Level::SEVERE, strPrompt); + return false; + } + + if (data->is_error) + { + string strPrompt = "Connect request error." + data->error.ToJson(); + log->log(Log::Level::SEVERE, strPrompt); + return false; + } + auto rsp =&data->response; + if (rsp->result.state) + { + connect_state = true; + return true; + } + else + { + string strPrompt = "Connect failed. Reason:"; + strPrompt += rsp->result.info.value(); + log->log(Log::Level::SEVERE, strPrompt); + return false; + } + +} + + + + +void SmartCardTool::DisConnect() +{ + if (!check_sct_alive()) + { + return ; + } + sct_Disconnect::notify notify; + sct->send(notify); + connect_state = false; + return ; +} + +bool SmartCardTool::DownLoadCapFile(const string& strCapFileName) +{ + if (!check_sct_alive()) + { + return false; + } + sct_DownLoadCapFile::request request; + request.params.uri.raw_uri_ = make_file_scheme_uri(strCapFileName); + + auto data = sct->waitResponse(request, 40000); + + if(!data) + { + wstring strPrompt = L"DownLoadCapFile request timeout."; + log->log(Log::Level::SEVERE,strPrompt); + return false; + } + + if(data->is_error) + { + string strPrompt = "DownLoadCapFile request error." + data->error.ToJson(); + log->log(Log::Level::SEVERE, strPrompt); + return false; + } + auto rsp = &data->response; + if(rsp->result.state) + { + string strPrompt = "DownLoadCapFile successfully"; + if(rsp->result.info) + { + strPrompt = rsp->result.info.value(); + } + log->log(Log::Level::INFO, strPrompt); + return true; + } + else + { + string strPrompt = "DownLoadCapFile failed. Reason:"; + strPrompt += rsp->result.info.value(); + log->log(Log::Level::SEVERE, strPrompt); + return false; + } + +} + +void SmartCardTool::SetWindowsVisible(SetWindowVisibleParams& params) +{ + if (!check_sct_alive()) + { + return ; + } + sct_SetWindowsVisible::notify notify; + notify.params.swap(params); + sct->send(notify); + +} + +void SmartCardTool::SetWindowPos(SetWindowPosParams& params) +{ + sct_SetWindowsPos::notify notify; + notify.params.swap(params); + sct->send(notify); +} + +bool SmartCardTool::SetProtocol(SctProtocol protocol) +{ + if (!check_sct_alive()) + { + return false; + } + sct_SetProtocol::request request; + + request.params.protocol = protocol; + + auto data = sct->waitResponse(request, 40000); + + if (!data) + { + wstring strPrompt = L"SetProtocol request timeout."; + log->log(Log::Level::SEVERE, strPrompt); + return false; + } + + if (data->is_error) + { + string strPrompt = "SetProtocol request error." + data->error.ToJson(); + log->log(Log::Level::SEVERE, strPrompt); + return false; + } + auto rsp = &data->response; + if (rsp->result.state) + { + m_curProtocol = protocol; + return true; + } + else + { + string strPrompt = "SetProtocol failed. Reason:"; + strPrompt += rsp->result.info.value(); + log->log(Log::Level::SEVERE, strPrompt); + return false; + } + +} + +bool SmartCardTool::GpAuth() +{ + + if (!check_sct_alive()) + { + return false; + } + sct_gp_auth::request request; + + auto data = sct->waitResponse(request, 100000); + + if (!data) + { + wstring strPrompt = L"gp_auth request timeout."; + log->log(Log::Level::SEVERE, strPrompt); + return false; + } + + if (data->is_error) + { + string strPrompt = "gp_auth request error." + data->error.ToJson(); + log->log(Log::Level::SEVERE, strPrompt); + return false; + } + auto rsp = &data->response; + if (rsp->result.state) + { + string strPrompt = "gp_auth request successfully."; + if (rsp->result.info) + strPrompt = rsp->result.info.value(); + + log->log(Log::Level::INFO, strPrompt); + return true; + } + else + { + string strPrompt = "gp_auth failed. Reason:"; + strPrompt += rsp->result.info.value(); + log->log(Log::Level::SEVERE, strPrompt); + return false; + } + +} + +bool SmartCardTool::InstallApplet(InstallAppletParams& params) +{ + if (!check_sct_alive()) + { + return false; + } + sct_InstalllApplet::request request; + request.params.swap(params); + auto data = sct->waitResponse(request); + + if (!data) + { + wstring strPrompt = L"Install Applet request timeout."; + log->log(Log::Level::SEVERE, strPrompt); + return false; + } + + if (data->is_error) + { + string strPrompt = "Install Applet request error." + data->error.ToJson(); + log->log(Log::Level::SEVERE, strPrompt); + return false; + } + auto rsp = &data->response; + if (rsp->result.state) + { + string strPrompt = "Install Applet successfully."; + if (rsp->result.info) + strPrompt = rsp->result.info.value(); + log->log(Log::Level::INFO, strPrompt); + return true; + } + else + { + string strPrompt = "Install Applet failed. Reason:"; + strPrompt += rsp->result.info.value(); + log->log(Log::Level::SEVERE, strPrompt); + return false; + } +} + + +bool SmartCardTool::Transmit(const std::vector<unsigned char>& cmdApdu, std::vector<unsigned char>& rspApdu) +{ + + if (!check_sct_alive()) + { + return false; + } + sct_Transmit::request request; + request.params.command = cmdApdu; + + auto data = sct->waitResponse(request); + + if (!data) + { + wstring strPrompt = L"Transmit request timeout."; + log->log(Log::Level::SEVERE, strPrompt); + return false; + } + + if (data->is_error) + { + string strPrompt = "Transmit request error." + data->error.ToJson(); + log->log(Log::Level::SEVERE, strPrompt); + return false; + } + auto rsp = &data->response; + if (rsp->result.state) + { + rspApdu.swap(rsp->result.data.value()); + //log->log(Log::Level::INFO, L"Transmit successfully"); + return true; + } + else + { + string strPrompt = "Transmit failed. Reason:"; + strPrompt += rsp->result.info.value(); + log->log(Log::Level::SEVERE, strPrompt); + return false; + } + + +} diff --git a/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/extention/sct/sct.h b/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/extention/sct/sct.h new file mode 100644 index 00000000000..59ffe02fd75 --- /dev/null +++ b/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/extention/sct/sct.h @@ -0,0 +1,103 @@ +#pragma once + +#include <LibLsp/JsonRpc/RemoteEndPoint.h> +#include <LibLsp/JsonRpc/Endpoint.h> +#include <LibLsp/lsp/ProtocolJsonHandler.h> +#include "protocol.h" +enum class lsMessageType; +enum CardInfoType : unsigned; +enum class SctProtocol : unsigned char; +struct InstallAppletParams; + + +using namespace std; + +class ModeState; +namespace sct +{ + class ProtocolJsonHandler : public MessageJsonHandler + { + public: + ProtocolJsonHandler(); + }; + +} +class SmartCardTool +{ + //IP �����ֽ��� + std::string m_ipAddr; + volatile uint16_t m_jdwpPort; + + + SctProtocol m_curProtocol; +public: + enum JCIDE_VERSION + { + V5_KIND = 5 + }; + SmartCardTool(); + ~SmartCardTool(); + + + bool GetCardInfo(CardInfoType type_,std::vector<unsigned char>&); + bool Launch(bool for_debug = false); + + void TerminateLaunch(); + void show_message(lsMessageType type_,const std::string& msg); + bool CheckBeforeLaunch(); + + string GetIpAddr(){return m_ipAddr;} + + uint16_t GetJdwpPort(){return m_jdwpPort;} + + + + void SetWindowsVisible(SetWindowVisibleParams&); + void SetWindowPos(SetWindowPosParams&); + + SctProtocol GetProtocol(){return m_curProtocol;} + + + bool SetProtocol(SctProtocol protocol = SctProtocol::T01); + + bool GpAuth(); + + + bool InstallApplet(InstallAppletParams&);; + + bool DownLoadCapFile(const string& strCapFileName); + + + + bool IsConnected() const { + + return connect_state; + } + + string GetErrorString() { return {}; }; + + bool Connect(SctProtocol protocol = SctProtocol::T01); + + void DisConnect(); + + + + + bool Transmit(const std::vector<unsigned char>& cmdApdu, std::vector<unsigned char>& rspApdu) ; + + + lsp::Log* log; + volatile bool connect_state = false; + + std::shared_ptr<RemoteEndPoint> sct; + + + bool initialize(int processId,int version); + const sctServerCapabilities& getServerCapabilities()const + { + return _lsServerCapabilities; + } +private: + sctServerCapabilities _lsServerCapabilities; + bool check_sct_alive(); +}; diff --git a/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/extention/sonarlint/protocol.h b/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/extention/sonarlint/protocol.h new file mode 100644 index 00000000000..d81c3eaa636 --- /dev/null +++ b/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/extention/sonarlint/protocol.h @@ -0,0 +1,176 @@ +#pragma once +#include <string> +#include <boost/optional.hpp> +#include "LibLsp/JsonRpc/RequestInMessage.h" +#include "LibLsp/lsp/lsDocumentUri.h" +#include "LibLsp/lsp/lsAny.h" +#include "LibLsp/JsonRpc/NotificationInMessage.h" +#include "LibLsp/lsp/general/InitializeParams.h" + +struct LintRule +{ + std::string key; + std::string name; + + + std::string Display() const + { + return name + " (" + key + ")"; + } + bool activeByDefault = true; + boost::optional<std::string> severity; + boost::optional<std::string> type; + int icon_index = -1; + MAKE_SWAP_METHOD(LintRule, key, name, activeByDefault, severity, type); + +}; +MAKE_REFLECT_STRUCT(LintRule, key, name, activeByDefault, severity, type); + + +struct RuleParameter { + std::string name; + boost::optional<std::string> description; + boost::optional<std::string> defaultValue; + +}; +MAKE_REFLECT_STRUCT(RuleParameter, name, description, defaultValue); + +struct ShowRuleDescriptionParams { + + boost::optional<std::string> key; + + boost::optional<std::string> name; + + boost::optional<std::string> htmlDescription; + + boost::optional<std::string> type; + + boost::optional<std::string> severity; + + boost::optional< std::vector<RuleParameter> > parameters; + MAKE_SWAP_METHOD(ShowRuleDescriptionParams, key, name, htmlDescription, type, severity, parameters) + + +}; +MAKE_REFLECT_STRUCT(ShowRuleDescriptionParams, key, name, htmlDescription, type, severity, parameters); + + +struct GetJavaConfigResponse { + std::string projectRoot; + std::string sourceLevel; + std::vector<std::string> classpath; + bool isTest; + std::string vmLocation; + MAKE_SWAP_METHOD(GetJavaConfigResponse, projectRoot, sourceLevel, classpath, isTest, vmLocation); +}; +MAKE_REFLECT_STRUCT(GetJavaConfigResponse, projectRoot, sourceLevel, classpath, isTest, vmLocation); + +struct SetTraceNotificationParams { + lsInitializeParams::lsTrace value; +}; +MAKE_REFLECT_STRUCT(SetTraceNotificationParams, value); + + +struct ServerConnectionSettings { + + std::string SONARCLOUD_URL = "https://sonarcloud.io"; + std::vector<std::string>SONARCLOUD_ALIAS = { "https://sonarqube.com", + "https://www.sonarqube.com", + "https://www.sonarcloud.io", + "https://sonarcloud.io" }; + + std::string connectionId; + std::string serverUrl; + std::string token; + boost::optional<std::string> organizationKey; + MAKE_SWAP_METHOD(ServerConnectionSettings, connectionId, serverUrl, token, organizationKey) + +}; +MAKE_REFLECT_STRUCT(ServerConnectionSettings, connectionId, serverUrl, token, organizationKey) + +struct RuleSetting +{ + bool IsOn(); + std::string level = "on"; + RuleSetting(bool activate); + RuleSetting() = default; + void toggle(); + void on() + { + level = "on"; + } + void off() + { + level = "off"; + } + void turn(bool activate) + { + if (activate) + { + on(); + } + else + { + off(); + } + } + boost::optional< std::map<std::string, std::string > > parameters; +}; +MAKE_REFLECT_STRUCT(RuleSetting, level, parameters) + +struct ConsoleParams +{ + boost::optional < bool >showAnalyzerLogs; + boost::optional < bool >showVerboseLogs; + MAKE_SWAP_METHOD(ConsoleParams, showAnalyzerLogs, showVerboseLogs) +}; +MAKE_REFLECT_STRUCT(ConsoleParams, showAnalyzerLogs, showVerboseLogs) + +struct SonarLintWorkspaceSettings +{ + boost::optional < bool > disableTelemetry; + boost::optional < std::map<std::string, ServerConnectionSettings> >connectedMode; + boost::optional<std::map<std::string, RuleSetting>> rules; + boost::optional<ConsoleParams> output; + + boost::optional<std::string > pathToNodeExecutable; + + boost::optional< std::map<std::string, std::string > > getConfigurationParameters(const std::string& ruleKey); + + +}; + +MAKE_REFLECT_STRUCT(SonarLintWorkspaceSettings, disableTelemetry, connectedMode, + rules, output, pathToNodeExecutable) + + + + DEFINE_REQUEST_RESPONSE_TYPE(slls_listAllRules, JsonNull, lsp::Any, "sonarlint/listAllRules"); + + + +DEFINE_NOTIFICATION_TYPE(Notify_didClasspathUpdate, lsDocumentUri, "sonarlint/didClasspathUpdate") + + +DEFINE_NOTIFICATION_TYPE(Notify_didJavaServerModeChange, std::string, "sonarlint/didJavaServerModeChange") + + + +DEFINE_REQUEST_RESPONSE_TYPE(slls_showSonarLintOutput, JsonNull, JsonNull, "sonarlint/showSonarLintOutput"); + + + +DEFINE_REQUEST_RESPONSE_TYPE(slls_openJavaHomeSettings, JsonNull, JsonNull, "sonarlint/openJavaHomeSettings"); + + + + +DEFINE_REQUEST_RESPONSE_TYPE(slls_openPathToNodeSettings, JsonNull, JsonNull, "sonarlint/openPathToNodeSettings"); + + +DEFINE_REQUEST_RESPONSE_TYPE(slls_showRuleDescription, ShowRuleDescriptionParams, JsonNull, "sonarlint/showRuleDescription"); + +DEFINE_REQUEST_RESPONSE_TYPE(slls_getJavaConfig, lsDocumentUri, GetJavaConfigResponse, "sonarlint/getJavaConfig"); + + +DEFINE_NOTIFICATION_TYPE(slls_setTraceNotification, SetTraceNotificationParams, "$/setTraceNotification")
\ No newline at end of file diff --git a/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/general/InitializeParams.h b/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/general/InitializeParams.h new file mode 100644 index 00000000000..f10080ea216 --- /dev/null +++ b/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/general/InitializeParams.h @@ -0,0 +1,128 @@ +#pragma once + +#include "LibLsp/lsp/lsDocumentUri.h" +#include "LibLsp/lsp/lsAny.h" +#include "lsClientCapabilities.h" +#include "LibLsp/lsp/workspace/workspaceFolders.h" + +struct ClientInfo { + std::string name; + boost::optional<std::string> version; + + MAKE_SWAP_METHOD(ClientInfo,name,version); +}; +MAKE_REFLECT_STRUCT(ClientInfo,name,version); + +struct lsInitializeParams { + // The process Id of the parent process that started + // the server. Is null if the process has not been started by another process. + // If the parent process is not alive then the server should exit (see exit + // notification) its process. + boost::optional<int> processId; + + /** + * Information about the client + * + * @since 3.15.0 + */ + boost::optional<ClientInfo> clientInfo; + /** + * The locale the client is currently showing the user interface + * in. This must not necessarily be the locale of the operating + * system. + * + * Uses IETF language tags as the value's syntax + * (See https://en.wikipedia.org/wiki/IETF_language_tag) + * + * @since 3.16.0 + */ + boost::optional<std::string> locale; + + // The rootPath of the workspace. Is null + // if no folder is open. + // + // @deprecated in favour of rootUri. + boost::optional<std::string> rootPath; + + // The rootUri of the workspace. Is null if no + // folder is open. If both `rootPath` and `rootUri` are set + // `rootUri` wins. + boost::optional<lsDocumentUri> rootUri; + + // User provided initialization options. + boost::optional<lsp::Any> initializationOptions; + + // The capabilities provided by the client (editor or tool) + lsClientCapabilities capabilities; + + + /** + * An boost::optional extension to the protocol. + * To tell the server what client (editor) is talking to it. + */ + // @Deprecated + boost::optional< std::string >clientName; + + + + enum class lsTrace { + // NOTE: serialized as a string, one of 'off' | 'messages' | 'verbose'; + Off, // off + Messages, // messages + Verbose // verbose + + }; + + // The initial trace setting. If omitted trace is disabled ('off'). + lsTrace trace = lsTrace::Off; + + + /** + * The workspace folders configured in the client when the server starts. + * This property is only available if the client supports workspace folders. + * It can be `null` if the client supports workspace folders but none are + * configured. + * + * Since 3.6.0 + */ + boost::optional< std::vector<WorkspaceFolder> > workspaceFolders; + + MAKE_SWAP_METHOD(lsInitializeParams, + processId, + rootPath, + rootUri, + initializationOptions, + capabilities, clientName, clientInfo, + trace, workspaceFolders, locale) +}; + +void Reflect(Reader& reader, lsInitializeParams::lsTrace& value); + + +void Reflect(Writer& writer, lsInitializeParams::lsTrace& value); + + +MAKE_REFLECT_STRUCT(lsInitializeParams, + processId, + rootPath, + rootUri, + initializationOptions, + capabilities, clientName, clientInfo, + trace, workspaceFolders, locale) + +struct lsInitializeError { + // Indicates whether the client should retry to send the + // initilize request after showing the message provided + // in the ResponseError. + bool retry; + void swap(lsInitializeError& arg) noexcept + { + auto tem = retry; + retry = arg.retry; + arg.retry = tem; + } +}; +MAKE_REFLECT_STRUCT(lsInitializeError, retry); + + + diff --git a/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/general/exit.h b/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/general/exit.h new file mode 100644 index 00000000000..02fe2160173 --- /dev/null +++ b/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/general/exit.h @@ -0,0 +1,7 @@ +#pragma once + +#include "LibLsp/JsonRpc/NotificationInMessage.h" +/** + * A notification to ask the server to exit its process. + */ +DEFINE_NOTIFICATION_TYPE(Notify_Exit, boost::optional<JsonNull>, "exit"); diff --git a/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/general/initialize.cpp b/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/general/initialize.cpp new file mode 100644 index 00000000000..4886be9b46f --- /dev/null +++ b/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/general/initialize.cpp @@ -0,0 +1,45 @@ +#include "initialize.h" +#include "LibLsp/JsonRpc/json.h" + +void Reflect(Reader& reader, lsInitializeParams::lsTrace& value) +{ + if (!reader.IsString()) + { + value = lsInitializeParams::lsTrace::Off; + return; + } + std::string v = reader.GetString(); + if (v == "off") + value = lsInitializeParams::lsTrace::Off; + else if (v == "messages") + value = lsInitializeParams::lsTrace::Messages; + else if (v == "verbose") + value = lsInitializeParams::lsTrace::Verbose; +} + +void Reflect(Writer& writer, lsInitializeParams::lsTrace& value) +{ + switch (value) + { + case lsInitializeParams::lsTrace::Off: + writer.String("off"); + break; + case lsInitializeParams::lsTrace::Messages: + writer.String("messages"); + break; + case lsInitializeParams::lsTrace::Verbose: + writer.String("verbose"); + break; + } +} + void Reflect(Reader& visitor, std::pair<boost::optional<lsTextDocumentSyncKind>, boost::optional<lsTextDocumentSyncOptions> >& value) +{ + if(((JsonReader&)visitor).m_->IsObject()) + { + Reflect(visitor, value.second); + } + else + { + Reflect(visitor, value.first); + } +}
\ No newline at end of file diff --git a/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/general/initialize.h b/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/general/initialize.h new file mode 100644 index 00000000000..eb8810939ac --- /dev/null +++ b/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/general/initialize.h @@ -0,0 +1,39 @@ +#pragma once +#include "LibLsp/JsonRpc/message.h" +#include "InitializeParams.h" +#include "lsServerCapabilities.h" +#include "LibLsp/JsonRpc/lsResponseMessage.h" +#include "LibLsp/JsonRpc/RequestInMessage.h" + + + + + + +/** + * The capabilities the language server provides. + */ + struct InitializeResult { + lsServerCapabilities capabilities; + MAKE_SWAP_METHOD(InitializeResult, capabilities); + }; + +MAKE_REFLECT_STRUCT(InitializeResult, capabilities); + + +/** + * The initialize request is sent as the first request from the client to + * the server. + * + * If the server receives request or notification before the initialize request it should act as follows: + * - for a request the respond should be errored with code: -32001. The message can be picked by the server. + * - notifications should be dropped, except for the exit notification. This will allow the exit a server without an initialize request. + * + * Until the server has responded to the initialize request with an InitializeResult + * the client must not sent any additional requests or notifications to the server. + * + * During the initialize request the server is allowed to sent the notifications window/showMessage, + * window/logMessage and telemetry/event as well as the window/showMessageRequest request to the client. + */ + +DEFINE_REQUEST_RESPONSE_TYPE(td_initialize, lsInitializeParams, InitializeResult, "initialize"); diff --git a/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/general/initialized.h b/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/general/initialized.h new file mode 100644 index 00000000000..bb6d12511cb --- /dev/null +++ b/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/general/initialized.h @@ -0,0 +1,13 @@ +#pragma once + + +#include "LibLsp/JsonRpc/NotificationInMessage.h" +/** + * The initialized notification is sent from the client to the server after + * the client received the result of the initialize request but before the + * client is sending any other request or notification to the server. The + * server can use the initialized notification for example to dynamically + * register capabilities. + */ +DEFINE_NOTIFICATION_TYPE(Notify_InitializedNotification, JsonNull, "initialized"); + diff --git a/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/general/lsClientCapabilities.h b/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/general/lsClientCapabilities.h new file mode 100644 index 00000000000..fcf6634e13f --- /dev/null +++ b/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/general/lsClientCapabilities.h @@ -0,0 +1,48 @@ +#pragma once + +#include "LibLsp/lsp/lsAny.h" +#include "lsWorkspaceClientCapabilites.h" +#include "lsTextDocumentClientCapabilities.h" + +/** + * Client capabilities specific to the used markdown parser. + * + * @since 3.16.0 + */ +struct MarkdownClientCapabilities { + /** + * The name of the parser. + */ + std::string parser; + + /** + * The version of the parser. + */ + boost::optional<std::string> version; + MAKE_SWAP_METHOD(MarkdownClientCapabilities, parser, version) + +}; +MAKE_REFLECT_STRUCT(MarkdownClientCapabilities, parser, version) + +struct lsClientCapabilities { + // Workspace specific client capabilities. + boost::optional<lsWorkspaceClientCapabilites> workspace; + + // Text document specific client capabilities. + boost::optional<lsTextDocumentClientCapabilities> textDocument; + + /** + * Window specific client capabilities. + */ + boost::optional<lsp::Any> window; + /** + * Experimental client capabilities. + */ + boost::optional<lsp::Any> experimental; + + MAKE_SWAP_METHOD(lsClientCapabilities, workspace, textDocument, window, experimental) +}; +MAKE_REFLECT_STRUCT(lsClientCapabilities, workspace, textDocument, window, experimental) + + + diff --git a/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/general/lsServerCapabilities.h b/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/general/lsServerCapabilities.h new file mode 100644 index 00000000000..66af2ced6b1 --- /dev/null +++ b/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/general/lsServerCapabilities.h @@ -0,0 +1,589 @@ +#pragma once +#include "LibLsp/lsp/method_type.h" + + +#include <stdexcept> +#include "LibLsp/JsonRpc/message.h" +#include "LibLsp/lsp/lsDocumentUri.h" +#include "LibLsp/lsp/lsAny.h" +#include "InitializeParams.h" +#include "LibLsp/lsp/textDocument/SemanticTokens.h" + + +extern void Reflect(Reader&, std::pair<boost::optional<lsTextDocumentSyncKind>, boost::optional<lsTextDocumentSyncOptions> >&); + +// + // Code Action options. + // +struct CodeActionOptions : WorkDoneProgressOptions { + // + // CodeActionKinds that this server may return. + // + // The list of kinds may be generic, such as `CodeActionKind.Refactor`, or the server + // may list out every specific kind they provide. + // + typedef std::string CodeActionKind; + std::vector<CodeActionKind> codeActionKinds; + + MAKE_SWAP_METHOD(CodeActionOptions, workDoneProgress, codeActionKinds); +}; +MAKE_REFLECT_STRUCT(CodeActionOptions, workDoneProgress, codeActionKinds) +struct CodeLensOptions : WorkDoneProgressOptions { + // + // Code lens has a resolve provider as well. + // + boost::optional<bool> resolveProvider ; + MAKE_SWAP_METHOD(CodeLensOptions, workDoneProgress, resolveProvider); +}; +MAKE_REFLECT_STRUCT(CodeLensOptions, workDoneProgress, resolveProvider) + + +// Format document on type options +struct lsDocumentOnTypeFormattingOptions :WorkDoneProgressOptions { + // A character on which formatting should be triggered, like `}`. + std::string firstTriggerCharacter; + + // More trigger characters. + std::vector<std::string> moreTriggerCharacter; + MAKE_SWAP_METHOD(lsDocumentOnTypeFormattingOptions, workDoneProgress, + firstTriggerCharacter, + moreTriggerCharacter); +}; +MAKE_REFLECT_STRUCT(lsDocumentOnTypeFormattingOptions, workDoneProgress, + firstTriggerCharacter, + moreTriggerCharacter); +struct RenameOptions : WorkDoneProgressOptions { + // + // Renames should be checked and tested before being executed. + // + boost::optional<bool> prepareProvider; + MAKE_SWAP_METHOD(RenameOptions, workDoneProgress, prepareProvider); +}; +MAKE_REFLECT_STRUCT(RenameOptions,workDoneProgress,prepareProvider) + +struct DocumentFilter{ + // + // A language id, like `typescript`. + // + boost::optional<std::string> language; + // + // A Uri [scheme](#Uri.scheme), like `file` or `untitled`. + // + boost::optional<std::string>scheme; + // + // A glob pattern, like `*.{ts,js}`. + // + // Glob patterns can have the following syntax: + // - `*` to match one or more characters in a path segment + // - `?` to match on one character in a path segment + // - `**` to match any number of path segments, including none + // - `{}` to group sub patterns into an OR expression. (e.g. `**/*.{ts,js} + // matches all TypeScript and JavaScript files) + // - `[]` to declare a range of characters to match in a path segment + // (e.g., `example.[0-9]` to match on `example.0`, `example.1`,...) + // - `[!...]` to negate a range of characters to match in a path segment + // (e.g., `example.[!0-9]` to match on `example.a`, `example.b`, but + // not `example.0`) + // + boost::optional<std::string>pattern; + MAKE_SWAP_METHOD(DocumentFilter, language, scheme, pattern) +}; +MAKE_REFLECT_STRUCT(DocumentFilter, language, scheme, pattern) + +//A document selector is the combination of one or more document filters. +using DocumentSelector = std::vector<DocumentFilter>; + +// Document link options +struct lsDocumentLinkOptions :WorkDoneProgressOptions { + // Document links have a resolve provider as well. + boost::optional<bool> resolveProvider; + MAKE_SWAP_METHOD(lsDocumentLinkOptions, workDoneProgress, resolveProvider); +}; +MAKE_REFLECT_STRUCT(lsDocumentLinkOptions, workDoneProgress,resolveProvider); + +// Execute command options. +struct lsExecuteCommandOptions : WorkDoneProgressOptions { + // The commands to be executed on the server + std::vector<std::string> commands; + MAKE_SWAP_METHOD(lsExecuteCommandOptions, workDoneProgress, commands); +}; +MAKE_REFLECT_STRUCT(lsExecuteCommandOptions, workDoneProgress, commands); + + +struct TextDocumentRegistrationOptions +{ +// + // A document selector to identify the scope of the registration. If set to null + // the document selector provided on the client side will be used. + // + boost::optional<DocumentSelector> documentSelector; + + MAKE_SWAP_METHOD(TextDocumentRegistrationOptions, documentSelector); +}; +MAKE_REFLECT_STRUCT(TextDocumentRegistrationOptions, documentSelector); + +// + // Static registration options to be returned in the initialize request. + // +struct StaticRegistrationOptions :public TextDocumentRegistrationOptions +{ + // + // The id used to register the request. The id can be used to deregister + // the request again. See also Registration#id. + // + boost::optional<std::string> id; + MAKE_SWAP_METHOD(StaticRegistrationOptions, documentSelector, id) +}; +MAKE_REFLECT_STRUCT(StaticRegistrationOptions, documentSelector,id) + +// + // The server supports workspace folder. + // + // Since 3.6.0 + // + +struct WorkspaceFoldersOptions { + // + // The server has support for workspace folders + // + boost::optional<bool> supported; + + // + // Whether the server wants to receive workspace folder + // change notifications. + // + // If a string is provided, the string is treated as an ID + // under which the notification is registered on the client + // side. The ID can be used to unregister for these events + // using the `client/unregisterCapability` request. + // + boost::optional<std::pair< boost::optional<std::string>, boost::optional<bool> > > changeNotifications; + MAKE_SWAP_METHOD(WorkspaceFoldersOptions, supported, changeNotifications); +}; +MAKE_REFLECT_STRUCT(WorkspaceFoldersOptions, supported, changeNotifications); + +// + // A pattern kind describing if a glob pattern matches a file a folder or + // both. + // + // @since 3.16.0 + // +enum lsFileOperationPatternKind +{ + file, + folder +}; +MAKE_REFLECT_TYPE_PROXY(lsFileOperationPatternKind) + +// + // Matching options for the file operation pattern. + // + // @since 3.16.0 + // +struct lsFileOperationPatternOptions { + + // + // The pattern should be matched ignoring casing. + // + boost::optional<bool> ignoreCase; + MAKE_SWAP_METHOD(lsFileOperationPatternOptions, ignoreCase) +}; +MAKE_REFLECT_STRUCT(lsFileOperationPatternOptions, ignoreCase) +// + // A pattern to describe in which file operation requests or notifications + // the server is interested in. + // + // @since 3.16.0 + // +struct lsFileOperationPattern { + // + // The glob pattern to match. Glob patterns can have the following syntax: + // - `*` to match one or more characters in a path segment + // - `?` to match on one character in a path segment + // - `**` to match any number of path segments, including none + // - `{}` to group sub patterns into an OR expression. (e.g. `**/*.{ts,js}` + // matches all TypeScript and JavaScript files) + // - `[]` to declare a range of characters to match in a path segment + // (e.g., `example.[0-9]` to match on `example.0`, `example.1`,...) + // - `[!...]` to negate a range of characters to match in a path segment + // (e.g., `example.[!0-9]` to match on `example.a`, `example.b`, but + // not `example.0`) + // + std::string glob; + + // + // Whether to match files or folders with this pattern. + // + // Matches both if undefined. + // + boost::optional<lsFileOperationPatternKind> matches; + + // + // Additional options used during matching. + // + boost::optional<lsFileOperationPatternOptions> options ; + MAKE_SWAP_METHOD(lsFileOperationPattern, glob, matches, options) +}; +MAKE_REFLECT_STRUCT(lsFileOperationPattern, glob, matches, options) +// + // A filter to describe in which file operation requests or notifications + // the server is interested in. + // + // @since 3.16.0 + // +struct lsFileOperationFilter { + + // + // A Uri like `file` or `untitled`. + // + boost::optional<std::string> scheme; + + // + // The actual file operation pattern. + // + boost::optional<lsFileOperationPattern> pattern; + MAKE_SWAP_METHOD(lsFileOperationFilter, scheme, pattern) +}; +MAKE_REFLECT_STRUCT(lsFileOperationFilter, scheme, pattern) +// + // The options to register for file operations. + // + // @since 3.16.0 + // +struct lsFileOperationRegistrationOptions { + // + // The actual filters. + // + boost::optional<std::vector<lsFileOperationFilter>> filters; + MAKE_SWAP_METHOD(lsFileOperationRegistrationOptions, filters) +}; +MAKE_REFLECT_STRUCT(lsFileOperationRegistrationOptions, filters) + +struct WorkspaceServerCapabilities { + // + // The server supports workspace folder. + // + // Since 3.6.0 + // + WorkspaceFoldersOptions workspaceFolders; + + + // + // The server is interested in file notifications/requests. + // + // @since 3.16.0 + // + struct lsFileOperations + { + // + // The server is interested in receiving didCreateFiles + // notifications. + // + boost::optional<lsFileOperationRegistrationOptions> didCreate; + + // + // The server is interested in receiving willCreateFiles requests. + // + boost::optional<lsFileOperationRegistrationOptions> willCreate; + + // + // The server is interested in receiving didRenameFiles + // notifications. + // + boost::optional<lsFileOperationRegistrationOptions> didRename; + + // + // The server is interested in receiving willRenameFiles requests. + // + boost::optional<lsFileOperationRegistrationOptions> willRename; + + // + // The server is interested in receiving didDeleteFiles file + // notifications. + // + boost::optional<lsFileOperationRegistrationOptions> didDelete; + + // + // The server is interested in receiving willDeleteFiles file + // requests. + // + boost::optional<lsFileOperationRegistrationOptions> willDelete; + MAKE_SWAP_METHOD(lsFileOperations, didCreate, willCreate, didRename, willRename, didDelete, willDelete) + }; + boost::optional<lsFileOperations>fileOperations; + + + MAKE_SWAP_METHOD(WorkspaceServerCapabilities, workspaceFolders, fileOperations) +}; +MAKE_REFLECT_STRUCT(WorkspaceServerCapabilities, workspaceFolders, fileOperations) +MAKE_REFLECT_STRUCT(WorkspaceServerCapabilities::lsFileOperations, didCreate, willCreate, didRename, willRename, didDelete, willDelete) + +// + // Semantic highlighting server capabilities. + // + // <p> + // <b>Note:</b> the <a href= + // "https://github.com/Microsoft/vscode-languageserver-node/pull/367">{@code textDocument/semanticHighlighting} + // language feature</a> is not yet part of the official LSP specification. + // + +struct SemanticHighlightingServerCapabilities { + // + // A "lookup table" of semantic highlighting <a href="https://manual.macromates.com/en/language_grammars">TextMate scopes</a> + // supported by the language server. If not defined or empty, then the server does not support the semantic highlighting + // feature. Otherwise, clients should reuse this "lookup table" when receiving semantic highlighting notifications from + // the server. + // + std::vector< std::vector<std::string> > scopes; + MAKE_SWAP_METHOD(SemanticHighlightingServerCapabilities, scopes) +}; +MAKE_REFLECT_STRUCT(SemanticHighlightingServerCapabilities, scopes) + +struct SemanticTokensServerFull +{ + // + // The server supports deltas for full documents. + // + bool delta =false; + MAKE_SWAP_METHOD(SemanticTokensServerFull, delta) +}; +MAKE_REFLECT_STRUCT(SemanticTokensServerFull, delta) +struct SemanticTokensWithRegistrationOptions +{ + SemanticTokensLegend legend; + + // + // Server supports providing semantic tokens for a specific range + // of a document. + // + boost::optional< std::pair< boost::optional<bool>, boost::optional<lsp::Any> > > range; + + // + // Server supports providing semantic tokens for a full document. + // + boost::optional< std::pair< boost::optional<bool>, + boost::optional<SemanticTokensServerFull> > > full; + + // + // A document selector to identify the scope of the registration. If set to null + // the document selector provided on the client side will be used. + // + boost::optional < std::vector<DocumentFilter> > documentSelector; + // + // The id used to register the request. The id can be used to deregister + // the request again. See also Registration#id. + // + boost::optional<std::string> id; + MAKE_SWAP_METHOD(SemanticTokensWithRegistrationOptions, legend, range, full, documentSelector, id) +}; +MAKE_REFLECT_STRUCT(SemanticTokensWithRegistrationOptions, legend, range, full, documentSelector ,id) + +using DocumentColorOptions = WorkDoneProgressOptions; +using FoldingRangeOptions = WorkDoneProgressOptions; +struct lsServerCapabilities { + // Defines how text documents are synced. Is either a detailed structure + // defining each notification or for backwards compatibility the + + // TextDocumentSyncKind number. + boost::optional< std::pair<boost::optional<lsTextDocumentSyncKind>, + boost::optional<lsTextDocumentSyncOptions> >> textDocumentSync; + + // The server provides hover support. + boost::optional<bool> hoverProvider; + + // The server provides completion support. + boost::optional < lsCompletionOptions > completionProvider; + + // The server provides signature help support. + boost::optional < lsSignatureHelpOptions > signatureHelpProvider; + + // The server provides goto definition support. + boost::optional< std::pair< boost::optional<bool>, boost::optional<WorkDoneProgressOptions> > > definitionProvider; + + + // + // The server provides Goto Type Definition support. + // + // Since 3.6.0 + // + boost::optional< std::pair< boost::optional<bool>, boost::optional<StaticRegistrationOptions> > > typeDefinitionProvider ; + + // The server provides implementation support. + boost::optional< std::pair< boost::optional<bool>, boost::optional<StaticRegistrationOptions> > > implementationProvider ; + + // The server provides find references support. + boost::optional< std::pair< boost::optional<bool>, boost::optional<WorkDoneProgressOptions> > > referencesProvider ; + + // The server provides document highlight support. + boost::optional< std::pair< boost::optional<bool>, boost::optional<WorkDoneProgressOptions> > > documentHighlightProvider ; + + // The server provides document symbol support. + boost::optional< std::pair< boost::optional<bool>, boost::optional<WorkDoneProgressOptions> > > documentSymbolProvider ; + + // The server provides workspace symbol support. + boost::optional< std::pair< boost::optional<bool>, boost::optional<WorkDoneProgressOptions> > > workspaceSymbolProvider ; + + // The server provides code actions. + boost::optional< std::pair< boost::optional<bool>, boost::optional<CodeActionOptions> > > codeActionProvider ; + + // The server provides code lens. + boost::optional<CodeLensOptions> codeLensProvider; + + // The server provides document formatting. + boost::optional< std::pair< boost::optional<bool>, boost::optional<WorkDoneProgressOptions> > > documentFormattingProvider ; + + // The server provides document range formatting. + boost::optional< std::pair< boost::optional<bool>, boost::optional<WorkDoneProgressOptions> > > documentRangeFormattingProvider ; + + // The server provides document formatting on typing. + boost::optional<lsDocumentOnTypeFormattingOptions> documentOnTypeFormattingProvider; + + // The server provides rename support. + boost::optional< std::pair< boost::optional<bool>, boost::optional<RenameOptions> > > renameProvider; + + + // The server provides document link support. + boost::optional<lsDocumentLinkOptions > documentLinkProvider; + + + // + // The server provides color provider support. + // + // @since 3.6.0 + // + boost::optional< std::pair< boost::optional<bool>, boost::optional<DocumentColorOptions> > > colorProvider; + + + // + // The server provides folding provider support. + // + // @since 3.10.0 + // + boost::optional < std::pair< boost::optional<bool>, boost::optional<FoldingRangeOptions> > > foldingRangeProvider; + + // The server provides execute command support. + boost::optional < lsExecuteCommandOptions >executeCommandProvider; + + + // + // Workspace specific server capabilities + // + boost::optional< WorkspaceServerCapabilities > workspace; + + // + // Semantic highlighting server capabilities. + // + + boost::optional< SemanticHighlightingServerCapabilities >semanticHighlighting; + + // + // Server capability for calculating super- and subtype hierarchies. + // The LS supports the type hierarchy language feature, if this capability is set to {@code true}. + // + // <p> + // <b>Note:</b> the <a href= + // "https://github.com/Microsoft/vscode-languageserver-node/pull/426">{@code textDocument/typeHierarchy} + // language feature</a> is not yet part of the official LSP specification. + // + + boost::optional< std::pair< boost::optional<bool>, + boost::optional<StaticRegistrationOptions> > > typeHierarchyProvider; + + // + // The server provides Call Hierarchy support. + // + + boost::optional< std::pair< boost::optional<bool>, + boost::optional<StaticRegistrationOptions> > > callHierarchyProvider; + + // + // The server provides selection range support. + // + // Since 3.15.0 + // + boost::optional< std::pair< boost::optional<bool>, + boost::optional<StaticRegistrationOptions> > > selectionRangeProvider; + + // + // The server provides linked editing range support. + // + // Since 3.16.0 + // + boost::optional< std::pair< boost::optional<bool>, + boost::optional<StaticRegistrationOptions> > > linkedEditingRangeProvider; + + + // + // The server provides semantic tokens support. + // + // Since 3.16.0 + // + boost::optional < SemanticTokensWithRegistrationOptions> semanticTokensProvider; + + // + // Whether server provides moniker support. + // + // Since 3.16.0 + // + boost::optional< std::pair< boost::optional<bool>, + boost::optional<StaticRegistrationOptions> > > monikerProvider; + + boost::optional<lsp::Any> experimental; + + + MAKE_SWAP_METHOD(lsServerCapabilities, + textDocumentSync, + hoverProvider, + completionProvider, + signatureHelpProvider, + definitionProvider, + typeDefinitionProvider, + implementationProvider, + referencesProvider, + documentHighlightProvider, + documentSymbolProvider, + workspaceSymbolProvider, + codeActionProvider, + codeLensProvider, + documentFormattingProvider, + documentRangeFormattingProvider, + documentOnTypeFormattingProvider, + renameProvider, + documentLinkProvider, + executeCommandProvider, + workspace, + semanticHighlighting, + typeHierarchyProvider, + callHierarchyProvider, + selectionRangeProvider, + experimental, colorProvider, foldingRangeProvider, + linkedEditingRangeProvider, monikerProvider, semanticTokensProvider) + +}; +MAKE_REFLECT_STRUCT(lsServerCapabilities, + textDocumentSync, + hoverProvider, + completionProvider, + signatureHelpProvider, + definitionProvider, + typeDefinitionProvider, + implementationProvider, + referencesProvider, + documentHighlightProvider, + documentSymbolProvider, + workspaceSymbolProvider, + codeActionProvider, + codeLensProvider, + documentFormattingProvider, + documentRangeFormattingProvider, + documentOnTypeFormattingProvider, + renameProvider, + documentLinkProvider, + executeCommandProvider, + workspace, + semanticHighlighting, + typeHierarchyProvider, + callHierarchyProvider, + selectionRangeProvider, + experimental, colorProvider, foldingRangeProvider, + linkedEditingRangeProvider, monikerProvider, semanticTokensProvider) diff --git a/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/general/lsTextDocumentClientCapabilities.h b/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/general/lsTextDocumentClientCapabilities.h new file mode 100644 index 00000000000..569f203c7a5 --- /dev/null +++ b/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/general/lsTextDocumentClientCapabilities.h @@ -0,0 +1,713 @@ +#pragma once +#include "LibLsp/lsp/method_type.h" + + +#include <stdexcept> +#include "LibLsp/JsonRpc/message.h" +#include "LibLsp/lsp/lsDocumentUri.h" +#include "LibLsp/lsp/lsAny.h" +#include "LibLsp/lsp/extention/jdtls/searchSymbols.h" +#include "lsWorkspaceClientCapabilites.h" +#include "LibLsp/lsp/lsp_completion.h" +#include "LibLsp/lsp/lsp_diagnostic.h" + + +struct WorkDoneProgressOptions +{ + boost::optional<bool>workDoneProgress; + MAKE_SWAP_METHOD(WorkDoneProgressOptions, workDoneProgress); +}; +MAKE_REFLECT_STRUCT(WorkDoneProgressOptions, workDoneProgress); + +// Completion options. +struct lsCompletionOptions:WorkDoneProgressOptions +{ + // The server provides support to resolve additional + // information for a completion item. + boost::optional<bool> resolveProvider = false; + + // + // Most tools trigger completion request automatically without explicitly requesting + // it using a keyboard shortcut (e.g. Ctrl+Space). Typically they do so when the user + // starts to type an identifier. For example if the user types `c` in a JavaScript file + // code complete will automatically pop up present `console` besides others as a + // completion item. Characters that make up identifiers don't need to be listed here. + // + // If code complete should automatically be trigger on characters not being valid inside + // an identifier (for example `.` in JavaScript) list them in `triggerCharacters`. + // + // https://github.com/Microsoft/language-server-protocol/issues/138. + boost::optional< std::vector<std::string> > triggerCharacters ; + + // + // The list of all possible characters that commit a completion. This field can be used + // if clients don't support individual commmit characters per completion item. See + // `ClientCapabilities.textDocument.completion.completionItem.commitCharactersSupport` + // + boost::optional< std::vector<std::string> > allCommitCharacters; + + MAKE_SWAP_METHOD(lsCompletionOptions, workDoneProgress, resolveProvider, triggerCharacters, allCommitCharacters); +}; +MAKE_REFLECT_STRUCT(lsCompletionOptions, workDoneProgress, resolveProvider, triggerCharacters,allCommitCharacters); + + + +// Save options. +struct lsSaveOptions { + // The client is supposed to include the content on save. + bool includeText = false; + void swap(lsSaveOptions& arg)noexcept + { + auto temp = includeText; + includeText = arg.includeText; + arg.includeText = temp; + } +}; +MAKE_REFLECT_STRUCT(lsSaveOptions, includeText); + +// Signature help options. +struct lsSignatureHelpOptions : WorkDoneProgressOptions { + // The characters that trigger signature help automatically. + // NOTE: If updating signature help tokens make sure to also update + // WorkingFile::FindClosestCallNameInBuffer. + std::vector<std::string> triggerCharacters; + MAKE_SWAP_METHOD(lsSignatureHelpOptions, workDoneProgress, triggerCharacters); +}; +MAKE_REFLECT_STRUCT(lsSignatureHelpOptions, workDoneProgress, triggerCharacters); + +// Defines how the host (editor) should sync document changes to the language +// server. +enum class lsTextDocumentSyncKind { + // Documents should not be synced at all. + None = 0, + + // Documents are synced by always sending the full content + // of the document. + Full = 1, + + // Documents are synced by sending the full content on open. + // After that only incremental updates to the document are + // send. + Incremental = 2 +}; + +#if _WIN32 +MAKE_REFLECT_TYPE_PROXY(lsTextDocumentSyncKind) +#else +//#pragma clang diagnostic push +//#pragma clang diagnostic ignored "-Wunused-function" +MAKE_REFLECT_TYPE_PROXY(lsTextDocumentSyncKind) +//#pragma clang diagnostic pop +#endif + +struct lsTextDocumentSyncOptions { + // Open and close notifications are sent to the server. + boost::optional<bool> openClose ; + // Change notificatins are sent to the server. See TextDocumentSyncKind.None, + // TextDocumentSyncKind.Full and TextDocumentSyncKindIncremental. + boost::optional< lsTextDocumentSyncKind> change ; + // Will save notifications are sent to the server. + boost::optional<bool> willSave; + // Will save wait until requests are sent to the server. + boost::optional<bool> willSaveWaitUntil; + // Save notifications are sent to the server. + boost::optional<lsSaveOptions> save; + + MAKE_SWAP_METHOD(lsTextDocumentSyncOptions, + openClose, + change, + willSave, + willSaveWaitUntil, + save); +}; +MAKE_REFLECT_STRUCT(lsTextDocumentSyncOptions, + openClose, + change, + willSave, + willSaveWaitUntil, + save); + +struct SynchronizationCapabilities { + // Whether text document synchronization supports dynamic registration. + boost::optional<bool> dynamicRegistration; + + // The client supports sending will save notifications. + boost::optional<bool> willSave; + + // The client supports sending a will save request and + // waits for a response providing text edits which will + // be applied to the document before it is saved. + boost::optional<bool> willSaveWaitUntil; + + // The client supports did save notifications. + boost::optional<bool> didSave; + + MAKE_SWAP_METHOD(SynchronizationCapabilities, + dynamicRegistration, + willSave, + willSaveWaitUntil, + didSave); +}; +MAKE_REFLECT_STRUCT(SynchronizationCapabilities, + dynamicRegistration, + willSave, + willSaveWaitUntil, + didSave); + +struct CompletionItemKindCapabilities +{ + boost::optional<std::vector<lsCompletionItemKind> >valueSet; + MAKE_SWAP_METHOD(CompletionItemKindCapabilities, valueSet); +}; +MAKE_REFLECT_STRUCT(CompletionItemKindCapabilities, valueSet); + +struct CompletionItemCapabilities { + // Client supports snippets as insert text. + // + // A snippet can define tab stops and placeholders with `$1`, `$2` + // and `${3:foo}`. `$0` defines the final tab stop, it defaults to + // the end of the snippet. Placeholders with equal identifiers are linked, + // that is typing in one will update others too. + boost::optional<bool> snippetSupport; + + // Client supports commit characters on a completion item. + + boost::optional<bool> commitCharactersSupport; + + + // Client supports the following content formats for the documentation + // property. The order describes the preferred format of the client. + + boost::optional< std::vector<std::string> > documentationFormat; + + // Client supports the deprecated property on a completion item. + + boost::optional<bool> deprecatedSupport; + + // + // Client supports the preselect property on a completion item. + // + boost::optional<bool> preselectSupport; + + MAKE_SWAP_METHOD(CompletionItemCapabilities, + snippetSupport, + commitCharactersSupport, + documentationFormat, + deprecatedSupport, preselectSupport); +}; +MAKE_REFLECT_STRUCT(CompletionItemCapabilities, + snippetSupport, + commitCharactersSupport, + documentationFormat, + deprecatedSupport, preselectSupport); + + +// + // Capabilities specific to the `textDocument/completion` + // +struct CompletionCapabilities { + // Whether completion supports dynamic registration. + boost::optional<bool> dynamicRegistration; + + + + // The client supports the following `CompletionItem` specific + // capabilities. + boost::optional<CompletionItemCapabilities> completionItem; + + // + // The client supports the following `CompletionItemKind` specific + // capabilities. + // + boost::optional<CompletionItemKindCapabilities> completionItemKind; + + // + // The client supports sending additional context information for a + // `textDocument/completion` request. + // + boost::optional<bool> contextSupport; + + + MAKE_SWAP_METHOD(CompletionCapabilities, + dynamicRegistration, + completionItem, completionItemKind); +}; + +MAKE_REFLECT_STRUCT(CompletionCapabilities, + dynamicRegistration, + completionItem , completionItemKind); + + +struct HoverCapabilities:public DynamicRegistrationCapabilities +{ + // + // Client supports the following content formats for the content + // property. The order describes the preferred format of the client. + // + // See {@link MarkupKind} for allowed values. + // + boost::optional<std::vector<std::string>> contentFormat; + + MAKE_SWAP_METHOD(HoverCapabilities, dynamicRegistration, contentFormat); +}; +MAKE_REFLECT_STRUCT(HoverCapabilities, dynamicRegistration, contentFormat); + +// + // Client capabilities specific to parameter information. + // +struct ParameterInformationCapabilities { + // + // The client supports processing label offsets instead of a + // simple label string. + // + // Since 3.14.0 + // + boost::optional<bool> labelOffsetSupport; + + MAKE_SWAP_METHOD(ParameterInformationCapabilities, labelOffsetSupport); +}; +MAKE_REFLECT_STRUCT(ParameterInformationCapabilities, labelOffsetSupport) + + +struct SignatureInformationCapabilities { + // + // Client supports the following content formats for the documentation + // property. The order describes the preferred format of the client. + // + // See {@link MarkupKind} for allowed values. + // + std::vector<std::string> documentationFormat; + + // + // Client capabilities specific to parameter information. + // + ParameterInformationCapabilities parameterInformation; + + MAKE_SWAP_METHOD(SignatureInformationCapabilities, documentationFormat, parameterInformation) +}; +MAKE_REFLECT_STRUCT(SignatureInformationCapabilities,documentationFormat, parameterInformation) + +struct SignatureHelpCapabilities :public DynamicRegistrationCapabilities +{ + // + // The client supports the following `SignatureInformation` + // specific properties. + // + boost::optional< SignatureInformationCapabilities > signatureInformation; + + MAKE_SWAP_METHOD(SignatureHelpCapabilities, dynamicRegistration, signatureInformation) +}; +MAKE_REFLECT_STRUCT(SignatureHelpCapabilities, dynamicRegistration, signatureInformation) + +struct DocumentSymbolCapabilities :public DynamicRegistrationCapabilities { + // + // Specific capabilities for the `SymbolKind`. + // + boost::optional<SymbolKindCapabilities> symbolKind; + + // + // The client support hierarchical document symbols. + // + boost::optional<bool> hierarchicalDocumentSymbolSupport; + + MAKE_SWAP_METHOD(DocumentSymbolCapabilities, dynamicRegistration, symbolKind, hierarchicalDocumentSymbolSupport) +}; +MAKE_REFLECT_STRUCT(DocumentSymbolCapabilities, dynamicRegistration, symbolKind, hierarchicalDocumentSymbolSupport) + +struct DeclarationCapabilities:public DynamicRegistrationCapabilities{ + // + // The client supports additional metadata in the form of declaration links. + // + boost::optional<bool>linkSupport; + + MAKE_SWAP_METHOD(DeclarationCapabilities, dynamicRegistration, linkSupport); +}; +MAKE_REFLECT_STRUCT(DeclarationCapabilities, dynamicRegistration, linkSupport) + + +struct CodeActionKindCapabilities +{ + // + // The code action kind values the client supports. When this + // property exists the client also guarantees that it will + // handle values outside its set gracefully and falls back + // to a default value when unknown. + // + // See {@link CodeActionKind} for allowed values. + // + boost::optional< std::vector< std::string> >valueSet; + + MAKE_SWAP_METHOD(CodeActionKindCapabilities, valueSet) +}; +MAKE_REFLECT_STRUCT(CodeActionKindCapabilities,valueSet) + +struct CodeActionLiteralSupportCapabilities +{ + boost::optional<CodeActionKindCapabilities> codeActionKind; + + MAKE_SWAP_METHOD(CodeActionLiteralSupportCapabilities, codeActionKind) +}; +MAKE_REFLECT_STRUCT(CodeActionLiteralSupportCapabilities, codeActionKind) + +struct CodeActionCapabilities:public DynamicRegistrationCapabilities{ + // + // The client support code action literals as a valid + // response of the `textDocument/codeAction` request. + // + boost::optional<CodeActionLiteralSupportCapabilities> codeActionLiteralSupport; + + MAKE_SWAP_METHOD(CodeActionCapabilities, dynamicRegistration, codeActionLiteralSupport) +}; +MAKE_REFLECT_STRUCT(CodeActionCapabilities,dynamicRegistration,codeActionLiteralSupport) + +struct RenameCapabilities :public DynamicRegistrationCapabilities { + // + // The client support code action literals as a valid + // response of the `textDocument/codeAction` request. + // + boost::optional<bool> prepareSupport; + + MAKE_SWAP_METHOD(RenameCapabilities, dynamicRegistration, prepareSupport) +}; +MAKE_REFLECT_STRUCT(RenameCapabilities, dynamicRegistration, prepareSupport) + +struct DiagnosticsTagSupport { + /** + * The tags supported by the client. + */ + std::vector<DiagnosticTag> valueSet; + MAKE_SWAP_METHOD(DiagnosticsTagSupport, valueSet) +}; +MAKE_REFLECT_STRUCT(DiagnosticsTagSupport, valueSet) + +struct PublishDiagnosticsClientCapabilities :public DynamicRegistrationCapabilities { + /** + * The client support code action literals as a valid + * response of the `textDocument/codeAction` request. + */ + boost::optional<bool> relatedInformation; + + /** + * Client supports the tag property to provide meta data about a diagnostic. + * Clients supporting tags have to handle unknown tags gracefully. + * + * This property had been added and implemented as boolean before it was + * added to the specification as {@link DiagnosticsTagSupport}. In order to + * keep this implementation compatible with intermediate clients (including + * vscode-language-client < 6.0.0) we add an either type here. + * + * Since 3.15 + */ + boost::optional < std::pair<boost::optional<bool>, boost::optional<DiagnosticsTagSupport> > > tagSupport; + + /** + * Whether the client interprets the version property of the + * `textDocument/publishDiagnostics` notification's parameter. + * + * Since 3.15.0 + */ + boost::optional<bool> versionSupport; + + /** + * Client supports a codeDescription property + * + * @since 3.16.0 + */ + boost::optional<bool> codeDescriptionSupport ; + + /** + * Whether code action supports the `data` property which is + * preserved between a `textDocument/publishDiagnostics` and + * `textDocument/codeAction` request. + * + * @since 3.16.0 + */ + boost::optional<bool> dataSupport ; + + + MAKE_SWAP_METHOD(PublishDiagnosticsClientCapabilities, dynamicRegistration, relatedInformation, tagSupport,versionSupport,codeDescriptionSupport,dataSupport) +}; +MAKE_REFLECT_STRUCT(PublishDiagnosticsClientCapabilities, dynamicRegistration, relatedInformation, tagSupport, versionSupport, codeDescriptionSupport, dataSupport) + + +struct FoldingRangeCapabilities :public DynamicRegistrationCapabilities { + // + // The maximum number of folding ranges that the client prefers to receive per document. The value serves as a + // hint, servers are free to follow the limit. + // + boost::optional<int> rangeLimit; + + // + // If set, the client signals that it only supports folding complete lines. If set, client will + // ignore specified `startCharacter` and `endCharacter` properties in a FoldingRange. + // + boost::optional<bool> lineFoldingOnly; + MAKE_SWAP_METHOD(FoldingRangeCapabilities, dynamicRegistration, rangeLimit, lineFoldingOnly) +}; +MAKE_REFLECT_STRUCT(FoldingRangeCapabilities, dynamicRegistration, rangeLimit,lineFoldingOnly) + + +struct SemanticHighlightingCapabilities :public DynamicRegistrationCapabilities { + // + // The client support code action literals as a valid + // response of the `textDocument/codeAction` request. + // + boost::optional<bool> semanticHighlighting; + + MAKE_SWAP_METHOD(SemanticHighlightingCapabilities, dynamicRegistration, semanticHighlighting) +}; +MAKE_REFLECT_STRUCT(SemanticHighlightingCapabilities, dynamicRegistration, semanticHighlighting) + +struct SemanticTokensClientCapabilitiesRequestsFull { + + // + // The client will send the `textDocument/semanticTokens/full/delta` request if + // the server provides a corresponding handler. + // + bool delta = false; + MAKE_SWAP_METHOD(SemanticTokensClientCapabilitiesRequestsFull, delta) +}; +MAKE_REFLECT_STRUCT(SemanticTokensClientCapabilitiesRequestsFull, delta) + +struct SemanticTokensClientCapabilities : public DynamicRegistrationCapabilities +{ + //export TokenFormat = 'relative'; + struct lsRequests + { + // + // The client will send the `textDocument/semanticTokens/range` request + // if the server provides a corresponding handler. + // + boost::optional<std::pair< boost::optional<bool>, + boost::optional<SemanticTokensClientCapabilitiesRequestsFull>>> range; + // + // The client will send the `textDocument/semanticTokens/full` request + // if the server provides a corresponding handler. + // + boost::optional<std::pair< boost::optional<bool>, boost::optional<lsp::Any>>> full; + MAKE_SWAP_METHOD(lsRequests, range, full) + }; + + lsRequests requests; + // + // The token types that the client supports. + // + std::vector<std::string> tokenTypes; + + // + // The token modifiers that the client supports. + // + std::vector<std::string> tokenModifiers; + // + // The formats the clients supports. + // + std::vector<std::string> formats; + // + // Whether the client supports tokens that can overlap each other. + // + boost::optional < bool >overlappingTokenSupport; + + // + // Whether the client supports tokens that can span multiple lines. + // + boost::optional < bool > multilineTokenSupport; + + MAKE_SWAP_METHOD(SemanticTokensClientCapabilities, dynamicRegistration,requests, tokenTypes, tokenModifiers, + formats, overlappingTokenSupport, multilineTokenSupport) + +}; +MAKE_REFLECT_STRUCT(SemanticTokensClientCapabilities::lsRequests, range,full) +MAKE_REFLECT_STRUCT(SemanticTokensClientCapabilities, dynamicRegistration, requests, tokenTypes, tokenModifiers, + formats, overlappingTokenSupport, multilineTokenSupport) + +// Text document specific client capabilities. +struct lsTextDocumentClientCapabilities { + + SynchronizationCapabilities synchronization; + + + // Capabilities specific to the `textDocument/completion` + boost::optional<CompletionCapabilities> completion; + + + + // Capabilities specific to the `textDocument/hover` + boost::optional<HoverCapabilities> hover; + + // Capabilities specific to the `textDocument/signatureHelp` + boost::optional<SignatureHelpCapabilities> signatureHelp; + + // Capabilities specific to the `textDocument/references` + boost::optional<DynamicRegistrationCapabilities> references; + + + + + + // Capabilities specific to the `textDocument/documentHighlight` + boost::optional<DynamicRegistrationCapabilities> documentHighlight; + + // Capabilities specific to the `textDocument/documentSymbol` + boost::optional<DocumentSymbolCapabilities> documentSymbol; + + // Capabilities specific to the `textDocument/formatting` + boost::optional<DynamicRegistrationCapabilities> formatting; + + // Capabilities specific to the `textDocument/rangeFormatting` + boost::optional<DynamicRegistrationCapabilities> rangeFormatting; + + // Capabilities specific to the `textDocument/onTypeFormatting` + boost::optional<DynamicRegistrationCapabilities> onTypeFormatting; + + + // + // Capabilities specific to the `textDocument/declaration` + // + // Since 3.14.0 + // + boost::optional< DeclarationCapabilities> declaration; + + + typedef DeclarationCapabilities DefinitionCapabilities; + // Capabilities specific to the `textDocument/definition` + boost::optional<DefinitionCapabilities> definition; + + + + // +// Capabilities specific to the `textDocument/typeDefinition` +// +// Since 3.6.0 +// + typedef DeclarationCapabilities TypeDefinitionCapabilities; + boost::optional<TypeDefinitionCapabilities> typeDefinition; + + + typedef DeclarationCapabilities ImplementationCapabilities; + // Capabilities specific to the `textDocument/implementation` + boost::optional<ImplementationCapabilities> implementation; + + + // Capabilities specific to the `textDocument/codeAction` + boost::optional<CodeActionCapabilities> codeAction; + + + // Capabilities specific to the `textDocument/codeLens` + boost::optional<DynamicRegistrationCapabilities> codeLens; + + // Capabilities specific to the `textDocument/documentLink` + boost::optional<DynamicRegistrationCapabilities> documentLink; + + // + // Capabilities specific to the `textDocument/documentColor` and the + // `textDocument/colorPresentation` request. + // + // Since 3.6.0 + // + boost::optional<DynamicRegistrationCapabilities> colorProvider; + + // Capabilities specific to the `textDocument/rename` + boost::optional<RenameCapabilities> rename; + +// +// Capabilities specific to `textDocument/publishDiagnostics`. +// + boost::optional<PublishDiagnosticsClientCapabilities> publishDiagnostics; + + // +// Capabilities specific to `textDocument/foldingRange` requests. +// +// Since 3.10.0 +// + boost::optional< FoldingRangeCapabilities > foldingRange; + + + // + // Capabilities specific to {@code textDocument/semanticHighlighting}. + // + boost::optional< SemanticHighlightingCapabilities > semanticHighlightingCapabilities; + + // + // Capabilities specific to {@code textDocument/typeHierarchy}. + // + boost::optional< DynamicRegistrationCapabilities > typeHierarchyCapabilities; + + + + // +// Capabilities specific to `textDocument/selectionRange` requests +// + + boost::optional< DynamicRegistrationCapabilities > selectionRange; + + // + // Capabilities specific to the `textDocument/linkedEditingRange` request. + // + // @since 3.16.0 + // + boost::optional< DynamicRegistrationCapabilities > linkedEditingRange; + + // + // Capabilities specific to the various call hierarchy requests. + // + // @since 3.16.0 + // + boost::optional< DynamicRegistrationCapabilities > callHierarchy; + + // + // Capabilities specific to the various semantic token requests. + // + // @since 3.16.0 + // + boost::optional< SemanticTokensClientCapabilities > semanticTokens; + + // + // Capabilities specific to the `textDocument/moniker` request. + // + // @since 3.16.0 + // + boost::optional< DynamicRegistrationCapabilities > moniker; + + MAKE_SWAP_METHOD(lsTextDocumentClientCapabilities, + synchronization, + completion, + hover, + signatureHelp, + implementation, + references, + documentHighlight, + documentSymbol, + formatting, + rangeFormatting, + onTypeFormatting, + declaration, + definition, typeDefinition, implementation, + codeAction, + codeLens, + documentLink, colorProvider, + rename, publishDiagnostics, foldingRange, + semanticHighlightingCapabilities, typeHierarchyCapabilities, + callHierarchy, selectionRange , linkedEditingRange, semanticTokens, moniker) +}; + + +MAKE_REFLECT_STRUCT(lsTextDocumentClientCapabilities, + synchronization, + completion, + hover, + signatureHelp, + implementation, + references, + documentHighlight, + documentSymbol, + formatting, + rangeFormatting, + onTypeFormatting, + declaration, + definition, typeDefinition, implementation, + codeAction, + codeLens, + documentLink, colorProvider, + rename, publishDiagnostics, foldingRange, + semanticHighlightingCapabilities, typeHierarchyCapabilities, + callHierarchy, selectionRange, linkedEditingRange, semanticTokens, moniker) diff --git a/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/general/lsWorkspaceClientCapabilites.h b/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/general/lsWorkspaceClientCapabilites.h new file mode 100644 index 00000000000..dd37a1af2ff --- /dev/null +++ b/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/general/lsWorkspaceClientCapabilites.h @@ -0,0 +1,256 @@ +#pragma once +#include "LibLsp/lsp/method_type.h" + + +#include <stdexcept> + +#include "LibLsp/JsonRpc/message.h" +#include "LibLsp/lsp/lsDocumentUri.h" +#include "LibLsp/lsp/lsAny.h" +#include "LibLsp/lsp/extention/jdtls/searchSymbols.h" + +/** + * Capabilities specific to `WorkspaceEdit`s + */ + +//New in version 3.13: ResourceOperationKind and FailureHandlingKind and the client capability workspace.workspaceEdit. +//resourceOperations as well as workspace.workspaceEdit.failureHandling. + +//The capabilities of a workspace edit has evolved over the time. +//Clients can describe their support using the following client capability : + +struct lschangeAnnotationSupport +{ + /** + * Whether the client groups edits with equal labels into tree nodes, + * for instance all edits labelled with "Changes in Strings" would + * be a tree node. + */ + boost::optional<bool> groupsOnLabel; + MAKE_SWAP_METHOD(lschangeAnnotationSupport, groupsOnLabel) +}; +MAKE_REFLECT_STRUCT(lschangeAnnotationSupport, groupsOnLabel) + +struct WorkspaceEditCapabilities { + /** + * The client supports versioned document changes in `WorkspaceEdit`s + */ + boost::optional<bool> documentChanges; + + /** + * The client supports resource changes + * in `WorkspaceEdit`s. + * + * @deprecated Since LSP introduces resource operations, use {link #resourceOperations} + */ + + boost::optional<bool> resourceChanges; + + /** + * The resource operations the client supports. Clients should at least + * support 'create', 'rename' and 'delete' files and folders. + * + * @since 3.13.0 + */ + boost::optional< std::vector<std::string> > resourceOperations; + + /** + * The failure handling strategy of a client if applying the workspace edit + * fails. + * + * See {@link FailureHandlingKind} for allowed values. + */ + boost::optional<std::string > failureHandling; + + /** + * Whether the client normalizes line endings to the client specific + * setting. + * If set to `true` the client will normalize line ending characters + * in a workspace edit to the client specific new line character(s). + * + * @since 3.16.0 + */ + boost::optional<bool> normalizesLineEndings;; + + /** + * Whether the client in general supports change annotations on text edits, + * create file, rename file and delete file changes. + * + * @since 3.16.0 + */ + boost::optional<lschangeAnnotationSupport> changeAnnotationSupport; + + MAKE_SWAP_METHOD(WorkspaceEditCapabilities, documentChanges, resourceChanges, resourceOperations, failureHandling, normalizesLineEndings, changeAnnotationSupport) + +}; +MAKE_REFLECT_STRUCT(WorkspaceEditCapabilities,documentChanges, resourceChanges, resourceOperations, failureHandling, normalizesLineEndings, changeAnnotationSupport) + + +struct DynamicRegistrationCapabilities { + // Did foo notification supports dynamic registration. + boost::optional<bool> dynamicRegistration; + + MAKE_SWAP_METHOD(DynamicRegistrationCapabilities, + dynamicRegistration); +}; + +MAKE_REFLECT_STRUCT(DynamicRegistrationCapabilities, + dynamicRegistration); + + + +// Workspace specific client capabilities. +struct SymbolKindCapabilities +{ + boost::optional< std::vector<lsSymbolKind> > valueSet; + + MAKE_SWAP_METHOD(SymbolKindCapabilities, valueSet) + + +}; +MAKE_REFLECT_STRUCT(SymbolKindCapabilities, valueSet) + + + + +struct SymbolCapabilities :public DynamicRegistrationCapabilities { + /** + * Specific capabilities for the `SymbolKind` in the `workspace/symbol` request. + */ + boost::optional<SymbolKindCapabilities> symbolKind; + + MAKE_SWAP_METHOD(SymbolCapabilities, + symbolKind, dynamicRegistration) +}; +MAKE_REFLECT_STRUCT(SymbolCapabilities, + symbolKind, dynamicRegistration) + + +struct lsFileOperations +{ + /** + * Whether the client supports dynamic registration for file + * requests/notifications. + */ + boost::optional<bool> dynamicRegistration ; + + /** + * The client has support for sending didCreateFiles notifications. + */ + boost::optional<bool>didCreate ; + + /** + * The client has support for sending willCreateFiles requests. + */ + boost::optional<bool>willCreate ; + + /** + * The client has support for sending didRenameFiles notifications. + */ + boost::optional<bool>didRename ; + + /** + * The client has support for sending willRenameFiles requests. + */ + boost::optional<bool>willRename ; + + /** + * The client has support for sending didDeleteFiles notifications. + */ + boost::optional<bool>didDelete ; + + /** + * The client has support for sending willDeleteFiles requests. + */ + boost::optional<bool> willDelete ; + MAKE_SWAP_METHOD(lsFileOperations, dynamicRegistration, didCreate, willCreate, + didRename, willRename, didDelete, willDelete) +}; +MAKE_REFLECT_STRUCT(lsFileOperations, dynamicRegistration, didCreate, willCreate, + didRename, willRename, didDelete, willDelete) + +struct lsWorkspaceClientCapabilites { + // The client supports applying batch edits to the workspace. + boost::optional<bool> applyEdit; + + + + // Capabilities specific to `WorkspaceEdit`s + boost::optional<WorkspaceEditCapabilities> workspaceEdit; + + + + // Capabilities specific to the `workspace/didChangeConfiguration` + // notification. + boost::optional<DynamicRegistrationCapabilities> didChangeConfiguration; + + // Capabilities specific to the `workspace/didChangeWatchedFiles` + // notification. + boost::optional<DynamicRegistrationCapabilities> didChangeWatchedFiles; + + // Capabilities specific to the `workspace/symbol` request. + boost::optional<SymbolCapabilities> symbol; + + // Capabilities specific to the `workspace/executeCommand` request. + boost::optional<DynamicRegistrationCapabilities> executeCommand; + + + /** + * The client has support for workspace folders. + * + * Since 3.6.0 + */ + boost::optional<bool> workspaceFolders; + + /** + * The client supports `workspace/configuration` requests. + * + * Since 3.6.0 + */ + boost::optional<bool> configuration; + + + /** + * Capabilities specific to the semantic token requests scoped to the + * workspace. + * + * @since 3.16.0 + */ + boost::optional<DynamicRegistrationCapabilities> semanticTokens ; + + /** + * Capabilities specific to the code lens requests scoped to the + * workspace. + * + * @since 3.16.0 + */ + boost::optional<DynamicRegistrationCapabilities> codeLens ; + + /** + * The client has support for file requests/notifications. + * + * @since 3.16.0 + */ + boost::optional<lsFileOperations> fileOperations; + + MAKE_SWAP_METHOD(lsWorkspaceClientCapabilites, + applyEdit, + workspaceEdit, + didChangeConfiguration, + didChangeWatchedFiles, + symbol,executeCommand, workspaceFolders, + configuration, semanticTokens, codeLens, fileOperations) +}; + +MAKE_REFLECT_STRUCT(lsWorkspaceClientCapabilites, + applyEdit, + workspaceEdit, + didChangeConfiguration, + didChangeWatchedFiles, + symbol, + executeCommand,workspaceFolders, + configuration, semanticTokens, codeLens, fileOperations) + + + + diff --git a/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/general/progress.h b/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/general/progress.h new file mode 100644 index 00000000000..01cb18d68df --- /dev/null +++ b/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/general/progress.h @@ -0,0 +1,16 @@ +#pragma once + +#include "LibLsp/JsonRpc/NotificationInMessage.h" +#include "LibLsp/lsp/lsAny.h" +//The base protocol offers also support to report progress in a generic fashion. +//This mechanism can be used to report any kind of progress including work done +//progress(usually used to report progress in the user interface using a progress bar) +//and partial result progress to support streaming of results. +struct ProgressParams +{ + std::pair<boost::optional<std::string> , boost::optional<int> > token; + lsp::Any value; + MAKE_SWAP_METHOD(ProgressParams, token, value) +}; +MAKE_REFLECT_STRUCT(ProgressParams, token, value) +DEFINE_NOTIFICATION_TYPE(Notify_Progress, ProgressParams, "$/progress"); diff --git a/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/general/shutdown.h b/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/general/shutdown.h new file mode 100644 index 00000000000..5366ff89d6b --- /dev/null +++ b/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/general/shutdown.h @@ -0,0 +1,15 @@ +#pragma once + + +#include "LibLsp/JsonRpc/lsResponseMessage.h" +#include "LibLsp/JsonRpc/RequestInMessage.h" + +/** + * The shutdown request is sent from the client to the server. It asks the + * server to shutdown, but to not exit (otherwise the response might not be + * delivered correctly to the client). There is a separate exit notification + * that asks the server to exit. + */ + +DEFINE_REQUEST_RESPONSE_TYPE(td_shutdown, boost::optional<JsonNull>, boost::optional<lsp::Any>, "shutdown"); + diff --git a/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/language/language.h b/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/language/language.h new file mode 100644 index 00000000000..b4c7829e95f --- /dev/null +++ b/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/language/language.h @@ -0,0 +1,170 @@ +#pragma once + +#include "LibLsp/JsonRpc/RequestInMessage.h" +#include "LibLsp/JsonRpc/NotificationInMessage.h" + +#include "LibLsp/lsp/lsDocumentUri.h" +#include "LibLsp/lsp/lsCommand.h" + +#ifdef _WIN32 +#include <ppltasks.h> +#endif + +struct StatusReport { + + std::string ToString() const + { + std::string info; + info += "type:" + type + "\n"; + info += "message:" + message + "\n"; + return info; + } + /** + * The message type. See { + * + */ + + std::string type; + /** + * The actual message + * + */ + + std::string message; + MAKE_SWAP_METHOD(StatusReport, type, message); +}; +MAKE_REFLECT_STRUCT(StatusReport, type, message); + +/** + * The show message notification is sent from a server to a client to ask + * the client to display a particular message in the user interface. + */ +DEFINE_NOTIFICATION_TYPE(lang_status, StatusReport, "language/status"); + + +enum class MessageType { + + /** + * An error message. + */ + Error=(1), + + /** + * A warning message. + */ + Warning=(2), + + /** + * An information message. + */ + Info=(3), + + /** + * A log message. + */ + Log=(4) +}; +MAKE_REFLECT_TYPE_PROXY(MessageType); + + +struct ActionableNotification { + + + + /** + * The message type. See { + * + */ + + MessageType severity; + /** + * The actual message + * + */ + + std::string message; + + /** + * Optional data + * + */ + + boost::optional<lsp::Any> data; + + + /** + * Optional commands + * + */ + + std::vector<lsCommandWithAny> commands; + + MAKE_SWAP_METHOD(ActionableNotification, severity, message, data, commands) +}; +MAKE_REFLECT_STRUCT(ActionableNotification, severity, message, data, commands) + + +/** + * The actionable notification is sent from a server to a client to ask the + * client to display a particular message in the user interface, and possible + * commands to execute. The commands must be implemented on the client side. + */ +DEFINE_NOTIFICATION_TYPE(lang_actionableNotification, ActionableNotification, "language/actionableNotification"); + + + +struct ProgressReport { + std::string ToString() const; + + std::string id; + + + std::string task; + + + std::string subTask; + + + std::string status; + + int totalWork = 0; + + + int workDone = 0; + + + bool complete = false; + MAKE_SWAP_METHOD(ProgressReport, id, task, subTask, status, workDone, complete); +}; + + +MAKE_REFLECT_STRUCT(ProgressReport, id, task, subTask, status, workDone, complete); + +/** + * The progress report notification is sent from a server to be handled by the + * client. + */ +DEFINE_NOTIFICATION_TYPE(lang_progressReport, ProgressReport, "language/progressReport"); + +enum EventType { + /** + * classpath updated event. + */ + ClasspathUpdated = (100), + + /** + * projects imported event. + */ + ProjectsImported = (200) +}; + +struct EventNotification +{ + int eventType; + lsp::Any data; + std::string ToString() const; + MAKE_SWAP_METHOD(EventNotification, eventType, data) +}; +MAKE_REFLECT_STRUCT(EventNotification, eventType, data); + +DEFINE_NOTIFICATION_TYPE(lang_eventNotification, EventNotification, "language/eventNotification");
\ No newline at end of file diff --git a/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/location_type.h b/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/location_type.h new file mode 100644 index 00000000000..14e130f5719 --- /dev/null +++ b/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/location_type.h @@ -0,0 +1,63 @@ +#pragma once + +#include "lsDocumentUri.h" +#include "lsRange.h" +//Represents a location inside a resource, such as a line inside a text file. +struct lsLocation { + lsLocation(); + lsLocation(lsDocumentUri uri, lsRange range); + + bool operator==(const lsLocation& other) const; + bool operator<(const lsLocation& o) const; + + lsDocumentUri uri; + lsRange range; + MAKE_SWAP_METHOD(lsLocation, uri, range) +}; +MAKE_REFLECT_STRUCT(lsLocation, uri, range) + + + +struct LinkLocation :public lsLocation +{ + std::string displayName; + std::string kind; + MAKE_REFLECT_STRUCT(LinkLocation, uri, range, displayName, kind) +}; +MAKE_REFLECT_STRUCT(LinkLocation, uri, range, displayName,kind) + +//Represents a link between a sourceand a target location. +struct LocationLink +{ + /** + * Span of the origin of this link. + * + * Used as the underlined span for mouse interaction. Defaults to the word range at + * the mouse position. + */ + boost::optional<lsRange> originSelectionRange; + + /** + * The target resource identifier of this link. + */ + + lsDocumentUri targetUri; + + /** + * The full target range of this link. If the target for example is a symbol then target range is the + * range enclosing this symbol not including leading/trailing whitespace but everything else + * like comments. This information is typically used to highlight the range in the editor. + */ + + lsRange targetRange; + + /** + * The range that should be selected and revealed when this link is being followed, e.g the name of a function. + * Must be contained by the the `targetRange`. See also `DocumentSymbol#range` + */ + + lsRange targetSelectionRange; + + MAKE_SWAP_METHOD(LocationLink, originSelectionRange, targetUri, targetRange, targetSelectionRange); +}; +MAKE_REFLECT_STRUCT(LocationLink, originSelectionRange, targetUri, targetRange, targetSelectionRange);
\ No newline at end of file diff --git a/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/lru_cache.h b/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/lru_cache.h new file mode 100644 index 00000000000..f33bc5627a8 --- /dev/null +++ b/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/lru_cache.h @@ -0,0 +1,151 @@ +#pragma once + +#include <algorithm> +#include <cassert> +#include <limits> +#include <memory> +#include <vector> + +// Cache that evicts old entries which have not been used recently. Implemented +// using array/linear search so this works well for small array sizes. +template <typename TKey, typename TValue> +struct LruCache { + explicit LruCache(int max_entries); + + // Fetches an entry for |key|. If it does not exist, |allocator| will be + // invoked to create one. + template <typename TAllocator> + TValue Get(const TKey& key, TAllocator allocator); + // Returns true if there is an entry for |key|. + bool Has(const TKey& key); + // Fetches the entry for |filename| and updates it's usage so it is less + // likely to be evicted. + bool TryGet(const TKey& key, TValue* dest); + // TryGetEntry, except the entry is removed from the cache. + bool TryTake(const TKey& key, TValue* dest); + // Inserts an entry. Evicts the oldest unused entry if there is no space. + void Insert(const TKey& key, const TValue& value); + + // Call |func| on existing entries. If |func| returns false iteration + // terminates early. + template <typename TFunc> + void IterateValues(TFunc func); + + // Empties the cache + void Clear(void); + + private: + // There is a global score counter, when we access an element we increase + // its score to the current global value, so it has the highest overall + // score. This means that the oldest/least recently accessed value has the + // lowest score. + // + // There is a bit of special logic to handle score overlow. + struct Entry { + uint32_t score = 0; + TKey key; + TValue value; + bool operator<(const Entry& other) const { return score < other.score; } + }; + + void IncrementScore(); + + std::vector<Entry> entries_; + int max_entries_ = 1; + uint32_t next_score_ = 0; +}; + +template <typename TKey, typename TValue> +LruCache<TKey, TValue>::LruCache(int max_entries) : max_entries_(max_entries) { + assert(max_entries > 0); +} + +template <typename TKey, typename TValue> +template <typename TAllocator> +TValue LruCache<TKey, TValue>::Get(const TKey& key, TAllocator allocator) { + for (Entry& entry : entries_) { + if (entry.key == key) + return entry.value; + } + + auto result = allocator(); + Insert(key, result); + return result; +} + +template <typename TKey, typename TValue> +bool LruCache<TKey, TValue>::Has(const TKey& key) { + for (Entry& entry : entries_) { + if (entry.key == key) + return true; + } + return false; +} + +template <typename TKey, typename TValue> +bool LruCache<TKey, TValue>::TryGet(const TKey& key, TValue* dest) { + // Assign new score. + for (Entry& entry : entries_) { + if (entry.key == key) { + entry.score = next_score_; + IncrementScore(); + if (dest) + *dest = entry.value; + return true; + } + } + + return false; +} + +template <typename TKey, typename TValue> +bool LruCache<TKey, TValue>::TryTake(const TKey& key, TValue* dest) { + for (size_t i = 0; i < entries_.size(); ++i) { + if (entries_[i].key == key) { + if (dest) + *dest = entries_[i].value; + entries_.erase(entries_.begin() + i); + return true; + } + } + + return false; +} + +template <typename TKey, typename TValue> +void LruCache<TKey, TValue>::Insert(const TKey& key, const TValue& value) { + if ((int)entries_.size() >= max_entries_) + entries_.erase(std::min_element(entries_.begin(), entries_.end())); + + Entry entry; + entry.score = next_score_; + IncrementScore(); + entry.key = key; + entry.value = value; + entries_.push_back(entry); +} + +template <typename TKey, typename TValue> +template <typename TFunc> +void LruCache<TKey, TValue>::IterateValues(TFunc func) { + for (Entry& entry : entries_) { + if (!func(entry.value)) + break; + } +} + +template <typename TKey, typename TValue> +void LruCache<TKey, TValue>::IncrementScore() { + // Overflow. + if (++next_score_ == 0) { + std::sort(entries_.begin(), entries_.end()); + for (Entry& entry : entries_) + entry.score = next_score_++; + } +} + +template <typename TKey, typename TValue> +void LruCache<TKey, TValue>::Clear(void) { + entries_.clear(); + next_score_ = 0; +} diff --git a/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/lsAny.h b/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/lsAny.h new file mode 100644 index 00000000000..3335aa86dc6 --- /dev/null +++ b/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/lsAny.h @@ -0,0 +1,159 @@ +#pragma once + +#include "LibLsp/JsonRpc/serializer.h" +#include <string> +#include "LibLsp/JsonRpc/message.h" +namespace lsp +{ + struct Any + { + //! Type of JSON value + enum Type { + kUnKnown=-1, + kNullType = 0, //!< null + kFalseType = 1, //!< false + kTrueType = 2, //!< true + kObjectType = 3, //!< object + kArrayType = 4, //!< array + kStringType = 5, //!< string + kNumberType = 6 //!< number + }; + + + + template <typename T> + bool Get(T& value); + + template <typename T> + void Set(T& value); + + int GuessType(); + int GetType(); + + void Set(std::unique_ptr<LspMessage> value); + + void SetJsonString(std::string&& _data, Type _type); + + void SetJsonString(const std::string& _data, Type _type); + + const std::string& Data()const + { + return data; + } + + void swap(Any& arg) noexcept; + + /* + *Example for GetFromMap + struct A{ + std::string visitor; + bool verbose; + } + REFLECT_MAP_TO_STRUCT(A,visitor,verbose) + + std::string data = "{\"visitor\":\"default\",\"verbose\":\"true\"}; + lsp:Any any; + any.SetJsonString(data, static_cast<lsp::Any::Type>(-1)); + A a_object; + any.GetFromMap(a_object); + */ + template <typename T> + bool GetFromMap(T& value); + + + template <typename T> + bool GetForMapHelper(T& value); + bool GetForMapHelper(std::string& value); + bool GetForMapHelper(boost::optional<std::string>& value); + private: + std::unique_ptr<Reader> GetReader(); + std::unique_ptr<Writer> GetWriter() const; + void SetData(std::unique_ptr<Writer>&); + + std::string data; + int jsonType = kUnKnown; + + }; + +}; + + +extern void Reflect(Reader& visitor, lsp::Any& value); +extern void Reflect(Writer& visitor, lsp::Any& value); + +template <typename T> +void ReflectMember(std::map < std::string, lsp::Any>& visitor, const char* name, T& value) { + + auto it = visitor.find(name); + if (it != visitor.end()) + { + it->second.GetForMapHelper(value); + } +} +template <typename T> +void ReflectMember(std::map < std::string, std::string>& visitor, const char* name, T& value) { + + auto it = visitor.find(name); + if (it != visitor.end()) + { + lsp::Any any; + any.SetJsonString(it->second, static_cast<lsp::Any::Type>(-1)); + any.Get(value); + } +} + +#define REFLECT_MAP_TO_STRUCT(type, ...) \ + template <typename TVisitor> \ + void ReflectMap(TVisitor& visitor, type& value) { \ + MACRO_MAP(_MAPPABLE_REFLECT_MEMBER, __VA_ARGS__) \ + } + + +namespace lsp +{ + template <typename T> + bool Any::Get(T& value) + { + const auto visitor = GetReader(); + Reflect(*visitor, value); + return true; + } + + template <typename T> + void Any::Set(T& value) + { + auto visitor = GetWriter(); + Reflect(*visitor, value); + SetData(visitor); + } + + template <typename T> + bool Any::GetFromMap(T& value) + { + const auto visitor = GetReader(); + std::map < std::string, lsp::Any> _temp; + Reflect(*visitor, _temp); + ReflectMap(_temp, value); + return true; + } + + template <typename T> + bool Any::GetForMapHelper(T& value) + { + jsonType = GetType(); + if (jsonType == kStringType) + { + auto copy = data; + copy.erase(copy.find_last_not_of('"') + 1); + copy.erase(0, copy.find_first_not_of('"')); + lsp::Any any; + any.SetJsonString(copy, kUnKnown); + any.Get(value); + } + else + { + Get(value); + } + return true; + } +} diff --git a/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/lsCodeAction.h b/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/lsCodeAction.h new file mode 100644 index 00000000000..06a14f15405 --- /dev/null +++ b/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/lsCodeAction.h @@ -0,0 +1,58 @@ +#pragma once + +#include "LibLsp/JsonRpc/serializer.h" + + + +#include <string> +#include <vector> +#include "lsPosition.h" +#include "lsWorkspaceEdit.h" +#include "lsp_diagnostic.h" +#include "lsCommand.h" + +struct CodeAction +{ + /** + * A short, human-readable, title for this code action. + */ + + std::string title; + + /** + * The kind of the code action. + * + * Used to filter code actions. + */ + boost::optional < std::string> kind; + + /** + * The diagnostics that this code action resolves. + */ + boost::optional < std::vector<lsDiagnostic>> diagnostics; + + /** + * The workspace edit this code action performs. + */ + boost::optional < lsWorkspaceEdit >edit; + + /** + * A command this code action executes. If a code action + * provides a edit and a command, first the edit is + * executed and then the command. + */ + boost::optional< lsCommandWithAny > command; + + MAKE_SWAP_METHOD(CodeAction, title, kind, diagnostics, edit, command) +}; +MAKE_REFLECT_STRUCT(CodeAction, title, kind, diagnostics, edit, command) +struct TextDocumentCodeAction + +{ + + typedef std::pair<boost::optional<lsCommandWithAny>, boost::optional<CodeAction> > Either; + +}; + + +extern void Reflect(Reader& visitor, TextDocumentCodeAction::Either& value);
\ No newline at end of file diff --git a/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/lsCommand.h b/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/lsCommand.h new file mode 100644 index 00000000000..94307f1479f --- /dev/null +++ b/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/lsCommand.h @@ -0,0 +1,44 @@ +#pragma once + +#include "LibLsp/JsonRpc/serializer.h" + + + +#include <string> +#include <vector> +#include "lsAny.h" +// +//Represents a reference to a command.Provides a title which will be used to represent a command in the UI. +//Commands are identified by a string identifier. +//The recommended way to handle commands is to implement their execution on the server side +//if the clientand server provides the corresponding capabilities.Alternatively the tool +//extension code could handle the command.The protocol currently doesn¡¯t specify a set of well - known commands. +template <typename AnyArray> +struct lsCommand { + // Title of the command (ie, 'save') + std::string title; + // Actual command identifier. + std::string command; + // Arguments to run the command with. + // **NOTE** This must be serialized as an array. Use + // MAKE_REFLECT_STRUCT_WRITER_AS_ARRAY. + boost::optional<AnyArray> arguments; + + void swap(lsCommand<AnyArray>& arg) noexcept + { + title.swap(arg.title); + command.swap(arg.command); + arguments.swap(arg.arguments); + } +}; +template <typename TVisitor, typename T> +void Reflect(TVisitor& visitor, lsCommand<T>& value) { + REFLECT_MEMBER_START(); + REFLECT_MEMBER(title); + REFLECT_MEMBER(command); + REFLECT_MEMBER(arguments); + REFLECT_MEMBER_END(); +} + + +using lsCommandWithAny = lsCommand< std::vector<lsp::Any>>; diff --git a/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/lsDocumentUri.h b/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/lsDocumentUri.h new file mode 100644 index 00000000000..5d24f59e3a3 --- /dev/null +++ b/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/lsDocumentUri.h @@ -0,0 +1,26 @@ +#pragma once +#include "LibLsp/JsonRpc/serializer.h" +#include <string> +struct lsDocumentUri { + static lsDocumentUri FromPath(const AbsolutePath& path); + + lsDocumentUri(); + + lsDocumentUri(const AbsolutePath& path); + lsDocumentUri(const lsDocumentUri& other);; + bool operator==(const lsDocumentUri& other) const; + bool operator==(const std::string& other) const; + void SetPath(const AbsolutePath& path); + std::string GetRawPath() const; + AbsolutePath GetAbsolutePath() const; + + + std::string raw_uri_; + void swap(lsDocumentUri& arg) noexcept + { + raw_uri_.swap(arg.raw_uri_); + } +}; +extern void Reflect(Writer& visitor, lsDocumentUri& value); +extern void Reflect(Reader& visitor, lsDocumentUri& value); +extern std::string make_file_scheme_uri(const std::string& absolute_path); diff --git a/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/lsFormattingOptions.h b/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/lsFormattingOptions.h new file mode 100644 index 00000000000..a92df9b0772 --- /dev/null +++ b/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/lsFormattingOptions.h @@ -0,0 +1,43 @@ +#pragma once + +#include "LibLsp/JsonRpc/serializer.h" + +struct lsFormattingOptions { + struct KeyData { + boost::optional<bool> _boolean; + boost::optional<int32_t> _integer; + boost::optional<std::string> _string; + }; + + // Size of a tab in spaces. + int tabSize =4; + // Prefer spaces over tabs. + bool insertSpaces = true; + + /** + * Trim trailing whitespace on a line. + * + * @since 3.15.0 + */ + boost::optional<bool> trimTrailingWhitespace; + + /** + * Insert a newline character at the end of the file if one does not exist. + * + * @since 3.15.0 + */ + boost::optional<bool> insertFinalNewline; + + /** + * Trim all newlines after the final newline at the end of the file. + * + * @since 3.15.0 + */ + boost::optional<bool> trimFinalNewlines; + boost::optional<KeyData> key; + MAKE_SWAP_METHOD(lsFormattingOptions, tabSize, insertSpaces, trimTrailingWhitespace, insertFinalNewline, trimFinalNewlines, key) +}; +MAKE_REFLECT_STRUCT(lsFormattingOptions, tabSize, insertSpaces, trimTrailingWhitespace, insertFinalNewline, trimFinalNewlines, key); + +extern void Reflect(Reader& visitor, lsFormattingOptions::KeyData& value); +extern void Reflect(Writer& visitor, lsFormattingOptions::KeyData& value);
\ No newline at end of file diff --git a/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/lsMarkedString.h b/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/lsMarkedString.h new file mode 100644 index 00000000000..9191aa66d14 --- /dev/null +++ b/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/lsMarkedString.h @@ -0,0 +1,45 @@ +#pragma once + +#include "LibLsp/JsonRpc/serializer.h" + +#include <string> +#include <vector> + + +// MarkedString can be used to render human readable text. It is either a +// markdown string or a code-block that provides a language and a code snippet. +// The language identifier is sematically equal to the optional language +// identifier in fenced code blocks in GitHub issues. See +// https://help.github.com/articles/creating-and-highlighting-code-blocks/#syntax-highlighting +// +// The pair of a language and a value is an equivalent to markdown: +// ```${language} +// ${value} +// ``` +// +// Note that markdown strings will be sanitized - that means html will be +// escaped. +struct lsMarkedString { + boost::optional<std::string> language; + std::string value; +}; + +struct MarkupContent { + /** + * The type of the Markup. + */ + + std::string kind; + + /** + * The content itself. + */ + + std::string value; + + MAKE_SWAP_METHOD(MarkupContent, kind, value); +}; +MAKE_REFLECT_STRUCT(MarkupContent,kind,value); + +void Reflect(Writer& visitor, lsMarkedString& value); +void Reflect(Reader& visitor, lsMarkedString& value); diff --git a/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/lsPosition.h b/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/lsPosition.h new file mode 100644 index 00000000000..8c2106e16e1 --- /dev/null +++ b/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/lsPosition.h @@ -0,0 +1,40 @@ +#pragma once + +#include "LibLsp/JsonRpc/serializer.h" + + + +#include <string> +#include <vector> + +//Position in a text document expressed as zero - based line and zero - based character offset. +//A position is between two characters like an ¡®insert¡¯ cursor in a editor.Special values like +//for example - 1 to denote the end of a line are not supported. +struct lsPosition { + lsPosition(); + lsPosition(int line, int character); + + bool operator==(const lsPosition& other) const; + bool operator<(const lsPosition& other) const; + + std::string ToString() const; + + /** + * Line position in a document (zero-based). + */ + // Note: these are 0-based. + unsigned line = 0; + /** + * Character offset on a line in a document (zero-based). Assuming that + * the line is represented as a string, the `character` value represents + * the gap between the `character` and `character + 1`. + * + * If the character value is greater than the line length it defaults back + * to the line length. + */ + unsigned character = 0; + static const lsPosition kZeroPosition; + + MAKE_SWAP_METHOD(lsPosition, line, character) +}; +MAKE_REFLECT_STRUCT(lsPosition, line, character);
\ No newline at end of file diff --git a/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/lsRange.h b/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/lsRange.h new file mode 100644 index 00000000000..6cc01e37a73 --- /dev/null +++ b/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/lsRange.h @@ -0,0 +1,32 @@ +#pragma once + +#include "LibLsp/JsonRpc/serializer.h" + + + +#include <string> +#include <vector> +#include "lsPosition.h" +//A range in a text document expressed as(zero - based) startand end positions. +//A range is comparable to a selection in an editor.Therefore the end position is exclusive. +//If you want to specify a range that contains a line including the line ending character(s) +//then use an end position denoting the start of the next line. +struct lsRange { + lsRange(); + lsRange(lsPosition start, lsPosition end); + + bool operator==(const lsRange& other) const; + bool operator<(const lsRange& other) const; + /** + * The range's start position. + */ + lsPosition start; + /** + * The range's end position. + */ + lsPosition end; + std::string ToString()const; + MAKE_SWAP_METHOD(lsRange, start, end) +}; + +MAKE_REFLECT_STRUCT(lsRange, start, end)
\ No newline at end of file diff --git a/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/lsResponseError.h b/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/lsResponseError.h new file mode 100644 index 00000000000..6146d6188f6 --- /dev/null +++ b/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/lsResponseError.h @@ -0,0 +1,117 @@ +#pragma once + +#include "LibLsp/JsonRpc/serializer.h" +#include <sstream> +#include "LibLsp/lsp/lsAny.h" + +enum class lsErrorCodes:int32_t { + // Defined by JSON RPC + ParseError = -32700, + InvalidRequest = -32600, + MethodNotFound = -32601, + InvalidParams = -32602, + InternalError = -32603, + + /** + * This is the start range of JSON RPC reserved error codes. + * It doesn't denote a real error code. No LSP error codes should + * be defined between the start and end range. For backwards + * compatibility the `ServerNotInitialized` and the `UnknownErrorCode` + * are left in the range. + * + * @since 3.16.0 + */ + jsonrpcReservedErrorRangeStart = -32099, + /** @deprecated use jsonrpcReservedErrorRangeStart */ + serverErrorStart = jsonrpcReservedErrorRangeStart, + + /** + * This is the start range of JSON RPC reserved error codes. + * It doesn't denote a real error code. + * + * @since 3.16.0 + */ + jsonrpcReservedErrorRangeEnd = -32000, + /** @deprecated use jsonrpcReservedErrorRangeEnd */ + serverErrorEnd = jsonrpcReservedErrorRangeEnd, + + /** + * Error code indicating that a server received a notification or + * request before the server has received the `initialize` request. + */ + ServerNotInitialized = -32002, + UnknownErrorCode = -32001, + + /** + * This is the start range of LSP reserved error codes. + * It doesn't denote a real error code. + * + * @since 3.16.0 + */ + lspReservedErrorRangeStart= -32899, + + /** + * The server cancelled the request. This error code should + * only be used for requests that explicitly support being + * server cancellable. + * + * @since 3.17.0 + */ + ServerCancelled = -32802, + + /** + * The server detected that the content of a document got + * modified outside normal conditions. A server should + * NOT send this error code if it detects a content change + * in it unprocessed messages. The result even computed + * on an older state might still be useful for the client. + * + * If a client decides that a result is not of any use anymore + * the client should cancel the request. + */ + ContentModified = -32801, + + /** + * The client has canceled a request and a server as detected + * the cancel. + */ + RequestCancelled = -32800, + + /** + * This is the end range of LSP reserved error codes. + * It doesn't denote a real error code. + * + * @since 3.16.0 + */ + lspReservedErrorRangeEnd = -32800, + + + +}; +MAKE_REFLECT_TYPE_PROXY(lsErrorCodes); +struct lsResponseError { + lsResponseError(): code(lsErrorCodes::UnknownErrorCode) + { + } + + /** + * A number indicating the error type that occurred. + */ + lsErrorCodes code; + // Short description. + /** + * A string providing a short description of the error. + */ + std::string message; + + /** + * A primitive or structured value that contains additional + * information about the error. Can be omitted. + */ + boost::optional<lsp::Any> data; + std::string ToString(); + void Write(Writer& visitor); + + MAKE_SWAP_METHOD(lsResponseError, code, message, data) +}; +MAKE_REFLECT_STRUCT(lsResponseError, code, message, data)
\ No newline at end of file diff --git a/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/lsTextDocumentEdit.h b/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/lsTextDocumentEdit.h new file mode 100644 index 00000000000..0bab8bc3d8d --- /dev/null +++ b/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/lsTextDocumentEdit.h @@ -0,0 +1,24 @@ +#pragma once + +#include "LibLsp/JsonRpc/serializer.h" +#include <vector> +#include "LibLsp/JsonRpc/message.h" +#include "lsVersionedTextDocumentIdentifier.h" +#include "lsTextEdit.h" + + +struct lsTextDocumentEdit { + // The text document to change. + lsVersionedTextDocumentIdentifier textDocument; + + /** + * The edits to be applied. + * + * @since 3.16.0 - support for AnnotatedTextEdit. This is guarded by the + * client capability `workspace.workspaceEdit.changeAnnotationSupport` + */ + // The edits to be applied. + std::vector< lsAnnotatedTextEdit > edits; + MAKE_SWAP_METHOD(lsTextDocumentEdit, textDocument, edits); +}; +MAKE_REFLECT_STRUCT(lsTextDocumentEdit, textDocument, edits);
\ No newline at end of file diff --git a/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/lsTextDocumentIdentifier.h b/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/lsTextDocumentIdentifier.h new file mode 100644 index 00000000000..bb316eae5a4 --- /dev/null +++ b/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/lsTextDocumentIdentifier.h @@ -0,0 +1,14 @@ +#pragma once + +#include "LibLsp/JsonRpc/serializer.h" +#include "lsDocumentUri.h" +//Text documents are identified using a URI.On the protocol level, +//URIs are passed as strings.The corresponding JSON structure looks like this: +struct lsTextDocumentIdentifier { + /** + * The text document's URI. + */ + lsDocumentUri uri; + MAKE_SWAP_METHOD(lsTextDocumentIdentifier, uri) +}; +MAKE_REFLECT_STRUCT(lsTextDocumentIdentifier, uri)
\ No newline at end of file diff --git a/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/lsTextDocumentItem.h b/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/lsTextDocumentItem.h new file mode 100644 index 00000000000..4d9b4ccc9f7 --- /dev/null +++ b/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/lsTextDocumentItem.h @@ -0,0 +1,26 @@ +#pragma once + +#include "LibLsp/JsonRpc/serializer.h" +#include <string> +#include <vector> +#include "lsDocumentUri.h" + +//An item to transfer a text document from the client to the server. +struct lsTextDocumentItem { + // The text document's URI. + lsDocumentUri uri; + + // The text document's language identifier. + std::string languageId; + + // The version number of this document (it will strictly increase after each + // change, including undo/redo). + int version = 0; + + // The content of the opened text document. + std::string text; + + MAKE_SWAP_METHOD(lsTextDocumentItem, uri, languageId, version, text) +}; + +MAKE_REFLECT_STRUCT(lsTextDocumentItem, uri, languageId, version, text)
\ No newline at end of file diff --git a/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/lsTextDocumentPositionParams.h b/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/lsTextDocumentPositionParams.h new file mode 100644 index 00000000000..52d291351e7 --- /dev/null +++ b/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/lsTextDocumentPositionParams.h @@ -0,0 +1,26 @@ +#pragma once + +#include "LibLsp/JsonRpc/message.h" + +#include "lsTextDocumentIdentifier.h" +#include "lsPosition.h" + +/** + * A parameter literal used in requests to pass a text document and a position inside that document. + */ +struct lsTextDocumentPositionParams { + // The text document. + lsTextDocumentIdentifier textDocument; + + // The position inside the text document. + lsPosition position; + + /** + * Legacy property to support protocol version 1.0 requests. + */ + boost::optional<lsDocumentUri> uri; + + MAKE_SWAP_METHOD(lsTextDocumentPositionParams, textDocument, position, uri); + +}; +MAKE_REFLECT_STRUCT(lsTextDocumentPositionParams, textDocument, position, uri); diff --git a/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/lsTextEdit.h b/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/lsTextEdit.h new file mode 100644 index 00000000000..8785e0dcbc3 --- /dev/null +++ b/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/lsTextEdit.h @@ -0,0 +1,87 @@ +#pragma once + +#include "LibLsp/JsonRpc/serializer.h" + + + +#include <string> +#include "lsRange.h" + + +//Since 3.16.0 there is also the concept of an annotated text edit which supports to add an annotation to a text edit. +//The annotation can add information describing the change to the text edit. +/** + * Additional information that describes document changes. + * + * @since 3.16.0 + */ +struct lsChangeAnnotation +{ + /** + * A human-readable string describing the actual change. The string + * is rendered prominent in the user interface. + */ + std::string label; + + /** + * A flag which indicates that user confirmation is needed + * before applying the change. + */ + boost::optional<bool> needsConfirmation; + + /** + * A human-readable string which is rendered less prominent in + * the user interface. + */ + boost::optional < std::string > description; + MAKE_REFLECT_STRUCT(lsChangeAnnotation, label, needsConfirmation, description) +}; +MAKE_REFLECT_STRUCT(lsChangeAnnotation, label, needsConfirmation, description) + + +//Usually clients provide options to group the changes along the annotations they are associated with. +//To support this in the protocol an edit or resource operation refers to a change annotation +//using an identifier and not the change annotation literal directly.This allows servers to use +//the identical annotation across multiple edits or resource operations which then allows clients +//to group the operations under that change annotation.The actual change annotations together with +//their identifers are managed by the workspace edit via the new property changeAnnotations. + + + +/** + * An identifier referring to a change annotation managed by a workspace + * edit. + * + * @since 3.16.0. + */ +using lsChangeAnnotationIdentifier = std::string; +/** + * A special text edit with an additional change annotation. + * + * @since 3.16.0. + */ + + +//A textual edit applicable to a text document. +struct lsTextEdit { + // The range of the text document to be manipulated. To insert + // text into a document create a range where start === end. + lsRange range; + + // The string to be inserted. For delete operations use an + // empty string. + std::string newText; + + /** + * The actual annotation identifier. + */ + boost::optional<lsChangeAnnotationIdentifier> annotationId; + + + bool operator==(const lsTextEdit& that); + std::string ToString() const; + MAKE_SWAP_METHOD(lsTextEdit, range, newText, annotationId) +}; +MAKE_REFLECT_STRUCT(lsTextEdit, range, newText, annotationId) + +using lsAnnotatedTextEdit = lsTextEdit; diff --git a/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/lsVersionedTextDocumentIdentifier.h b/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/lsVersionedTextDocumentIdentifier.h new file mode 100644 index 00000000000..8a858053b14 --- /dev/null +++ b/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/lsVersionedTextDocumentIdentifier.h @@ -0,0 +1,32 @@ +#pragma once + +#include "LibLsp/JsonRpc/serializer.h" + +#include "LibLsp/JsonRpc/message.h" +#include "LibLsp/lsp/lsDocumentUri.h" +#include "LibLsp/lsp/lsTextDocumentIdentifier.h" + +struct lsVersionedTextDocumentIdentifier +{ + lsDocumentUri uri; + // The version number of this document. number | null + boost::optional<int> version; + + lsTextDocumentIdentifier AsTextDocumentIdentifier() const; + + MAKE_SWAP_METHOD(lsVersionedTextDocumentIdentifier, uri, version) +}; +MAKE_REFLECT_STRUCT(lsVersionedTextDocumentIdentifier, uri, version) + +/** + * The version number of this document. If an optional versioned text document + * identifier is sent from the server to the client and the file is not + * open in the editor (the server has not received an open notification + * before) the server can send `null` to indicate that the version is + * known and the content on disk is the master (as specified with document + * content ownership). + * + * The version number of a document will increase after each change, + * including undo/redo. The number doesn't need to be consecutive. + */ +using lsOptionalVersionedTextDocumentIdentifier = lsVersionedTextDocumentIdentifier;
\ No newline at end of file diff --git a/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/lsWorkspaceEdit.h b/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/lsWorkspaceEdit.h new file mode 100644 index 00000000000..c7fb73930a3 --- /dev/null +++ b/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/lsWorkspaceEdit.h @@ -0,0 +1,57 @@ +#pragma once + +#include "LibLsp/JsonRpc/serializer.h" +#include <vector> +#include "lsTextDocumentEdit.h" +#include "LibLsp/lsp/ResourceOperation.h" +#include "lsAny.h" + +//A workspace edit represents changes to many resources managed in the workspace. +//The edit should either provide changes or documentChanges. +//If the client can handle versioned document edits and if documentChanges are present, the latter are preferred over changes. + +//Since version 3.13.0 a workspace edit can contain resource operations(create, delete or rename files and folders) as well. +//If resource operations are present clients need to execute the operations in the order in which they are provided. +//So a workspace edit for example can consist of the following two changes : (1) create file a.txt and (2) a text document edit which insert text into file a. +//txt.An invalid sequence(e.g. (1) delete file a.txt and (2) insert text into file a.txt) will cause failure of the operation. +//How the client recovers from the failure is described by the client capability : workspace.workspaceEdit.failureHandling + + + +struct lsChangeAnnotations +{ + lsChangeAnnotation id; + MAKE_SWAP_METHOD(lsChangeAnnotations, id) +}; +MAKE_REFLECT_STRUCT(lsChangeAnnotations, id) +struct lsWorkspaceEdit { + // Holds changes to existing resources. + // changes ? : { [uri:string]: TextEdit[]; }; + // std::unordered_map<lsDocumentUri, std::vector<lsTextEdit>> changes; + + // An array of `TextDocumentEdit`s to express changes to specific a specific + // version of a text document. Whether a client supports versioned document + // edits is expressed via `WorkspaceClientCapabilites.versionedWorkspaceEdit`. + // + boost::optional< std::map<std::string, std::vector<lsTextEdit> > > changes; + typedef std::pair < boost::optional<lsTextDocumentEdit>, boost::optional<lsp::Any> > Either; + + boost::optional < std::vector< Either > > documentChanges; + /** + * A map of change annotations that can be referenced in + * `AnnotatedTextEdit`s or create, rename and delete file / folder + * operations. + * + * Whether clients honor this property depends on the client capability + * `workspace.changeAnnotationSupport`. + * + * @since 3.16.0 + */ + boost::optional< lsChangeAnnotations > changeAnnotations; + + MAKE_SWAP_METHOD(lsWorkspaceEdit, changes, documentChanges, changeAnnotations) +}; +MAKE_REFLECT_STRUCT(lsWorkspaceEdit, changes, documentChanges, changeAnnotations) + +extern void Reflect(Reader& visitor, lsWorkspaceEdit::Either& value); + diff --git a/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/lsp.cpp b/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/lsp.cpp new file mode 100644 index 00000000000..81bf34ba3a4 --- /dev/null +++ b/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/lsp.cpp @@ -0,0 +1,1087 @@ + + +#include "lru_cache.h" + + +#include <rapidjson/writer.h> + + +#include <stdio.h> +#include <iostream> +#include "location_type.h" +#include "out_list.h" +#include "lsTextDocumentIdentifier.h" +#include "lsVersionedTextDocumentIdentifier.h" +#include "lsResponseError.h" +#include "lsPosition.h" +#include "lsTextEdit.h" +#include "lsMarkedString.h" +#include "lsWorkspaceEdit.h" +#include "textDocument/code_action.h" +#include "textDocument/document_symbol.h" +#include "extention/jdtls/codeActionResult.h" + +#include "textDocument/selectionRange.h" +#include "AbsolutePath.h" + +#ifdef _WIN32 +#include <Windows.h> +#else +#include <climits> +#include <cstdlib> +#endif + +#include "Directory.h" +#include "lsFormattingOptions.h" +#include "LibLsp/JsonRpc/json.h" +#include "language/language.h" +#include "network/uri/uri_builder.hpp" +#include "lsp_completion.h" +#include "utils.h" +#include "client/registerCapability.h" +#include <boost/uuid/uuid.hpp> +#include <boost/uuid/uuid_io.hpp> +#include <boost/uuid/uuid_generators.hpp> +// namespace + + + +lsTextDocumentIdentifier +lsVersionedTextDocumentIdentifier::AsTextDocumentIdentifier() const { + lsTextDocumentIdentifier result; + result.uri = uri; + return result; +} + + +lsPosition::lsPosition() {} +lsPosition::lsPosition(int line, int character) + : line(line), character(character) {} + +bool lsPosition::operator==(const lsPosition& other) const { + return line == other.line && character == other.character; +} + +bool lsPosition::operator<(const lsPosition& other) const { + return line != other.line ? line < other.line : character < other.character; +} + +std::string lsPosition::ToString() const { + return std::to_string(line) + ":" + std::to_string(character); +} +const lsPosition lsPosition::kZeroPosition = lsPosition(); + +lsRange::lsRange() {} +lsRange::lsRange(lsPosition start, lsPosition end) : start(start), end(end) {} + +bool lsRange::operator==(const lsRange& o) const { + return start == o.start && end == o.end; +} + +bool lsRange::operator<(const lsRange& o) const { + return !(start == o.start) ? start < o.start : end < o.end; +} + +std::string lsRange::ToString() const +{ + std::stringstream ss; + ss << "start:" << start.ToString() << std::endl; + ss << "end" << end.ToString() << std::endl; + return ss.str(); +} + +lsLocation::lsLocation() {} +lsLocation::lsLocation(lsDocumentUri uri, lsRange range) + : uri(uri), range(range) {} + +bool lsLocation::operator==(const lsLocation& o) const { + return uri == o.uri && range == o.range; +} + +bool lsLocation::operator<(const lsLocation& o) const { + return std::make_tuple(uri.raw_uri_, range) < + std::make_tuple(o.uri.raw_uri_, o.range); +} + +bool lsTextEdit::operator==(const lsTextEdit& that) { + return range == that.range && newText == that.newText; +} + +std::string lsTextEdit::ToString() const +{ + std::stringstream ss; + ss << "Range:" << range.ToString() << std::endl; + ss << "newText:" << newText << std::endl; + return ss.str(); +} + +void Reflect(Writer& visitor, lsMarkedString& value) { + // If there is a language, emit a `{language:string, value:string}` object. If + // not, emit a string. + if (value.language) { + REFLECT_MEMBER_START(); + REFLECT_MEMBER(language); + REFLECT_MEMBER(value); + REFLECT_MEMBER_END(); + } else { + Reflect(visitor, value.value); + } +} + +void Reflect(Reader& visitor, lsMarkedString& value) +{ + REFLECT_MEMBER_START(); + REFLECT_MEMBER(language); + REFLECT_MEMBER(value); + REFLECT_MEMBER_END(); +} + + void Reflect(Reader& visitor, LocationListEither::Either& value) +{ + if(!visitor.IsArray()) + { + throw std::invalid_argument("Rsp_LocationListEither::Either& value is not array"); + } + auto data = ((JsonReader&)visitor).m_->GetArray(); + if (data.Size() && data[0].HasMember("originSelectionRange")) + { + Reflect(visitor, value.second); + } + else { + Reflect(visitor, value.first); + } + +} + + void Reflect(Writer& visitor, LocationListEither::Either& value) +{ + if (value.first) + { + Reflect(visitor, value.first.value()); + } + else if (value.second) + { + Reflect(visitor, value.second.value()); + } +} + + +void Reflect(Reader& visitor, TextDocumentCodeAction::Either& value) +{ + + + if(visitor.HasMember("command")) + { + if(visitor["command"]->IsString()) + { + Reflect(visitor, value.first); + } + else + { + Reflect(visitor, value.second); + } + } + else + { + if (visitor.HasMember("diagnostics") || visitor.HasMember("edit")) + { + Reflect(visitor, value.second); + } + else + { + Reflect(visitor, value.first); + } + } + +} + + +void Reflect(Reader& visitor, lsWorkspaceEdit::Either& value) +{ + + + if(visitor.HasMember("textDocument")) + { + Reflect(visitor, value.first); + } + else + { + Reflect(visitor, value.second); + } +} +ResourceOperation* GetResourceOperation(lsp::Any& lspAny) +{ + rapidjson::Document document; + auto& data = lspAny.Data(); + document.Parse(data.c_str(), data.length()); + if (document.HasParseError()) { + // ��ʾ + return nullptr; + } + auto find = document.FindMember("kind"); + + JsonReader visitor{ &document }; + try + { + if (find->value == "create") + { + auto ptr = std::make_unique<lsCreateFile>(); + auto temp = ptr.get(); + Reflect(visitor, *temp); + return ptr.release(); + } + else if (find->value == "rename") + { + auto ptr = std::make_unique<lsRenameFile>(); + auto temp = ptr.get(); + Reflect(visitor, *temp); + return ptr.release(); + } + else if (find->value == "delete") + { + + auto ptr = std::make_unique<lsDeleteFile>(); + auto temp = ptr.get(); + Reflect(visitor, *temp); + return ptr.release(); + } + } + catch (std::exception&) + { + + } + return nullptr; +} + + void Reflect(Writer& visitor, ResourceOperation* value) +{ + + if(!value) + { + throw std::invalid_argument("ResourceOperation value is nullptr"); + } + if (value->kind == "create") + { + auto temp = (lsCreateFile*)value; + Reflect(visitor, *temp); + } + else if (value->kind == "rename") + { + auto temp = (lsRenameFile*)value; + Reflect(visitor, *temp); + } + else if (value->kind == "delete") + { + + auto temp = (lsDeleteFile*)value; + Reflect(visitor, *temp); + } + +} + +int lsp::Any::GuessType() +{ + if (!data.empty()) + { + if (data == "null") + { + jsonType = rapidjson::kNullType; + } + else if (data == "true") + { + jsonType = rapidjson::kTrueType; + } + else if(data == "false") + { + jsonType = rapidjson::kFalseType; + } + else if (data[0] == '{') + { + jsonType = rapidjson::kObjectType; + } + else if (data[0] == '[') + { + if (data.size() >= 2 && data[1] == '{') + jsonType = rapidjson::kStringType; + else + jsonType = rapidjson::kArrayType; + } + else if (data[0] == '"') + { + jsonType = rapidjson::kStringType; + } + else + { + jsonType = rapidjson::kNumberType; + } + } + else + { + if (jsonType != kUnKnown) + return jsonType; + jsonType = rapidjson::kNullType; + } + return jsonType; +} + +int lsp::Any::GetType() +{ + if (jsonType == Type::kUnKnown) + { + if (data.empty()) + { + jsonType = rapidjson::kNullType; + return jsonType; + } + rapidjson::Document document; + document.Parse(data.c_str(), data.length()); + if (document.HasParseError()) + { + // ��ʾ + return jsonType; + } + jsonType = document.GetType(); + } + return jsonType; +} + +void lsp::Any::Set(std::unique_ptr<LspMessage> value) +{ + if (value) + { + jsonType = rapidjson::Type::kObjectType; + data = value->ToJson(); + } + else + { + assert(false); + } +} + +void lsp::Any::SetJsonString(std::string&& _data, Type _type) +{ + jsonType = _type; + data.swap(_data); + GetType(); +} + +void lsp::Any::SetJsonString(const std::string& _data, Type _type) +{ + jsonType = _type; + data = (_data); + GetType(); +} + +void lsp::Any::swap(Any& arg) noexcept +{ + data.swap(arg.data); + const int temp = jsonType; + jsonType = arg.jsonType; + arg.jsonType = temp; +} + +class JsonReaderForAny : public JsonReader +{ +public: + JsonReaderForAny() + : JsonReader(&document) + { + } + rapidjson::Document document; +}; + +bool lsp::Any::GetForMapHelper(std::string& value) +{ + return Get(value); +} + +bool lsp::Any::GetForMapHelper(boost::optional<std::string>& value) +{ + return Get(value); +} + +std::unique_ptr<Reader> lsp::Any::GetReader() +{ + auto reader = new JsonReaderForAny(); + std::unique_ptr<Reader> ret(reader); + reader->document.Parse(data.c_str(), data.length()); + if (reader->document.HasParseError()) + { + return {}; + } + if (jsonType == kUnKnown) + { + jsonType = reader->document.GetType(); + } + return (ret); +} + +class JsonWriterForAny : public JsonWriter +{ +public: + rapidjson::StringBuffer output; + rapidjson::Writer<rapidjson::StringBuffer> writer; + JsonWriterForAny():JsonWriter(&writer), writer(output) + { + + } +}; + +std::unique_ptr<Writer> lsp::Any::GetWriter() const +{ + return std::make_unique<JsonWriterForAny>(); +} + +void lsp::Any::SetData(std::unique_ptr<Writer>& writer) +{ + auto _temp = static_cast<JsonWriterForAny*>(writer.get()); + data = _temp->output.GetString(); + GuessType(); +} + +namespace +{ +#if 0 + rapidjson::Type convert(lsp::Any::Type type) + { + switch (type) + { + case lsp::Any::Type::kNullType: + return rapidjson::Type::kNullType; + case lsp::Any::Type::kFalseType: + return rapidjson::Type::kFalseType; + case lsp::Any::Type::kTrueType: + return rapidjson::Type::kTrueType; + case lsp::Any::Type::kObjectType: + return rapidjson::Type::kObjectType; + case lsp::Any::Type::kArrayType: + return rapidjson::Type::kArrayType; + case lsp::Any::Type::kStringType: + return rapidjson::Type::kStringType; + case lsp::Any::Type::kNumberType: + return rapidjson::Type::kNumberType; + default: + return rapidjson::Type::kNullType; + } + } +#endif + lsp::Any::Type convert(rapidjson::Type type) + { + switch (type) + { + case rapidjson::Type::kNullType: + return lsp::Any::Type::kNullType; + case rapidjson::Type::kFalseType: + return lsp::Any::Type::kFalseType; + case rapidjson::Type::kTrueType: + return lsp::Any::Type::kTrueType; + case rapidjson::Type::kObjectType: + return lsp::Any::Type::kObjectType; + case rapidjson::Type::kArrayType: + return lsp::Any::Type::kArrayType; + case rapidjson::Type::kStringType: + return lsp::Any::Type::kStringType; + case rapidjson::Type::kNumberType: + return lsp::Any::Type::kNumberType; + default: + return lsp::Any::Type::kNullType; + } + } +} + +void Reflect(Reader& visitor, lsp::Any& value) +{ + + //if (visitor.IsNull()) { + // visitor.GetNull(); + // value.SetJsonString("", rapidjson::Type::kNullType); + // return; + //}else + //{ + // + //} + JsonReader& json_reader = reinterpret_cast<JsonReader&>(visitor); + value.SetJsonString(visitor.ToString(), convert(json_reader.m_->GetType())); +} + void Reflect(Writer& visitor, lsp::Any& value) + { + JsonWriter& json_writer = reinterpret_cast<JsonWriter&>(visitor); + json_writer.m_->RawValue( value.Data().data(),value.Data().size(),static_cast<rapidjson::Type>(value.GetType())); + + } + void Reflect(Reader& visitor, lsFormattingOptions::KeyData& value) +{ + if (visitor.IsBool()) + { + Reflect(visitor, value._boolean); + } + else if (visitor.IsInt() || visitor.IsInt64() || visitor.IsUint64()) + { + Reflect(visitor, value._integer); + } + else if(visitor.IsString()) + { + Reflect(visitor, value._string); + } +} + void Reflect(Writer& visitor, lsFormattingOptions::KeyData& value) +{ + if (value._boolean.has_value()) + { + Reflect(visitor, value._boolean); + } + else if (value._integer.has_value()) + { + Reflect(visitor, value._integer); + } + else if (value._string.has_value()) + { + Reflect(visitor, value._string); + } +} + +lsCreateFile::lsCreateFile() +{ + kind = "create"; +} + +lsDeleteFile::lsDeleteFile() +{ + kind = "delete"; +} + +lsRenameFile::lsRenameFile() +{ + kind = "rename"; +} + + +void Reflect(Reader& visitor, boost::optional< SelectionRange* >& value) +{ + if (visitor.IsNull()) { + visitor.GetNull(); + return; + } + + SelectionRange* entry_value = nullptr; + + + std::unique_ptr<SelectionRange> ptr = std::make_unique<SelectionRange>(); + SelectionRange* temp = ptr.get(); + Reflect(visitor, *temp); + + entry_value = ptr.release(); + value = (entry_value); + +} +void Reflect(Writer& visitor, SelectionRange* value) +{ + + if (!value) + { + throw std::invalid_argument("ResourceOperation value is nullptr"); + } + + Reflect(visitor, *value); + + +} + + std::string make_file_scheme_uri(const std::string& absolute_path) +{ + network::uri_builder builder; + builder.scheme("file"); + builder.host(""); + builder.path(absolute_path); + return builder.uri().string(); + //// lsDocumentUri uri; + //// uri.SetPath(absolute_path); + /// return uri.raw_uri_; +} + +// static +AbsolutePath AbsolutePath::BuildDoNotUse(const std::string& path) { + AbsolutePath p; + p.path = std::string(path); + return p; +} + + +AbsolutePath::AbsolutePath() {} + + + +AbsolutePath::operator std::string() const { + return path; +} + +bool AbsolutePath::operator==(const AbsolutePath& rhs) const { + return path == rhs.path; +} + +bool AbsolutePath::operator!=(const AbsolutePath& rhs) const { + return path != rhs.path; +} + +bool AbsolutePath::operator<(const AbsolutePath& rhs) const +{ + return path < rhs.path; +} + +bool AbsolutePath::operator>(const AbsolutePath& rhs) const +{ + return path > rhs.path; +} + +void Reflect(Reader& visitor, AbsolutePath& value) { + value.path = visitor.GetString(); +} +void Reflect(Writer& visitor, AbsolutePath& value) { + visitor.String(value.path.c_str(), value.path.length()); +} + +std::ostream& operator<<(std::ostream& out, const AbsolutePath& path) { + out << path.path; + return out; +} + +lsDocumentUri lsDocumentUri::FromPath(const AbsolutePath& path) { + lsDocumentUri result; + result.SetPath(path); + return result; +} +//void lsDocumentUri::SetPath(const AbsolutePath& path) +//{ +// raw_uri_ = make_file_scheme_uri(path.path); +//} +// +void lsDocumentUri::SetPath(const AbsolutePath& path) { + // file:///c%3A/Users/jacob/Desktop/superindex/indexer/full_tests + raw_uri_ = path; + + size_t index = raw_uri_.find(":"); + if (index == 1) { // widows drive letters must always be 1 char + raw_uri_.replace(raw_uri_.begin() + index, raw_uri_.begin() + index + 1, + "%3A"); + } + + // subset of reserved characters from the URI standard + // http://www.ecma-international.org/ecma-262/6.0/#sec-uri-syntax-and-semantics + std::string t; + t.reserve(8 + raw_uri_.size()); + + // TODO: proper fix +#if defined(_WIN32) + t += "file:///"; +#else + t += "file://"; +#endif + + // clang-format off + for (char c : raw_uri_) + switch (c) { + case ' ': t += "%20"; break; + case '#': t += "%23"; break; + case '$': t += "%24"; break; + case '&': t += "%26"; break; + case '(': t += "%28"; break; + case ')': t += "%29"; break; + case '+': t += "%2B"; break; + case ',': t += "%2C"; break; + case ';': t += "%3B"; break; + case '?': t += "%3F"; break; + case '@': t += "%40"; break; + default: t += c; break; + } + // clang-format on + raw_uri_ = std::move(t); +} + +std::string lsDocumentUri::GetRawPath() const { + + + if (raw_uri_.compare(0, 8, "file:///")) + return raw_uri_; + + + std::string ret; +#if defined(_WIN32) + size_t i = 8; +#else + size_t i = 7; +#endif + auto from_hex = [](unsigned char c) { + return c - '0' < 10 ? c - '0' : (c | 32) - 'a' + 10; + }; + for (; i < raw_uri_.size(); i++) { + if (i + 3 <= raw_uri_.size() && raw_uri_[i] == '%') { + ret.push_back(from_hex(raw_uri_[i + 1]) * 16 + from_hex(raw_uri_[i + 2])); + i += 2; + } + else + ret.push_back(raw_uri_[i] == '\\' ? '/' : raw_uri_[i]); + } + return ret; +} + +lsDocumentUri::lsDocumentUri() {} + + +lsDocumentUri::lsDocumentUri(const AbsolutePath& path) +{ + SetPath(path); +} + +lsDocumentUri::lsDocumentUri(const lsDocumentUri& other): raw_uri_(other.raw_uri_) +{ +} + +bool lsDocumentUri::operator==(const lsDocumentUri& other) const { + return raw_uri_ == other.raw_uri_; +} + +bool lsDocumentUri::operator==(const std::string& other) const +{ + return raw_uri_ == other; +} + + +AbsolutePath lsDocumentUri::GetAbsolutePath() const { + + + if (raw_uri_.find("file://") != std::string::npos){ + try + { + return lsp::NormalizePath(GetRawPath(), false /*ensure_exists*/, false); + } + catch (std::exception&) + { + return AbsolutePath("", false); + } + } + + return AbsolutePath(raw_uri_,false); + +} + +AbsolutePath::AbsolutePath(const std::string& path, bool validate) + : path(path) { + // TODO: enable validation after fixing tests. + if (validate && !lsp::IsAbsolutePath(path)) { + qualify = false; + auto temp = lsp::NormalizePath(path,false); + if(!temp.path.empty()) + { + this->path = temp.path; + } + } +} + +void Reflect(Writer& visitor, lsDocumentUri& value) { + Reflect(visitor, value.raw_uri_); +} +void Reflect(Reader& visitor, lsDocumentUri& value) { + Reflect(visitor, value.raw_uri_); + // Only record the path when we deserialize a URI, since it most likely came + // from the client. + +} + + std::string ProgressReport::ToString() const +{ + std::string info; + info += "id:" + id + "\n"; + info += "task:" + task + "\n"; + info += "subTask:" + subTask + "\n"; + info += "status:" + status + "\n"; + { + std::stringstream ss; + ss << "totalWork:" << totalWork << std::endl; + info += ss.str(); + } + { + std::stringstream ss; + ss << "workDone:" << workDone << std::endl; + info += ss.str(); + } + + { + std::stringstream ss; + ss << "complete:" << complete << std::endl; + info += ss.str(); + } + + return info; +} + +std::string EventNotification::ToString() const +{ + std::string info; + if (ClasspathUpdated == eventType) + { + info += "eventType:ClasspathUpdated\n"; + } + else if (ProjectsImported == eventType) + { + info += "eventType:ProjectsImported\n"; + } + else + { + std::ostringstream oss; + oss << std::hex << eventType << std::endl; + + info += "eventType:"; + info += oss.str(); + } + info += "data:" + data.Data() + "\n"; + return info; +} + +std::string lsp::ToString(lsCompletionItemKind _kind) +{ + switch (_kind) { + case lsCompletionItemKind::Text: + return "Text"; + case lsCompletionItemKind::Method: + return "Method"; + case lsCompletionItemKind::Function: + return ""; + case lsCompletionItemKind::Constructor: + return "Function"; + case lsCompletionItemKind::Field: + return "Field"; + case lsCompletionItemKind::Variable: + return ""; + case lsCompletionItemKind::Class: + return "Variable"; + case lsCompletionItemKind::Interface: + return "Interface"; + case lsCompletionItemKind::Module: + return "Module"; + case lsCompletionItemKind::Property: + return "Property"; + case lsCompletionItemKind::Unit: + return "Unit"; + case lsCompletionItemKind::Value: + return "Value"; + case lsCompletionItemKind::Enum: + return "Enum"; + case lsCompletionItemKind::Keyword: + return "Keyword"; + case lsCompletionItemKind::Snippet: + return "Snippet"; + case lsCompletionItemKind::Color: + return "Color"; + case lsCompletionItemKind::File: + return "File"; + case lsCompletionItemKind::Reference: + return "Reference"; + case lsCompletionItemKind::Folder: + return "Folder"; + case lsCompletionItemKind::EnumMember: + return "EnumMember"; + case lsCompletionItemKind::Constant: + return "Constant"; + case lsCompletionItemKind::Struct: + return "Struct"; + case lsCompletionItemKind::Event: + return "Event"; + case lsCompletionItemKind::Operator: + return "Operator"; + case lsCompletionItemKind::TypeParameter: + return "TypeParameter"; + default: + return "Unknown"; + } +} + +std::string lsp::ToString(lsInsertTextFormat _kind) +{ + if (_kind == lsInsertTextFormat::PlainText) + { + return "PlainText"; + } + else if (_kind == lsInsertTextFormat::Snippet) + { + return "Snippet"; + }else + { + return "Unknown"; + } +} + +const std::string& lsCompletionItem::InsertedContent() const +{ + if (textEdit) + return textEdit->newText; + if (insertText.has_value() && !insertText->empty()) + return insertText.value(); + return label; +} + +std::string lsCompletionItem::DisplayText() +{ + + if (detail) + { + + return label + " in " + detail.value(); + } + return label; +} + +std::string lsCompletionItem::ToString() + { + std::stringstream info; + info << "label : " << label << std::endl; + if(kind) + info << "kind : " << lsp::ToString(kind.value()) << std::endl; + else + info << "kind : no exist." << std::endl; + + if (detail) + info << "detail : " << detail.value() << std::endl; + else + info << "detail : no exist." << std::endl; + + if (documentation) + { + info << "documentation : " << std::endl; + if(documentation.value().first) + { + info << documentation.value().first.value(); + } + else if(documentation.value().second) + { + info << documentation.value().second.value().value; + } + } + else + info << "documentation : no exist." << std::endl; + + if (deprecated) + info << "deprecated : " << deprecated.value() << std::endl; + else + info << "deprecated : no exist." << std::endl; + + if (preselect) + info << "preselect : " << preselect.value() << std::endl; + else + info << "preselect : no exist." << std::endl; + + if (sortText) + info << "sortText : " << sortText.value() << std::endl; + else + info << "sortText : no exist." << std::endl; + + if (filterText) + info << "filterText : " << filterText.value() << std::endl; + else + info << "filterText : no exist." << std::endl; + + + if (insertText) + info << "insertText : " << insertText.value() << std::endl; + else + info << "insertText : no exist." << std::endl; + + + if (insertTextFormat) + info << "insertText : " << lsp::ToString(insertTextFormat.value()) << std::endl; + else + info << "insertTextFormat : no exist." << std::endl; + + if (textEdit) + info << "textEdit : " << textEdit.value().ToString() << std::endl; + else + info << "textEdit : no exist." << std::endl; + + + + return info.str(); + + } +namespace JDT +{ + namespace CodeActionKind { + + + /** + * Base kind for quickfix actions: 'quickfix' + */ + const char* QuickFix = "quickfix"; + + /** + * Base kind for refactoring actions: 'refactor' + */ + const char* Refactor = "refactor"; + + /** + * Base kind for refactoring extraction actions: 'refactor.extract' + * + * Example extract actions: + * + * - Extract method - Extract function - Extract variable - Extract interface + * from class - ... + */ + const char* RefactorExtract = "refactor.extract"; + + /** + * Base kind for refactoring inline actions: 'refactor.inline' + * + * Example inline actions: + * + * - Inline function - Inline variable - Inline constant - ... + */ + const char* RefactorInline = "refactor.inline"; + + /** + * Base kind for refactoring rewrite actions: 'refactor.rewrite' + * + * Example rewrite actions: + * + * - Convert JavaScript function to class - Add or remove parameter - + * Encapsulate field - Make method static - Move method to base class - ... + */ + const char* RefactorRewrite = "refactor.rewrite"; + + /** + * Base kind for source actions: `source` + * + * Source code actions apply to the entire file. + */ + const char* Source = "source"; + + /** + * Base kind for an organize imports source action: `source.organizeImports` + */ + const char* SourceOrganizeImports = "source.organizeImports"; + + const char* COMMAND_ID_APPLY_EDIT = "java.apply.workspaceEdit"; + + }; + + +} +Directory::Directory(const AbsolutePath& path) : path(path.path) { + lsp::EnsureEndsInSlash(this->path); +} + +bool Directory::operator==(const Directory& rhs) const { + return path == rhs.path; +} + +bool Directory::operator!=(const Directory& rhs) const { + return path != rhs.path; +} + + + + Registration Registration::Create(const std::string& method) +{ + Registration reg; + reg.method = method; + const boost::uuids::uuid a_uuid = boost::uuids::random_generator()(); + reg.id = to_string(a_uuid); + return reg; +} diff --git a/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/lsp_code_action.h b/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/lsp_code_action.h new file mode 100644 index 00000000000..37acc6ca61a --- /dev/null +++ b/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/lsp_code_action.h @@ -0,0 +1,64 @@ +#pragma once + + +#include "location_type.h" +#include "lsDocumentUri.h" +#include "lsTextEdit.h" +#include "lsPosition.h" + +// codeAction +struct CommandArgs { + lsDocumentUri textDocumentUri; + std::vector<lsTextEdit> edits; +}; +MAKE_REFLECT_STRUCT_WRITER_AS_ARRAY(CommandArgs, textDocumentUri, edits); +inline void Reflect(Reader& visitor, CommandArgs& value) { + int i = 0; + visitor.IterArray([&](Reader& visitor) { + switch (i++) { + case 0: + Reflect(visitor, value.textDocumentUri); + break; + case 1: + Reflect(visitor, value.edits); + break; + + } + }); +} + +// codeLens +struct lsCodeLensUserData {}; +MAKE_REFLECT_EMPTY_STRUCT(lsCodeLensUserData); + +struct lsCodeLensCommandArguments { + lsDocumentUri uri; + lsPosition position; + std::vector<lsLocation> locations; +}; + +// FIXME Don't use array in vscode-cquery +inline void Reflect(Writer& visitor, lsCodeLensCommandArguments& value) { + visitor.StartArray(3); + Reflect(visitor, value.uri); + Reflect(visitor, value.position); + Reflect(visitor, value.locations); + visitor.EndArray(); +} + +inline void Reflect(Reader& visitor, lsCodeLensCommandArguments& value) { + int i = 0; + visitor.IterArray([&](Reader& visitor) { + switch (i++) { + case 0: + Reflect(visitor, value.uri); + break; + case 1: + Reflect(visitor, value.position); + break; + case 2: + Reflect(visitor, value.locations); + break; + } + }); +} diff --git a/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/lsp_completion.h b/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/lsp_completion.h new file mode 100644 index 00000000000..250699a44ab --- /dev/null +++ b/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/lsp_completion.h @@ -0,0 +1,224 @@ +#pragma once +#include "lsTextEdit.h" +#include "lsMarkedString.h" +#include "lsCommand.h" + + +// The kind of a completion entry. +enum class lsCompletionItemKind { + Text = 1, + Method = 2, + Function = 3, + Constructor = 4, + Field = 5, + Variable = 6, + Class = 7, + Interface = 8, + Module = 9, + Property = 10, + Unit = 11, + Value = 12, + Enum = 13, + Keyword = 14, + Snippet = 15, + Color = 16, + File = 17, + Reference = 18, + Folder = 19, + EnumMember = 20, + Constant = 21, + Struct = 22, + Event = 23, + Operator = 24, + TypeParameter = 25, +}; +MAKE_REFLECT_TYPE_PROXY(lsCompletionItemKind); + + + +// Defines whether the insert text in a completion item should be interpreted as +// plain text or a snippet. +enum class lsInsertTextFormat { + // The primary text to be inserted is treated as a plain string. + PlainText = 1, + + // The primary text to be inserted is treated as a snippet. + // + // A snippet can define tab stops and placeholders with `$1`, `$2` + // and `${3:foo}`. `$0` defines the final tab stop, it defaults to + // the end of the snippet. Placeholders with equal identifiers are linked, + // that is typing in one will update others too. + // + // See also: + // https://github.com/Microsoft/vscode/blob/master/src/vs/editor/contrib/snippet/common/snippet.md + Snippet = 2 +}; +MAKE_REFLECT_TYPE_PROXY(lsInsertTextFormat); + +namespace lsp +{ + std::string ToString(lsCompletionItemKind); + std::string ToString(lsInsertTextFormat); +} +/** + * The Completion request is sent from the client to the server to compute completion items at a given cursor position. + * Completion items are presented in the IntelliSense user class. If computing complete completion items is expensive + * servers can additional provide a handler for the resolve completion item request. This request is send when a + * completion item is selected in the user class. + */ +struct lsCompletionItem { + + // The label of this completion item. By default + // also the text that is inserted when selecting + // this completion. + std::string label; + + // The kind of this completion item. Based of the kind + // an icon is chosen by the editor. + boost::optional<lsCompletionItemKind> kind ; + + // A human-readable string with additional information + // about this item, like type or symbol information. + boost::optional < std::string > detail; + + // A human-readable string that represents a doc-comment. + boost::optional< std::pair<boost::optional< std::string> , boost::optional<MarkupContent> > > documentation; + + + /** + * Indicates if this item is deprecated. + */ + boost::optional< bool >deprecated; + + + /** + * Select this item when showing. + * + * *Note* that only one completion item can be selected and that the + * tool / client decides which item that is. The rule is that the *first + * item of those that match best is selected. + */ + boost::optional< bool > preselect; + + + // Internal information to order candidates. + int relevance = 0; + + // A string that shoud be used when comparing this item + // with other items. When `falsy` the label is used. + boost::optional< std::string > sortText; + + // A string that should be used when filtering a set of + // completion items. When `falsy` the label is used. + boost::optional<std::string> filterText; + + // A string that should be inserted a document when selecting + // this completion. When `falsy` the label is used. + boost::optional<std::string> insertText; + + // The format of the insert text. The format applies to both the `insertText` + // property and the `newText` property of a provided `textEdit`. + boost::optional< lsInsertTextFormat> insertTextFormat ; + + // An edit which is applied to a document when selecting this completion. When + // an edit is provided the value of `insertText` is ignored. + // + // *Note:* The range of the edit must be a single line range and it must + // contain the position at which completion has been requested. + boost::optional<lsTextEdit> textEdit; + + // An boost::optional array of additional text edits that are applied when + // selecting this completion. Edits must not overlap with the main edit + // nor with themselves. + // std::vector<TextEdit> additionalTextEdits; + + // An boost::optional command that is executed *after* inserting this completion. + // *Note* that additional modifications to the current document should be + // described with the additionalTextEdits-property. Command command; + + // An data entry field that is preserved on a completion item between + // a completion and a completion resolve request. + // data ? : any + + // Use this helper to figure out what content the completion item will insert + // into the document, as it could live in either |textEdit|, |insertText|, or + // |label|. + const std::string& InsertedContent() const; + + std::string DisplayText(); + /** + * An boost::optional array of additional text edits that are applied when + * selecting this completion. Edits must not overlap (including the same insert position) + * with the main edit nor with themselves. + * + * Additional text edits should be used to change text unrelated to the current cursor position + * (for example adding an import statement at the top of the file if the completion item will + * insert an unqualified type). + */ + boost::optional<std::vector<lsTextEdit> >additionalTextEdits; + + /** +* An boost::optional set of characters that when pressed while this completion is active will accept it first and +* then type that character. *Note* that all commit characters should have `length=1` and that superfluous +* characters will be ignored. +*/ + boost::optional< std::vector<std::string> > commitCharacters; + + /** +* An boost::optional command that is executed *after* inserting this completion. *Note* that +* additional modifications to the current document should be described with the +* additionalTextEdits-property. +*/ + boost::optional<lsCommandWithAny> command; + + /** +* An data entry field that is preserved on a completion item between a completion and a completion resolve request. +*/ + boost::optional<lsp::Any> data; + std::string ToString(); + MAKE_SWAP_METHOD(lsCompletionItem, + label, + kind, + detail, + documentation, + sortText, + insertText, + filterText, + insertTextFormat, + textEdit, + deprecated, preselect, additionalTextEdits, commitCharacters, + command, data); + +}; + + + +MAKE_REFLECT_STRUCT(lsCompletionItem, + label, + kind, + detail, + documentation, + sortText, + insertText, + filterText, + insertTextFormat, + textEdit, + deprecated, preselect, additionalTextEdits, commitCharacters, + command, data); + + + +struct CompletionList { + // This list it not complete. Further typing should result in recomputing + // this list. + bool isIncomplete = false; + // The completion items. + std::vector<lsCompletionItem> items; + + void swap(CompletionList& arg) noexcept + { + items.swap(arg.items); + std::swap(isIncomplete, arg.isIncomplete); + } +}; +MAKE_REFLECT_STRUCT(CompletionList, isIncomplete, items);
\ No newline at end of file diff --git a/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/lsp_diagnostic.cpp b/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/lsp_diagnostic.cpp new file mode 100644 index 00000000000..c323706dc03 --- /dev/null +++ b/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/lsp_diagnostic.cpp @@ -0,0 +1,74 @@ +#include "lsp_diagnostic.h" +bool lsDiagnostic::operator==(const lsDiagnostic& rhs) const { + // Just check the important fields. + return range == rhs.range && message == rhs.message; +} +bool lsDiagnostic::operator!=(const lsDiagnostic& rhs) const { + return !(*this == rhs); +} + +std::string lsResponseError::ToString() +{ + std::string info = "code:"; + switch (code) + { + case lsErrorCodes::ParseError: + info += "ParseError\n"; + break; + case lsErrorCodes::InvalidRequest: + info += "InvalidRequest\n"; + break; + case lsErrorCodes::MethodNotFound: + info += "MethodNotFound\n"; + break; + case lsErrorCodes::InvalidParams: + info += "InvalidParams\n"; + break; + case lsErrorCodes::InternalError: + info += "InternalError\n"; + break; + case lsErrorCodes::serverErrorStart: + info += "serverErrorStart\n"; + break; + case lsErrorCodes::serverErrorEnd: + info += "serverErrorEnd\n"; + break; + case lsErrorCodes::ServerNotInitialized: + info += "ServerNotInitialized\n"; + break; + case lsErrorCodes::UnknownErrorCode: + info += "UnknownErrorCode\n"; + break; + // Defined by the protocol. + case lsErrorCodes::RequestCancelled: + info += "RequestCancelled\n"; + break; + default: + { + std::stringstream ss; + ss << "unknown code:" << (int32_t)code << std::endl; + info += ss.str(); + } + break; + } + info += "message:" + message; + info += "\n"; + + if(data.has_value()) + { + + info += "data:" + data.value().Data(); + info += "\n"; + } + return info; +} + +void lsResponseError::Write(Writer& visitor) { + auto& value = *this; + int code2 = static_cast<int>(this->code); + + visitor.StartObject(); + REFLECT_MEMBER2("code", code2); + REFLECT_MEMBER(message); + visitor.EndObject(); +} diff --git a/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/lsp_diagnostic.h b/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/lsp_diagnostic.h new file mode 100644 index 00000000000..d1b1d1ba784 --- /dev/null +++ b/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/lsp_diagnostic.h @@ -0,0 +1,151 @@ +#pragma once +#include "lsRange.h" +#include "lsTextEdit.h" +#include "lsDocumentUri.h" + +#include "lsResponseError.h" +#include "location_type.h" + +#include "LibLsp/JsonRpc/RequestInMessage.h" +#include "LibLsp/JsonRpc/lsResponseMessage.h" + +enum class lsDiagnosticSeverity { + // Reports an error. + Error = 1, + // Reports a warning. + Warning = 2, + // Reports an information. + Information = 3, + // Reports a hint. + Hint = 4 +}; +MAKE_REFLECT_TYPE_PROXY(lsDiagnosticSeverity); + +/** + * The diagnostic tags. + * + * @since 3.15.0 + */ +enum class DiagnosticTag :uint8_t { + + /** + * Unused or unnecessary code. + * + * Clients are allowed to render diagnostics with this tag faded out instead of having + * an error squiggle. + */ + Unnecessary=(1), + + /** + * Deprecated or obsolete code. + * + * Clients are allowed to rendered diagnostics with this tag strike through. + */ + Deprecated=(2), +}; +MAKE_REFLECT_TYPE_PROXY(DiagnosticTag); + + + +/** + * Represents a related message and source code location for a diagnostic. This should be + * used to point to code locations that cause or related to a diagnostics, e.g when duplicating + * a symbol in a scope. + * + * Since 3.7.0 + */ + +struct DiagnosticRelatedInformation { + /** + * The location of this related diagnostic information. + */ + + lsLocation location; + + /** + * The message of this related diagnostic information. + */ + + std::string message; + + MAKE_SWAP_METHOD(DiagnosticRelatedInformation, location, message) +}; +MAKE_REFLECT_STRUCT(DiagnosticRelatedInformation, location, message) +/** + * Structure to capture a description for an error code. + * + * @since 3.16.0 + */ +struct DiagnosticCodeDescription { + /** + * An URI to open with more information about the diagnostic error. + */ + std::string href; + MAKE_SWAP_METHOD(DiagnosticCodeDescription, href) +}; +MAKE_REFLECT_STRUCT(DiagnosticCodeDescription, href) + +//Represents a diagnostic, such as a compiler error or warning.Diagnostic objects are only valid in the scope of a resource. +struct lsDiagnostic { + // The range at which the message applies. + lsRange range; + + // The diagnostic's severity. Can be omitted. If omitted it is up to the + // client to interpret diagnostics as error, warning, info or hint. + boost::optional<lsDiagnosticSeverity> severity; + + // The diagnostic's code. Can be omitted. + boost::optional< std::pair<boost::optional<std::string>, boost::optional<int>> > code; + + boost::optional<DiagnosticCodeDescription> codeDescription; + // A human-readable string describing the source of this + // diagnostic, e.g. 'typescript' or 'super lint'. + boost::optional < std::string >source ; + + // The diagnostic's message. + std::string message; + + // Non-serialized set of fixits. + std::vector<lsTextEdit> fixits_; + + /** + * Additional metadata about the diagnostic. + * + * @since 3.15.0 + */ + boost::optional<std::vector<DiagnosticTag>> tags; + + + /** + * An array of related diagnostic information, e.g. when symbol-names within a scope collide + * all definitions can be marked via this property. + * + * Since 3.7.0 + */ + boost::optional<std::vector<DiagnosticRelatedInformation>> relatedInformation; + + /** + * A data entry field that is preserved between a + * `textDocument/publishDiagnostics` notification and + * `textDocument/codeAction` request. + * + * @since 3.16.0 + */ + boost::optional<lsp::Any> data; + bool operator==(const lsDiagnostic& rhs) const; + bool operator!=(const lsDiagnostic& rhs) const; + + MAKE_SWAP_METHOD(lsDiagnostic, range, severity, code, codeDescription, source, message, tags, data) +}; +MAKE_REFLECT_STRUCT(lsDiagnostic, range, severity, code, codeDescription, source, message, tags, data) + + + +struct Rsp_Error : ResponseError<lsResponseError, Rsp_Error> { + + MAKE_SWAP_METHOD(Rsp_Error, jsonrpc, id, error) +}; +MAKE_REFLECT_STRUCT(Rsp_Error, jsonrpc, id, error) + + + diff --git a/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/method_type.h b/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/method_type.h new file mode 100644 index 00000000000..dcbb4a851a8 --- /dev/null +++ b/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/method_type.h @@ -0,0 +1,7 @@ +#pragma once +#include <string> + +using MethodType = const char* const; + + + diff --git a/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/out_list.h b/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/out_list.h new file mode 100644 index 00000000000..36c4aa78ba1 --- /dev/null +++ b/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/out_list.h @@ -0,0 +1,22 @@ +#pragma once + + +#include "location_type.h" + + +#include "LibLsp/JsonRpc/RequestInMessage.h" +#include "LibLsp/JsonRpc/lsResponseMessage.h" + + + +//DEFINE_RESPONCE_TYPE(Rsp_FindLinkLocationList, std::vector<LinkLocation>); +//DEFINE_RESPONCE_TYPE(Rsp_LocationList, std::vector<lsLocation>); + + +namespace LocationListEither{ + + typedef std::pair< boost::optional<std::vector<lsLocation>> , boost::optional<std::vector<LocationLink> > > Either; + +}; +extern void Reflect(Reader& visitor, LocationListEither::Either& value); +//DEFINE_RESPONCE_TYPE(Rsp_LocationListEither, LocationListEither::Either); diff --git a/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/symbol.h b/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/symbol.h new file mode 100644 index 00000000000..57298b8d7f9 --- /dev/null +++ b/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/symbol.h @@ -0,0 +1,164 @@ +#pragma once +#include "LibLsp/lsp/location_type.h" + + +enum class lsSymbolKind : uint8_t { + Unknown = 0, + + File = 1, + Module = 2, + Namespace = 3, + Package = 4, + Class = 5, + Method = 6, + Property = 7, + Field = 8, + Constructor = 9, + Enum = 10, + Interface = 11, + Function = 12, + Variable = 13, + Constant = 14, + String = 15, + Number = 16, + Boolean = 17, + Array = 18, + Object = 19, + Key = 20, + Null = 21, + EnumMember = 22, + Struct = 23, + Event = 24, + Operator = 25, + + // For C++, this is interpreted as "template parameter" (including + // non-type template parameters). + TypeParameter = 26, + + // cquery extensions + // See also https://github.com/Microsoft/language-server-protocol/issues/344 + // for new SymbolKind clang/Index/IndexSymbol.h clang::index::SymbolKind + TypeAlias = 252, + Parameter = 253, + StaticMethod = 254, + Macro = 255, +}; +MAKE_REFLECT_TYPE_PROXY(lsSymbolKind); + +typedef lsSymbolKind SymbolKind; + +// A document highlight kind. +enum class lsDocumentHighlightKind { + // A textual occurrence. + Text = 1, + // Read-access of a symbol, like reading a variable. + Read = 2, + // Write-access of a symbol, like writing to a variable. + Write = 3 +}; +MAKE_REFLECT_TYPE_PROXY(lsDocumentHighlightKind); + +// A document highlight is a range inside a text document which deserves +// special attention. Usually a document highlight is visualized by changing +// the background color of its range. +struct lsDocumentHighlight { + // The range this highlight applies to. + lsRange range; + + // The highlight kind, default is DocumentHighlightKind.Text. + boost::optional<lsDocumentHighlightKind> kind ; + + MAKE_SWAP_METHOD(lsDocumentHighlight, range, kind) +}; +MAKE_REFLECT_STRUCT(lsDocumentHighlight, range, kind); + +struct lsSymbolInformation { + +/** + * The name of this symbol. + */ + std::string name; + /** + * The kind of this symbol. + */ + lsSymbolKind kind; + /** +* Indicates if this symbol is deprecated. +*/ + boost::optional<bool> deprecated; + /** + * The location of this symbol. The location's range is used by a tool + * to reveal the location in the editor. If the symbol is selected in the + * tool the range's start information is used to position the cursor. So + * the range usually spans more then the actual symbol's name and does + * normally include things like visibility modifiers. + * + * The range doesn't have to denote a node range in the sense of a abstract + * syntax tree. It can therefore not be used to re-construct a hierarchy of + * the symbols. + */ + lsLocation location; + /** + * The name of the symbol containing this symbol. This information is for + * user interface purposes (e.g. to render a qualifier in the user interface + * if necessary). It can't be used to re-infer a hierarchy for the document + * symbols. + */ + boost::optional<std::string> containerName; + + + MAKE_SWAP_METHOD(lsSymbolInformation, name, kind, deprecated, location, containerName); +}; +MAKE_REFLECT_STRUCT(lsSymbolInformation, name, kind, deprecated, location, containerName); + + +struct lsDocumentSymbol { + /** + * The name of this symbol. + */ + + std::string name; + + /** + * The kind of this symbol. + */ + + lsSymbolKind kind = lsSymbolKind::Unknown; + + /** + * The range enclosing this symbol not including leading/trailing whitespace but everything else + * like comments. This information is typically used to determine if the clients cursor is + * inside the symbol to reveal in the symbol in the UI. + */ + + lsRange range; + + /** + * The range that should be selected and revealed when this symbol is being picked, e.g the name of a function. + * Must be contained by the `range`. + */ + + lsRange selectionRange; + + /** + * More detail for this symbol, e.g the signature of a function. If not provided the + * name is used. + */ + boost::optional< std::string > detail; + + /** + * Indicates if this symbol is deprecated. + */ + boost::optional< bool > deprecated; + + /** + * Children of this symbol, e.g. properties of a class. + */ + boost::optional < std::vector<lsDocumentSymbol> > children; + + //internal use + int flags=0; + + MAKE_SWAP_METHOD(lsDocumentSymbol, name, kind, range, selectionRange, detail, deprecated, children, flags); +}; +MAKE_REFLECT_STRUCT(lsDocumentSymbol, name, kind, range, selectionRange, detail, deprecated, children, flags);
\ No newline at end of file diff --git a/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/textDocument/SemanticTokens.h b/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/textDocument/SemanticTokens.h new file mode 100644 index 00000000000..612d186f6fb --- /dev/null +++ b/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/textDocument/SemanticTokens.h @@ -0,0 +1,267 @@ +#pragma once + +#include "LibLsp/lsp/lsTextDocumentIdentifier.h" +#include "LibLsp/lsp/lsVersionedTextDocumentIdentifier.h" +#include "LibLsp/JsonRpc/RequestInMessage.h" +enum class HighlightingKind_clangD { + Variable = 0, + LocalVariable, + Parameter, + Function, + Method, + StaticMethod, + Field, + StaticField, + Class, + Interface, + Enum, + EnumConstant, + Typedef, + Type, + Unknown, + Namespace, + TemplateParameter, + Concept, + Primitive, + Macro, + + // This one is different from the other kinds as it's a line style + // rather than a token style. + InactiveCode, + + LastKind = InactiveCode +}; +std::string toSemanticTokenType(HighlightingKind_clangD kind); + +enum class HighlightingModifier_clangD { + Declaration, + Deprecated, + Deduced, + Readonly, + Static, + Abstract, + DependentName, + DefaultLibrary, + + FunctionScope, + ClassScope, + FileScope, + GlobalScope, + + LastModifier = GlobalScope +}; +std::string toSemanticTokenModifier(HighlightingModifier_clangD modifier); + +enum SemanticTokenType { + ls_namespace=0,// 'namespace', + /** + * Represents a generic type. Acts as a fallback for types which + * can't be mapped to a specific type like class or enum. + */ + ls_type,// 'type', + ls_class,// 'class', + ls_enum,// 'enum', + ls_interface,// 'interface', + ls_struct,// 'struct', + ls_typeParameter,// 'typeParameter', + ls_parameter,// 'parameter', + ls_variable,// 'variable', + ls_property,// 'property', + ls_enumMember,// 'enumMember', + ls_event,// 'event', + ls_function,// 'function', + ls_method,// 'method', + ls_macro,// 'macro', + ls_keyword,// 'keyword', + ls_modifier,// 'modifier', + ls_comment,// 'comment', + ls_string,// 'string', + ls_number,// 'number', + ls_regexp,// 'regexp', + ls_operator,// 'operator' + lastKind = ls_operator +}; +std::string to_string(SemanticTokenType); +unsigned toSemanticTokenType(std::vector<SemanticTokenType>& modifiers); + +enum TokenType_JDT { + PACKAGE_JDT=0, + CLASS_JDT, + INTERFACE_JDT, + ENUM_JDT, + ENUM_MEMBER_JDT, + TYPE_JDT, + TYPE_PARAMETER_JDT, + ANNOTATION_JDT, + ANNOTATION_MEMBER_JDT, + METHOD_JDT, + PROPERTY_JDT, + VARIABLE_JDT, + PARAMETER_JDT +}; +std::string to_string(TokenType_JDT); + +enum SemanticTokenModifier { + ls_declaration=0,// 'declaration', + ls_definition,// 'definition', + ls_readonly,// 'readonly', + ls_static,// 'static', + ls_deprecated,// 'deprecated', + ls_abstract,// 'abstract', + ls_async,// 'async', + ls_modification,// 'modification', + ls_documentation,// 'documentation', + ls_defaultLibrary,// 'defaultLibrary' + LastModifier = ls_defaultLibrary +}; +std::string to_string(SemanticTokenModifier); +unsigned toSemanticTokenModifiers(std::vector<SemanticTokenModifier>&); +/// Specifies a single semantic token in the document. +/// This struct is not part of LSP, which just encodes lists of tokens as +/// arrays of numbers directly. +struct SemanticToken { + /// token line number, relative to the previous token + unsigned deltaLine = 0; + /// token start character, relative to the previous token + /// (relative to 0 or the previous token's start if they are on the same line) + unsigned deltaStart = 0; + /// the length of the token. A token cannot be multiline + unsigned length = 0; + /// will be looked up in `SemanticTokensLegend.tokenTypes` + unsigned tokenType = 0; + /// each set bit will be looked up in `SemanticTokensLegend.tokenModifiers` + unsigned tokenModifiers = 0; +}; +bool operator==(const SemanticToken&, const SemanticToken&); +struct SemanticTokens{ + + /** + * Tokens in a file are represented as an array of integers. The position of each token is expressed relative to + * the token before it, because most tokens remain stable relative to each other when edits are made in a file. + * + * --- + * In short, each token takes 5 integers to represent, so a specific token `i` in the file consists of the following array indices: + * - at index `5*i` - `deltaLine`: token line number, relative to the previous token + * - at index `5*i+1` - `deltaStart`: token start character, relative to the previous token (relative to 0 or the previous token's start if they are on the same line) + * - at index `5*i+2` - `length`: the length of the token. A token cannot be multiline. + * - at index `5*i+3` - `tokenType`: will be looked up in `SemanticTokensLegend.tokenTypes`. We currently ask that `tokenType` < 65536. + * - at index `5*i+4` - `tokenModifiers`: each set bit will be looked up in `SemanticTokensLegend.tokenModifiers` + * + * --- + * ### How to encode tokens + * + * Here is an example for encoding a file with 3 tokens in a uint32 array: + * ``` + * { line: 2, startChar: 5, length: 3, tokenType: "property", tokenModifiers: ["private", "static"] }, + * { line: 2, startChar: 10, length: 4, tokenType: "type", tokenModifiers: [] }, + * { line: 5, startChar: 2, length: 7, tokenType: "class", tokenModifiers: [] } + * ``` + * + * 1. First of all, a legend must be devised. This legend must be provided up-front and capture all possible token types. + * For this example, we will choose the following legend which must be passed in when registering the provider: + * ``` + * tokenTypes: ['property', 'type', 'class'], + * tokenModifiers: ['private', 'static'] + * ``` + * + * 2. The first transformation step is to encode `tokenType` and `tokenModifiers` as integers using the legend. Token types are looked + * up by index, so a `tokenType` value of `1` means `tokenTypes[1]`. Multiple token modifiers can be set by using bit flags, + * so a `tokenModifier` value of `3` is first viewed as binary `0b00000011`, which means `[tokenModifiers[0], tokenModifiers[1]]` because + * bits 0 and 1 are set. Using this legend, the tokens now are: + * ``` + * { line: 2, startChar: 5, length: 3, tokenType: 0, tokenModifiers: 3 }, + * { line: 2, startChar: 10, length: 4, tokenType: 1, tokenModifiers: 0 }, + * { line: 5, startChar: 2, length: 7, tokenType: 2, tokenModifiers: 0 } + * ``` + * + * 3. The next step is to represent each token relative to the previous token in the file. In this case, the second token + * is on the same line as the first token, so the `startChar` of the second token is made relative to the `startChar` + * of the first token, so it will be `10 - 5`. The third token is on a different line than the second token, so the + * `startChar` of the third token will not be altered: + * ``` + * { deltaLine: 2, deltaStartChar: 5, length: 3, tokenType: 0, tokenModifiers: 3 }, + * { deltaLine: 0, deltaStartChar: 5, length: 4, tokenType: 1, tokenModifiers: 0 }, + * { deltaLine: 3, deltaStartChar: 2, length: 7, tokenType: 2, tokenModifiers: 0 } + * ``` + * + * 4. Finally, the last step is to inline each of the 5 fields for a token in a single array, which is a memory friendly representation: + * ``` + * // 1st token, 2nd token, 3rd token + * [ 2,5,3,0,3, 0,5,4,1,0, 3,2,7,2,0 ] + * ``` + */ + std::vector<int32_t> data; + static std::vector<int32_t> encodeTokens(std::vector<SemanticToken>& tokens); + + /** + * An optional result id. If provided and clients support delta updating + * the client will include the result id in the next semantic token request. + * A server can then instead of computing all semantic tokens again simply + * send a delta. + */ + boost::optional<std::string> resultId; + MAKE_SWAP_METHOD(SemanticTokens, data, resultId) +}; +MAKE_REFLECT_STRUCT(SemanticTokens, data, resultId) + +/// Body of textDocument/semanticTokens/full request. +struct SemanticTokensParams { + /// The text document. + lsTextDocumentIdentifier textDocument; + MAKE_REFLECT_STRUCT(SemanticTokensParams, textDocument) +}; +MAKE_REFLECT_STRUCT(SemanticTokensParams, textDocument) + + +/// Body of textDocument/semanticTokens/full/delta request. +/// Requests the changes in semantic tokens since a previous response. +struct SemanticTokensDeltaParams { + /// The text document. + lsTextDocumentIdentifier textDocument; + /** + * The result id of a previous response. The result Id can either point to + * a full response or a delta response depending on what was received last. + */ + std::string previousResultId; + + MAKE_REFLECT_STRUCT(SemanticTokensDeltaParams, textDocument, previousResultId) +}; +MAKE_REFLECT_STRUCT(SemanticTokensDeltaParams, textDocument, previousResultId) + +/// Describes a a replacement of a contiguous range of semanticTokens. +struct SemanticTokensEdit { + // LSP specifies `start` and `deleteCount` which are relative to the array + // encoding of the previous tokens. + // We use token counts instead, and translate when serializing this struct. + unsigned startToken = 0; + unsigned deleteTokens = 0; + std::vector<int32_t> tokens; // encoded as a flat integer array + + MAKE_REFLECT_STRUCT(SemanticTokensEdit, startToken, deleteTokens, tokens) +}; +MAKE_REFLECT_STRUCT(SemanticTokensEdit, startToken, deleteTokens, tokens) + + +/// This models LSP SemanticTokensDelta | SemanticTokens, which is the result of +/// textDocument/semanticTokens/full/delta. +struct SemanticTokensOrDelta { + boost::optional<std::string > resultId; + /// Set if we computed edits relative to a previous set of tokens. + boost::optional< std::vector<SemanticTokensEdit> > edits; + /// Set if we computed a fresh set of tokens. + /// Set if we computed edits relative to a previous set of tokens. + boost::optional<std::vector<int32_t>> tokens; // encoded as integer array + MAKE_REFLECT_STRUCT(SemanticTokensOrDelta, resultId, edits, tokens) +}; +MAKE_REFLECT_STRUCT(SemanticTokensOrDelta, resultId, edits, tokens) + + +struct SemanticTokensLegend { + std::vector<std::string> tokenTypes; + std::vector<std::string> tokenModifiers; + MAKE_REFLECT_STRUCT(SemanticTokensLegend, tokenTypes, tokenModifiers) +}; +MAKE_REFLECT_STRUCT(SemanticTokensLegend, tokenTypes, tokenModifiers) + +DEFINE_REQUEST_RESPONSE_TYPE(td_semanticTokens_full, SemanticTokensParams,boost::optional<SemanticTokens >,"textDocument/semanticTokens/full") +DEFINE_REQUEST_RESPONSE_TYPE(td_semanticTokens_full_delta, SemanticTokensDeltaParams, boost::optional<SemanticTokensOrDelta >, "textDocument/semanticTokens/full/delta")
\ No newline at end of file diff --git a/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/textDocument/callHierarchy.h b/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/textDocument/callHierarchy.h new file mode 100644 index 00000000000..a005c182e17 --- /dev/null +++ b/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/textDocument/callHierarchy.h @@ -0,0 +1,121 @@ +#pragma once + +#include "LibLsp/lsp/lsAny.h" +#include "LibLsp/JsonRpc/RequestInMessage.h" +#include "LibLsp/JsonRpc/lsResponseMessage.h" +#include "LibLsp/lsp/symbol.h" +#include "LibLsp/lsp/lsTextDocumentPositionParams.h" +#include "LibLsp/lsp/lsRange.h" + +enum class SymbolTag { Deprecated = 1 }; +MAKE_REFLECT_TYPE_PROXY(SymbolTag) + +struct CallHierarchyPrepareParams +{ + lsTextDocumentIdentifier textDocument; + lsPosition position; + + MAKE_SWAP_METHOD(CallHierarchyPrepareParams, + textDocument, + position) +}; +MAKE_REFLECT_STRUCT(CallHierarchyPrepareParams, + textDocument, + position) + + + + /// Represents programming constructs like functions or constructors + /// in the context of call hierarchy. +struct CallHierarchyItem { + /// The name of this item. + std::string name; + + /// The kind of this item. + SymbolKind kind; + + /// Tags for this item. + boost::optional<std::vector<SymbolTag>> tags; + + /// More detaill for this item, e.g. the signature of a function. + boost::optional<std::string> detail; + + /// The resource identifier of this item. + lsDocumentUri uri; + + /** + * The range enclosing this symbol not including leading/trailing whitespace + * but everything else, e.g. comments and code. + */ + lsRange range; + + /** + * The range that should be selected and revealed when this symbol is being + * picked, e.g. the name of a function. Must be contained by the + * [`range`](#CallHierarchyItem.range). + */ + lsRange selectionRange; + + /** + * A data entry field that is preserved between a call hierarchy prepare and + * incoming calls or outgoing calls requests. + */ + boost::optional<lsp::Any> data; + MAKE_SWAP_METHOD(CallHierarchyItem, name, kind, tags, detail, uri, range, selectionRange, data) +}; +MAKE_REFLECT_STRUCT(CallHierarchyItem, name, kind, tags, detail, uri, range, selectionRange, data) + + + +/// The parameter of a `callHierarchy/incomingCalls` request. +struct CallHierarchyIncomingCallsParams { + CallHierarchyItem item; + MAKE_SWAP_METHOD(CallHierarchyIncomingCallsParams,item) +}; +MAKE_REFLECT_STRUCT(CallHierarchyIncomingCallsParams, item) + + +/// Represents an incoming call, e.g. a caller of a method or constructor. +struct CallHierarchyIncomingCall { + /// The item that makes the call. + CallHierarchyItem from; + + /// The range at which the calls appear. + /// This is relative to the caller denoted by `From`. + std::vector<lsRange> fromRanges; + MAKE_SWAP_METHOD(CallHierarchyIncomingCall, from, fromRanges) +}; +MAKE_REFLECT_STRUCT(CallHierarchyIncomingCall, from, fromRanges) + + + + +/// The parameter of a `callHierarchy/outgoingCalls` request. +struct CallHierarchyOutgoingCallsParams { + CallHierarchyItem item; + MAKE_SWAP_METHOD(CallHierarchyOutgoingCallsParams, item) +}; +MAKE_REFLECT_STRUCT(CallHierarchyOutgoingCallsParams, item) + +/// Represents an outgoing call, e.g. calling a getter from a method or +/// a method from a constructor etc. +struct CallHierarchyOutgoingCall { + /// The item that is called. + CallHierarchyItem to; + + /// The range at which this item is called. + /// This is the range relative to the caller, and not `To`. + std::vector<lsRange> fromRanges; + MAKE_SWAP_METHOD(CallHierarchyOutgoingCall, to, fromRanges) +}; +MAKE_REFLECT_STRUCT(CallHierarchyOutgoingCall, to, fromRanges) + + +DEFINE_REQUEST_RESPONSE_TYPE(td_prepareCallHierarchy, CallHierarchyPrepareParams, + boost::optional<std::vector<CallHierarchyItem>>, "textDocument/prepareCallHierarchy") + +DEFINE_REQUEST_RESPONSE_TYPE(td_incomingCalls, CallHierarchyIncomingCallsParams, + boost::optional<std::vector<CallHierarchyIncomingCall>>, "callHierarchy/incomingCalls") + +DEFINE_REQUEST_RESPONSE_TYPE(td_outgoingCalls, CallHierarchyOutgoingCallsParams, + boost::optional<std::vector<CallHierarchyOutgoingCall>>, "callHierarchy/CallHierarchyOutgoingCall")
\ No newline at end of file diff --git a/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/textDocument/code_action.h b/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/textDocument/code_action.h new file mode 100644 index 00000000000..419fdfbc9b4 --- /dev/null +++ b/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/textDocument/code_action.h @@ -0,0 +1,37 @@ +#pragma once +#include "LibLsp/lsp/method_type.h" +#include "LibLsp/JsonRpc/RequestInMessage.h" +#include "LibLsp/JsonRpc/lsResponseMessage.h" +#include "LibLsp/lsp/lsTextDocumentIdentifier.h" +#include "LibLsp/lsp/CodeActionParams.h" + +namespace QuickAssistProcessor { + + extern const char* SPLIT_JOIN_VARIABLE_DECLARATION_ID;//$NON-NLS-1$ + extern const char* CONVERT_FOR_LOOP_ID;// ;// "org.eclipse.jdt.ls.correction.convertForLoop.assist"; //$NON-NLS-1$ + extern const char* ASSIGN_TO_LOCAL_ID ;// "org.eclipse.jdt.ls.correction.assignToLocal.assist"; //$NON-NLS-1$ + extern const char* ASSIGN_TO_FIELD_ID ;// "org.eclipse.jdt.ls.correction.assignToField.assist"; //$NON-NLS-1$ + extern const char* ASSIGN_PARAM_TO_FIELD_ID ;// "org.eclipse.jdt.ls.correction.assignParamToField.assist"; //$NON-NLS-1$ + extern const char* ASSIGN_ALL_PARAMS_TO_NEW_FIELDS_ID ;// "org.eclipse.jdt.ls.correction.assignAllParamsToNewFields.assist"; //$NON-NLS-1$ + extern const char* ADD_BLOCK_ID ;// "org.eclipse.jdt.ls.correction.addBlock.assist"; //$NON-NLS-1$ + extern const char* EXTRACT_LOCAL_ID ;// "org.eclipse.jdt.ls.correction.extractLocal.assist"; //$NON-NLS-1$ + extern const char* EXTRACT_LOCAL_NOT_REPLACE_ID ;// "org.eclipse.jdt.ls.correction.extractLocalNotReplaceOccurrences.assist"; //$NON-NLS-1$ + extern const char* EXTRACT_CONSTANT_ID ;// "org.eclipse.jdt.ls.correction.extractConstant.assist"; //$NON-NLS-1$ + extern const char* INLINE_LOCAL_ID ;// "org.eclipse.jdt.ls.correction.inlineLocal.assist"; //$NON-NLS-1$ + extern const char* CONVERT_LOCAL_TO_FIELD_ID ;// "org.eclipse.jdt.ls.correction.convertLocalToField.assist"; //$NON-NLS-1$ + extern const char* CONVERT_ANONYMOUS_TO_LOCAL_ID ;// "org.eclipse.jdt.ls.correction.convertAnonymousToLocal.assist"; //$NON-NLS-1$ + extern const char* CONVERT_TO_STRING_BUFFER_ID ;// "org.eclipse.jdt.ls.correction.convertToStringBuffer.assist"; //$NON-NLS-1$ + extern const char* CONVERT_TO_MESSAGE_FORMAT_ID ;// "org.eclipse.jdt.ls.correction.convertToMessageFormat.assist"; //$NON-NLS-1$; + extern const char* EXTRACT_METHOD_INPLACE_ID ;// "org.eclipse.jdt.ls.correction.extractMethodInplace.assist"; //$NON-NLS-1$; + + extern const char* CONVERT_ANONYMOUS_CLASS_TO_NESTED_COMMAND ;// "convertAnonymousClassToNestedCommand"; +}; +/** + * The code action request is sent from the client to the server to compute + * commands for a given text document and range. These commands are + * typically code fixes to either fix problems or to beautify/refactor code. + * + * Registration Options: TextDocumentRegistrationOptions + */ + +DEFINE_REQUEST_RESPONSE_TYPE(td_codeAction, lsCodeActionParams, std::vector<lsCommandWithAny>, "textDocument/codeAction"); diff --git a/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/textDocument/code_lens.h b/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/textDocument/code_lens.h new file mode 100644 index 00000000000..7fd5ae0cf98 --- /dev/null +++ b/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/textDocument/code_lens.h @@ -0,0 +1,42 @@ +#pragma once + +#include "LibLsp/JsonRpc/RequestInMessage.h" +#include "LibLsp/JsonRpc/lsResponseMessage.h" + +struct lsDocumentCodeLensParams { + +/** + * The document to request code lens for. + */ + lsTextDocumentIdentifier textDocument; + + MAKE_SWAP_METHOD(lsDocumentCodeLensParams, textDocument); +}; +MAKE_REFLECT_STRUCT(lsDocumentCodeLensParams, textDocument); + + + + +struct lsCodeLens { + // The range in which this code lens is valid. Should only span a single line. + lsRange range; + // The command this code lens represents. + boost::optional<lsCommandWithAny> command; + // A data entry field that is preserved on a code lens item between + // a code lens and a code lens resolve request. + boost::optional< lsp::Any> data; + + MAKE_SWAP_METHOD(lsCodeLens, range, command, data) +}; +MAKE_REFLECT_STRUCT(lsCodeLens, range, command, data) + + + +/** + * The code lens request is sent from the client to the server to compute + * code lenses for a given text document. + * + * Registration Options: CodeLensRegistrationOptions + */ +DEFINE_REQUEST_RESPONSE_TYPE(td_codeLens, lsDocumentCodeLensParams, std::vector<lsCodeLens>, "textDocument/codeLens") + diff --git a/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/textDocument/colorPresentation.h b/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/textDocument/colorPresentation.h new file mode 100644 index 00000000000..22574e3e194 --- /dev/null +++ b/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/textDocument/colorPresentation.h @@ -0,0 +1,63 @@ +#pragma once + + +#include "LibLsp/JsonRpc/RequestInMessage.h" +#include "LibLsp/JsonRpc/lsResponseMessage.h" + +#include "LibLsp/lsp/lsTextDocumentIdentifier.h" +#include "LibLsp/lsp/lsRange.h" +#include "documentColor.h" +#include "LibLsp/lsp/lsTextEdit.h" + + +struct ColorPresentationParams { + + /** + * The text document. + */ + lsTextDocumentIdentifier textDocument; + + /** + * The range in the document where this color appers. + */ + + lsRange range; + + /** + * The actual color value for this color range. + */ + + TextDocument::Color color; + MAKE_SWAP_METHOD(ColorPresentationParams, textDocument, range, color) +}; +MAKE_REFLECT_STRUCT(ColorPresentationParams, textDocument, range, color) + + +struct ColorPresentation { + /** + * The label of this color presentation. It will be shown on the color + * picker header. By default this is also the text that is inserted when selecting + * this color presentation. + */ + + std::string label; + + /** + * An edit which is applied to a document when selecting + * this presentation for the color. When `null` the label is used. + */ + lsTextEdit textEdit; + + /** + * An optional array of additional text edits that are applied when + * selecting this color presentation. Edits must not overlap with the main edit nor with themselves. + */ + std::vector<lsTextEdit> additionalTextEdits; + MAKE_SWAP_METHOD(ColorPresentation, label, textEdit, additionalTextEdits) +}; +MAKE_REFLECT_STRUCT(ColorPresentation, label, textEdit, additionalTextEdits) + + + +DEFINE_REQUEST_RESPONSE_TYPE(td_colorPresentation, + ColorPresentationParams, std::vector<ColorPresentation>, "textDocument/colorPresentation")
\ No newline at end of file diff --git a/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/textDocument/completion.h b/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/textDocument/completion.h new file mode 100644 index 00000000000..883c5cfe3a8 --- /dev/null +++ b/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/textDocument/completion.h @@ -0,0 +1,82 @@ +#pragma once + + +#include "LibLsp/JsonRpc/RequestInMessage.h" +#include "LibLsp/JsonRpc/lsResponseMessage.h" + +#include <regex> +#include "LibLsp/lsp/lsp_completion.h" +#include "LibLsp/lsp/lsTextDocumentPositionParams.h" + + +// How a completion was triggered +enum class lsCompletionTriggerKind { + // Completion was triggered by typing an identifier (24x7 code + // complete), manual invocation (e.g Ctrl+Space) or via API. + Invoked = 1, + + // Completion was triggered by a trigger character specified by + // the `triggerCharacters` properties of the `CompletionRegistrationOptions`. + TriggerCharacter = 2 +}; +MAKE_REFLECT_TYPE_PROXY(lsCompletionTriggerKind); + + +// Contains additional information about the context in which a completion +// request is triggered. +struct lsCompletionContext { + // How the completion was triggered. + lsCompletionTriggerKind triggerKind = lsCompletionTriggerKind::Invoked; + + // The trigger character (a single character) that has trigger code complete. + // Is undefined if `triggerKind !== CompletionTriggerKind.TriggerCharacter` + boost::optional<std::string> triggerCharacter; + + MAKE_SWAP_METHOD(lsCompletionContext, triggerKind, triggerCharacter); +}; +MAKE_REFLECT_STRUCT(lsCompletionContext, triggerKind, triggerCharacter); + +struct lsCompletionParams : lsTextDocumentPositionParams { + // The completion context. This is only available it the client specifies to + // send this using + // `ClientCapabilities.textDocument.completion.contextSupport === true` + boost::optional<lsCompletionContext> context; + + MAKE_SWAP_METHOD(lsCompletionParams, textDocument, position, context); + +}; +MAKE_REFLECT_STRUCT(lsCompletionParams, textDocument, position, context); + + + + + + + + + +namespace TextDocumentComplete{ + + typedef std::pair< boost::optional<std::vector<lsCompletionItem>>, boost::optional<CompletionList> > Either; + +}; +extern void Reflect(Reader& visitor, TextDocumentComplete::Either& value); + +/** + * The Completion request is sent from the client to the server to compute + * completion items at a given cursor position. Completion items are + * presented in the IntelliSense user interface. If computing complete + * completion items is expensive servers can additional provide a handler + * for the resolve completion item request. This request is sent when a + * completion item is selected in the user interface. + * + * Registration Options: CompletionRegistrationOptions + */ +DEFINE_REQUEST_RESPONSE_TYPE(td_completion, lsCompletionParams, CompletionList , "textDocument/completion") + + + + + + + diff --git a/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/textDocument/declaration_definition.h b/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/textDocument/declaration_definition.h new file mode 100644 index 00000000000..aa20fce0463 --- /dev/null +++ b/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/textDocument/declaration_definition.h @@ -0,0 +1,29 @@ +#pragma once + + +#include "LibLsp/JsonRpc/RequestInMessage.h" +#include "LibLsp/JsonRpc/lsResponseMessage.h" + +#include "LibLsp/lsp/lsTextDocumentPositionParams.h" +#include "LibLsp/lsp/out_list.h" + + +/** + * The go to declaration request is sent from the client to the server to resolve + * the declaration location of a symbol at a given text document position. + * + * Registration Options: TextDocumentRegistrationOptions + * + * Since version 3.14.0 + */ +DEFINE_REQUEST_RESPONSE_TYPE(td_declaration, lsTextDocumentPositionParams, LocationListEither::Either, "textDocument/declaration"); + +/** + * The goto definition request is sent from the client to the server to resolve + * the definition location of a symbol at a given text document position. + * + * Registration Options: TextDocumentRegistrationOptions + */ +DEFINE_REQUEST_RESPONSE_TYPE(td_definition, lsTextDocumentPositionParams, LocationListEither::Either, "textDocument/definition"); + + diff --git a/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/textDocument/didRenameFiles.h b/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/textDocument/didRenameFiles.h new file mode 100644 index 00000000000..e8a6235a002 --- /dev/null +++ b/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/textDocument/didRenameFiles.h @@ -0,0 +1,44 @@ +#pragma once + +#include "LibLsp/JsonRpc/RequestInMessage.h" +#include "LibLsp/JsonRpc/lsResponseMessage.h" +#include <string> +#include "LibLsp/lsp/CodeActionParams.h" +#include "LibLsp/lsp/lsWorkspaceEdit.h" + + +class FileRenameEvent { +public: + std::string oldUri; + std::string newUri; + + FileRenameEvent() { + } + + FileRenameEvent(std::string oldUri, std::string newUri) { + this->oldUri = oldUri; + this->newUri = newUri; + } + MAKE_SWAP_METHOD(FileRenameEvent, oldUri, newUri); +}; +MAKE_REFLECT_STRUCT(FileRenameEvent, oldUri, newUri); + +class FileRenameParams { +public: + std::vector <FileRenameEvent> files; + + FileRenameParams() { + } + + FileRenameParams(std::vector<FileRenameEvent>& files) { + this->files = files; + } + MAKE_SWAP_METHOD(FileRenameParams, files); +}; +MAKE_REFLECT_STRUCT(FileRenameParams, files); + + +DEFINE_REQUEST_RESPONSE_TYPE(td_didRenameFiles, FileRenameParams, boost::optional<lsWorkspaceEdit>, "java/didRenameFiles"); + + +DEFINE_REQUEST_RESPONSE_TYPE(td_willRenameFiles, FileRenameParams, boost::optional<lsWorkspaceEdit>, "java/willRenameFiles"); diff --git a/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/textDocument/did_change.h b/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/textDocument/did_change.h new file mode 100644 index 00000000000..0887bf66029 --- /dev/null +++ b/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/textDocument/did_change.h @@ -0,0 +1,51 @@ +#pragma once + + +#include "LibLsp/JsonRpc/NotificationInMessage.h" +#include "LibLsp/JsonRpc/lsResponseMessage.h" + +#include "LibLsp/lsp/lsVersionedTextDocumentIdentifier.h" +#include "LibLsp/lsp/lsRange.h" +#include "LibLsp/lsp/lsDocumentUri.h" +struct lsTextDocumentContentChangeEvent { + // The range of the document that changed. + boost::optional<lsRange> range; + // The length of the range that got replaced. + boost::optional<int> rangeLength; + // The new text of the range/document. + std::string text; + + MAKE_SWAP_METHOD(lsTextDocumentContentChangeEvent, range, rangeLength, text); +}; +MAKE_REFLECT_STRUCT(lsTextDocumentContentChangeEvent, range, rangeLength, text); + + +struct lsTextDocumentDidChangeParams { + lsVersionedTextDocumentIdentifier textDocument; + std::vector<lsTextDocumentContentChangeEvent> contentChanges; + + /** + * Legacy property to support protocol version 1.0 requests. + */ + + boost::optional<lsDocumentUri> uri; + + void swap(lsTextDocumentDidChangeParams& arg) noexcept + { + uri.swap(arg.uri); + contentChanges.swap(arg.contentChanges); + textDocument.swap(arg.textDocument); + } +}; +MAKE_REFLECT_STRUCT(lsTextDocumentDidChangeParams, + textDocument, + contentChanges, uri); + +/** + * The document change notification is sent from the client to the server to + * signal changes to a text document. + * + * Registration Options: TextDocumentChangeRegistrationOptions + */ +DEFINE_NOTIFICATION_TYPE(Notify_TextDocumentDidChange, lsTextDocumentDidChangeParams, "textDocument/didChange"); + diff --git a/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/textDocument/did_close.h b/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/textDocument/did_close.h new file mode 100644 index 00000000000..e2eaa2cfcd8 --- /dev/null +++ b/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/textDocument/did_close.h @@ -0,0 +1,33 @@ +#pragma once + + + +#include "LibLsp/JsonRpc/NotificationInMessage.h" + + + + +namespace TextDocumentDidClose { + + struct Params { + lsTextDocumentIdentifier textDocument; + void swap(Params& arg) noexcept + { + textDocument.swap(arg.textDocument); + } + + }; + +}; + +MAKE_REFLECT_STRUCT(TextDocumentDidClose::Params, textDocument); + +/** + * The document close notification is sent from the client to the server + * when the document got closed in the client. The document's truth now + * exists where the document's uri points to (e.g. if the document's uri is + * a file uri the truth now exists on disk). + * + * Registration Options: TextDocumentRegistrationOptions + */ +DEFINE_NOTIFICATION_TYPE(Notify_TextDocumentDidClose, TextDocumentDidClose::Params, "textDocument/didClose"); diff --git a/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/textDocument/did_open.h b/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/textDocument/did_open.h new file mode 100644 index 00000000000..7be7a735d64 --- /dev/null +++ b/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/textDocument/did_open.h @@ -0,0 +1,39 @@ +#pragma once + + +#include "LibLsp/JsonRpc/NotificationInMessage.h" + +#include "LibLsp/lsp/lsTextDocumentItem.h" + +// Open, view, change, close file +namespace TextDocumentDidOpen { + + struct Params { + lsTextDocumentItem textDocument; + + + + /** + * Legacy property to support protocol version 1.0 requests. + */ + boost::optional<std::string> text; + + MAKE_SWAP_METHOD(TextDocumentDidOpen::Params, textDocument, text); + + }; + +} +MAKE_REFLECT_STRUCT(TextDocumentDidOpen::Params, textDocument, text); + +/** + * The document open notification is sent from the client to the server to + * signal newly opened text documents. The document's truth is now managed + * by the client and the server must not try to read the document's truth + * using the document's uri. + * + * Registration Options: TextDocumentRegistrationOptions + */; + + +DEFINE_NOTIFICATION_TYPE(Notify_TextDocumentDidOpen, TextDocumentDidOpen::Params, "textDocument/didOpen"); + diff --git a/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/textDocument/did_save.h b/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/textDocument/did_save.h new file mode 100644 index 00000000000..1ce386c415f --- /dev/null +++ b/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/textDocument/did_save.h @@ -0,0 +1,31 @@ +#pragma once + + + +#include "LibLsp/JsonRpc/NotificationInMessage.h" + + +namespace TextDocumentDidSave { + + struct Params { + // The document that was saved. + lsTextDocumentIdentifier textDocument; + + // Optional the content when saved. Depends on the includeText value + // when the save notifcation was requested. + boost::optional<std::string> text; + + MAKE_SWAP_METHOD(TextDocumentDidSave::Params, textDocument, text); + }; + +}; +MAKE_REFLECT_STRUCT(TextDocumentDidSave::Params, textDocument, text); + +/** + * The document save notification is sent from the client to the server when + * the document for saved in the client. + * + * Registration Options: TextDocumentSaveRegistrationOptions + */ +DEFINE_NOTIFICATION_TYPE(Notify_TextDocumentDidSave, TextDocumentDidSave::Params, "textDocument/didSave"); + diff --git a/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/textDocument/documentColor.h b/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/textDocument/documentColor.h new file mode 100644 index 00000000000..23a6d08d87c --- /dev/null +++ b/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/textDocument/documentColor.h @@ -0,0 +1,73 @@ +#pragma once + +#include "LibLsp/JsonRpc/RequestInMessage.h" +#include "LibLsp/JsonRpc/lsResponseMessage.h" + +#include "LibLsp/lsp/lsTextDocumentIdentifier.h" +#include "LibLsp/lsp/lsRange.h" +#include <vector> +struct DocumentColorParams { + /** + * The text document. + */ + + lsTextDocumentIdentifier textDocument; + MAKE_SWAP_METHOD(DocumentColorParams, textDocument); +}; +MAKE_REFLECT_STRUCT(DocumentColorParams, textDocument); + +/** + * The document color request is sent from the client to the server to list all color references found in a given text + * document. Along with the range, a color value in RGB is returned. + * + * Clients can use the result to decorate color references in an editor. For example: + * - Color boxes showing the actual color next to the reference + * - Show a color picker when a color reference is edited + * + * Since version 3.6.0 + */ + +namespace TextDocument { + struct Color { + /** + * The red component of this color in the range [0-1]. + */ + double red = 0; + + /** + * The green component of this color in the range [0-1]. + */ + double green = 0; + + /** + * The blue component of this color in the range [0-1]. + */ + double blue = 0; + + /** + * The alpha component of this color in the range [0-1]. + */ + double alpha = 0; + MAKE_SWAP_METHOD(TextDocument::Color, red, green, blue, alpha) + }; +} +MAKE_REFLECT_STRUCT(TextDocument::Color, red, green, blue, alpha) + + +struct ColorInformation { + /** + * The range in the document where this color appers. + */ + + lsRange range; + + /** + * The actual color value for this color range. + */ + + TextDocument::Color color; + MAKE_SWAP_METHOD(ColorInformation, range, color) +}; +MAKE_REFLECT_STRUCT(ColorInformation,range,color) + +DEFINE_REQUEST_RESPONSE_TYPE(td_documentColor, DocumentColorParams,std::vector<ColorInformation>, "textDocument/documentColor");
\ No newline at end of file diff --git a/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/textDocument/document_link.h b/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/textDocument/document_link.h new file mode 100644 index 00000000000..536a625c4c9 --- /dev/null +++ b/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/textDocument/document_link.h @@ -0,0 +1,44 @@ +#pragma once + +#include "LibLsp/JsonRpc/RequestInMessage.h" +#include "LibLsp/JsonRpc/lsResponseMessage.h" + + +namespace TextDocumentDocumentLink { + + struct Params { + // The document to provide document links for. + lsTextDocumentIdentifier textDocument; + MAKE_SWAP_METHOD(Params, textDocument) + }; + +}; +MAKE_REFLECT_STRUCT(TextDocumentDocumentLink::Params, textDocument); + + + + +// A document link is a range in a text document that links to an internal or +// external resource, like another text document or a web site. +struct lsDocumentLink { + // The range this link applies to. + lsRange range; + // The uri this link points to. If missing a resolve request is sent later. + boost::optional<lsDocumentUri> target; + + boost::optional<lsp::Any> data; + + MAKE_SWAP_METHOD(lsDocumentLink, range, target, data) + +}; +MAKE_REFLECT_STRUCT(lsDocumentLink, range, target,data); + + +DEFINE_REQUEST_RESPONSE_TYPE(td_links, TextDocumentDocumentLink::Params, lsDocumentLink, "textDocument/documentLink"); + + +/** + * The document link resolve request is sent from the client to the server to resolve the target of a given document link. + */ +DEFINE_REQUEST_RESPONSE_TYPE(td_linkResolve, std::vector<lsDocumentLink>, lsDocumentLink, "documentLink/resolve"); + diff --git a/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/textDocument/document_symbol.h b/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/textDocument/document_symbol.h new file mode 100644 index 00000000000..8aa6e8b00e5 --- /dev/null +++ b/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/textDocument/document_symbol.h @@ -0,0 +1,55 @@ +#pragma once + + +#include "LibLsp/JsonRpc/RequestInMessage.h" +#include "LibLsp/JsonRpc/lsResponseMessage.h" + +#include "LibLsp/lsp/symbol.h" +#include "LibLsp/lsp/lsTextDocumentIdentifier.h" + /** + * The document symbol request is sent from the client to the server to list all symbols found in a given text document. + */ +struct lsDocumentSymbolParams { + lsTextDocumentIdentifier textDocument; + MAKE_SWAP_METHOD(lsDocumentSymbolParams, textDocument) +}; +MAKE_REFLECT_STRUCT(lsDocumentSymbolParams, textDocument); + + + +struct TextDocumentDocumentSymbol{ + typedef std::pair< boost::optional<lsSymbolInformation> , boost::optional<lsDocumentSymbol> > Either; +}; +void Reflect(Reader& visitor, TextDocumentDocumentSymbol::Either& value); + + + +/** + * The document symbol request is sent from the client to the server to list all + * symbols found in a given text document. + * + * Registration Options: {@link TextDocumentRegistrationOptions} + * + * <p> + * <b>Caveat</b>: although the return type allows mixing the + * {@link DocumentSymbol} and {@link SymbolInformation} instances into a list do + * not do it because the clients cannot accept a heterogeneous list. A list of + * {@code DocumentSymbol} instances is only a valid return value if the + * {@link DocumentSymbolCapabilities#getHierarchicalDocumentSymbolSupport() + * textDocument.documentSymbol.hierarchicalDocumentSymbolSupport} is + * {@code true}. More details on this difference between the LSP and the LSP4J + * can be found <a href="https://github.com/eclipse/lsp4j/issues/252">here</a>. + * </p> + */ + +//DEFINE_REQUEST_RESPONSE_TYPE(td_symbol, +// lsDocumentSymbolParams, +// std::vector<TextDocumentDocumentSymbol::Either> ); +// + +DEFINE_REQUEST_RESPONSE_TYPE(td_symbol, + lsDocumentSymbolParams, + std::vector< lsDocumentSymbol >,"textDocument/documentSymbol" ); + + + diff --git a/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/textDocument/foldingRange.h b/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/textDocument/foldingRange.h new file mode 100644 index 00000000000..27977a4517b --- /dev/null +++ b/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/textDocument/foldingRange.h @@ -0,0 +1,62 @@ +#pragma once + + +#include "LibLsp/JsonRpc/RequestInMessage.h" +#include "LibLsp/JsonRpc/lsResponseMessage.h" + +#include "document_symbol.h" +#include "LibLsp/lsp/lsTextDocumentIdentifier.h" + + +struct FoldingRangeRequestParams { + /** + * The text document. + */ + + lsTextDocumentIdentifier textDocument; + MAKE_SWAP_METHOD(FoldingRangeRequestParams, textDocument) +}; +MAKE_REFLECT_STRUCT(FoldingRangeRequestParams, textDocument) + + +struct FoldingRange { + /** + * The zero-based line number from where the folded range starts. + */ + int startLine; + + /** + * The zero-based line number where the folded range ends. + */ + int endLine; + + /** + * The zero-based character offset from where the folded range starts. If not defined, defaults + * to the length of the start line. + */ + int startCharacter; + + /** + * The zero-based character offset before the folded range ends. If not defined, defaults to the + * length of the end line. + */ + int endCharacter; + + /** + * Describes the kind of the folding range such as `comment' or 'region'. The kind + * is used to categorize folding ranges and used by commands like 'Fold all comments'. See + * FoldingRangeKind for an enumeration of standardized kinds. + */ + std::string kind; + + MAKE_SWAP_METHOD(FoldingRange, startLine, endLine, startCharacter, endCharacter, kind) +}; +MAKE_REFLECT_STRUCT(FoldingRange,startLine,endLine,startCharacter,endCharacter,kind) + + +/** + * The folding range request is sent from the client to the server to return all folding + * ranges found in a given text document. + */ +DEFINE_REQUEST_RESPONSE_TYPE(td_foldingRange, FoldingRangeRequestParams, std::vector<FoldingRange>, "textDocument/foldingRange"); + diff --git a/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/textDocument/formatting.h b/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/textDocument/formatting.h new file mode 100644 index 00000000000..ad54e24bf96 --- /dev/null +++ b/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/textDocument/formatting.h @@ -0,0 +1,32 @@ +#pragma once +#include "LibLsp/lsp/lsFormattingOptions.h" + +#include "LibLsp/JsonRpc/RequestInMessage.h" +#include "LibLsp/JsonRpc/lsResponseMessage.h" + + +namespace TextDocumentFormatting { + + struct Params { + /** + * The document to format. + */ + lsTextDocumentIdentifier textDocument; + /** + * The format options. + */ + lsFormattingOptions options; + MAKE_SWAP_METHOD(Params, textDocument, options); + }; + +}; +MAKE_REFLECT_STRUCT(TextDocumentFormatting::Params, textDocument, options); +/** + * The document formatting request is sent from the client to the server to + * format a whole document. + * + * Registration Options: TextDocumentRegistrationOptions + */ +DEFINE_REQUEST_RESPONSE_TYPE(td_formatting, TextDocumentFormatting::Params, + std::vector<lsTextEdit>, "textDocument/formatting"); + diff --git a/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/textDocument/highlight.h b/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/textDocument/highlight.h new file mode 100644 index 00000000000..332baf69e16 --- /dev/null +++ b/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/textDocument/highlight.h @@ -0,0 +1,18 @@ +#pragma once + +#include "LibLsp/JsonRpc/RequestInMessage.h" +#include "LibLsp/JsonRpc/lsResponseMessage.h" +#include "LibLsp/lsp/lsTextDocumentPositionParams.h" +#include "document_symbol.h" + +/** + * The references request is sent from the client to the server to resolve + * project-wide references for the symbol denoted by the given text document + * position. + * + * Registration Options: TextDocumentRegistrationOptions + */ + +DEFINE_REQUEST_RESPONSE_TYPE(td_highlight, lsTextDocumentPositionParams, + std::vector<lsDocumentHighlight>, "textDocument/documentHighlight"); + diff --git a/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/textDocument/hover.h b/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/textDocument/hover.h new file mode 100644 index 00000000000..5302316c6f5 --- /dev/null +++ b/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/textDocument/hover.h @@ -0,0 +1,55 @@ +#pragma once + + +#include "LibLsp/JsonRpc/RequestInMessage.h" +#include "LibLsp/JsonRpc/lsResponseMessage.h" + +#include "LibLsp/lsp/lsMarkedString.h" +#include "LibLsp/lsp/lsTextDocumentPositionParams.h" +#include "LibLsp/lsp/lsRange.h" +/** + * The hover request is sent from the client to the server to request hover + * information at a given text document position. + * + * Registration Options: TextDocumentRegistrationOptions + */ + +namespace TextDocumentHover +{ + typedef boost::optional< std::vector< std::pair<boost::optional<std::string>, boost::optional<lsMarkedString>> > > Left; + typedef std::pair< Left, boost::optional<MarkupContent> > Either; + struct Result { + /** + * The hover's content as markdown + */ + Either contents; + + /** + * An boost::optional range + */ + boost::optional<lsRange> range; + + MAKE_SWAP_METHOD(Result, contents, range) + }; +} +MAKE_REFLECT_STRUCT(TextDocumentHover::Result, contents, range); + +extern void Reflect(Reader& visitor, std::pair<boost::optional<std::string>, boost::optional<lsMarkedString>>& value); +extern void Reflect(Reader& visitor, TextDocumentHover::Either& value); + + +DEFINE_REQUEST_RESPONSE_TYPE(td_hover, lsTextDocumentPositionParams, TextDocumentHover::Result, "textDocument/hover") + +//struct Rsp_TextDocumentHover : ResponseMessage< TextDocumentHover::Result, Rsp_TextDocumentHover> { +// +//}; +//MAKE_REFLECT_STRUCT(Rsp_TextDocumentHover, +// jsonrpc, +// id, +// result); + +//MAKE_REFLECT_STRUCT_OPTIONALS_MANDATORY(Rsp_TextDocumentHover, +// jsonrpc, +// id, +// result); + diff --git a/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/textDocument/implementation.h b/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/textDocument/implementation.h new file mode 100644 index 00000000000..0d7851cb819 --- /dev/null +++ b/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/textDocument/implementation.h @@ -0,0 +1,16 @@ +#pragma once + + +#include "LibLsp/JsonRpc/RequestInMessage.h" +#include "LibLsp/lsp/out_list.h" + + +/** + * The goto implementation request is sent from the client to the server to resolve + * the implementation location of a symbol at a given text document position. + * + * Registration Options: TextDocumentRegistrationOptions + * + * Since version 3.6.0 + */ +DEFINE_REQUEST_RESPONSE_TYPE(td_implementation, lsTextDocumentPositionParams, LocationListEither::Either, "textDocument/implementation");
\ No newline at end of file diff --git a/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/textDocument/linkedEditingRange.h b/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/textDocument/linkedEditingRange.h new file mode 100644 index 00000000000..e4055d359ff --- /dev/null +++ b/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/textDocument/linkedEditingRange.h @@ -0,0 +1,51 @@ +#pragma once + + +#include "LibLsp/JsonRpc/RequestInMessage.h" +#include "LibLsp/JsonRpc/lsResponseMessage.h" +#include "LibLsp/lsp/lsAny.h" +#include "LibLsp/lsp/symbol.h" +#include "LibLsp/lsp/lsTextDocumentPositionParams.h" +#include "LibLsp/lsp/lsRange.h" + + + +struct LinkedEditingRangeParams +{ + lsTextDocumentIdentifier textDocument; + lsPosition position; + + MAKE_SWAP_METHOD(LinkedEditingRangeParams, + textDocument, + position) +}; +MAKE_REFLECT_STRUCT(LinkedEditingRangeParams, + textDocument, + position) + + +struct LinkedEditingRanges +{ + /** + * A list of ranges that can be renamed together. The ranges must have + * identical length and contain identical text content. The ranges cannot overlap. + */ + std::vector<lsRange> ranges; + + /** + * An optional word pattern (regular expression) that describes valid contents for + * the given ranges. If no pattern is provided, the client configuration's word + * pattern will be used. + */ + + boost::optional<std::string> wordPattern; + MAKE_SWAP_METHOD(LinkedEditingRanges, + ranges, + wordPattern) +}; + +MAKE_REFLECT_STRUCT(LinkedEditingRanges, + ranges, + wordPattern) +DEFINE_REQUEST_RESPONSE_TYPE(td_linkedEditingRange, LinkedEditingRangeParams, + boost::optional<std::vector<LinkedEditingRanges >>,"textDocument/linkedEditingRange")
\ No newline at end of file diff --git a/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/textDocument/onTypeFormatting.h b/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/textDocument/onTypeFormatting.h new file mode 100644 index 00000000000..df14ea5d3dd --- /dev/null +++ b/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/textDocument/onTypeFormatting.h @@ -0,0 +1,44 @@ +#pragma once + + +#include "LibLsp/JsonRpc/RequestInMessage.h" +#include "LibLsp/JsonRpc/lsResponseMessage.h" + +#include "LibLsp/lsp/lsFormattingOptions.h" +#include "LibLsp/lsp/lsTextDocumentIdentifier.h" +#include "LibLsp/lsp/lsRange.h" +#include "LibLsp/lsp/lsTextEdit.h" + + +struct lsDocumentOnTypeFormattingParams +{ + lsTextDocumentIdentifier textDocument; + lsFormattingOptions options; + + lsPosition position; + + /** + * The character that has been typed. + */ + + std::string ch; + + MAKE_SWAP_METHOD(lsDocumentOnTypeFormattingParams, + textDocument, + position, + options, ch); +}; +MAKE_REFLECT_STRUCT(lsDocumentOnTypeFormattingParams, + textDocument, + position, + options,ch); + +/** + * The document range formatting request is sent from the client to the + * server to format a given range in a document. + * + * Registration Options: TextDocumentRegistrationOptions + */ +DEFINE_REQUEST_RESPONSE_TYPE(td_onTypeFormatting, + lsDocumentOnTypeFormattingParams, std::vector<lsTextEdit>, "textDocument/onTypeFormatting"); + diff --git a/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/textDocument/prepareRename.h b/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/textDocument/prepareRename.h new file mode 100644 index 00000000000..8c653d9864b --- /dev/null +++ b/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/textDocument/prepareRename.h @@ -0,0 +1,40 @@ +#pragma once + +#include "LibLsp/JsonRpc/RequestInMessage.h" +#include "LibLsp/JsonRpc/lsResponseMessage.h" + +#include "LibLsp/lsp/lsWorkspaceEdit.h" +#include "LibLsp/lsp/lsTextDocumentPositionParams.h" + +/** + * The rename request is sent from the client to the server to do a + * workspace wide rename of a symbol. + * + * Registration Options: TextDocumentRegistrationOptions + */ +struct PrepareRenameResult{ + /** + * The range of the string to rename + */ + + lsRange range; + +/** + * A placeholder text of the string content to be renamed. + */ + + std::string placeholder; + + MAKE_SWAP_METHOD(PrepareRenameResult, range, placeholder) + +}; +MAKE_REFLECT_STRUCT(PrepareRenameResult,range,placeholder) + + + +typedef std::pair< boost::optional< lsRange>, boost::optional<PrepareRenameResult>> TextDocumentPrepareRenameResult; +extern void Reflect(Reader& visitor, TextDocumentPrepareRenameResult& value); + + +DEFINE_REQUEST_RESPONSE_TYPE(td_prepareRename, + lsTextDocumentPositionParams, TextDocumentPrepareRenameResult, "textDocument/prepareRename");
\ No newline at end of file diff --git a/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/textDocument/publishDiagnostics.h b/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/textDocument/publishDiagnostics.h new file mode 100644 index 00000000000..bf28104bbbf --- /dev/null +++ b/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/textDocument/publishDiagnostics.h @@ -0,0 +1,28 @@ +#pragma once + +#include "LibLsp/JsonRpc/NotificationInMessage.h" +#include "LibLsp/lsp/lsp_diagnostic.h" + +// Diagnostics +namespace TextDocumentPublishDiagnostics{ + struct Params { + // The URI for which diagnostic information is reported. + lsDocumentUri uri; + + // An array of diagnostic information items. + std::vector<lsDiagnostic> diagnostics; + MAKE_SWAP_METHOD(Params,uri,diagnostics); + }; + + +}; +MAKE_REFLECT_STRUCT(TextDocumentPublishDiagnostics::Params, + uri, + diagnostics); + +/** + * Diagnostics notifications are sent from the server to the client to + * signal results of validation runs. + */ +DEFINE_NOTIFICATION_TYPE(Notify_TextDocumentPublishDiagnostics, TextDocumentPublishDiagnostics::Params, "textDocument/publishDiagnostics"); + diff --git a/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/textDocument/range_formatting.h b/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/textDocument/range_formatting.h new file mode 100644 index 00000000000..b2fe750af15 --- /dev/null +++ b/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/textDocument/range_formatting.h @@ -0,0 +1,35 @@ +#pragma once + + +#include "LibLsp/JsonRpc/RequestInMessage.h" +#include "LibLsp/JsonRpc/lsResponseMessage.h" + +#include "LibLsp/lsp/lsFormattingOptions.h" + + +struct lsTextDocumentRangeFormattingParams { + lsTextDocumentIdentifier textDocument; + lsRange range; + lsFormattingOptions options; + + MAKE_SWAP_METHOD(lsTextDocumentRangeFormattingParams, + textDocument, + range, + options) +}; +MAKE_REFLECT_STRUCT(lsTextDocumentRangeFormattingParams, + textDocument, + range, + options); + +/** + * The document range formatting request is sent from the client to the + * server to format a given range in a document. + * + * Registration Options: TextDocumentRegistrationOptions + */ +DEFINE_REQUEST_RESPONSE_TYPE(td_rangeFormatting, lsTextDocumentRangeFormattingParams, std::vector<lsTextEdit>, + "textDocument/rangeFormatting"); + + + diff --git a/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/textDocument/references.h b/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/textDocument/references.h new file mode 100644 index 00000000000..23769127565 --- /dev/null +++ b/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/textDocument/references.h @@ -0,0 +1,48 @@ +#pragma once + + +#include "LibLsp/JsonRpc/RequestInMessage.h" +#include "LibLsp/JsonRpc/lsResponseMessage.h" + +#include "LibLsp/lsp/symbol.h" + + +namespace TextDocumentReferences { + + struct lsReferenceContext { + // Include the declaration of the current symbol. + boost::optional<bool> includeDeclaration; + MAKE_REFLECT_STRUCT(lsReferenceContext, + includeDeclaration) + }; + struct Params { + lsTextDocumentIdentifier textDocument; + lsPosition position; + lsReferenceContext context; + MAKE_SWAP_METHOD(Params, + textDocument, + position, + context) + + }; + +}; +MAKE_REFLECT_STRUCT(TextDocumentReferences::lsReferenceContext, + includeDeclaration); +MAKE_REFLECT_STRUCT(TextDocumentReferences::Params, + textDocument, + position, + context); + + + + +/** + * The references request is sent from the client to the server to resolve + * project-wide references for the symbol denoted by the given text document + * position. + * + * Registration Options: TextDocumentRegistrationOptions + */ +DEFINE_REQUEST_RESPONSE_TYPE(td_references, TextDocumentReferences::Params, + std::vector<lsLocation>, "textDocument/references"); diff --git a/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/textDocument/rename.h b/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/textDocument/rename.h new file mode 100644 index 00000000000..35895f0f4f6 --- /dev/null +++ b/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/textDocument/rename.h @@ -0,0 +1,41 @@ +#pragma once + + +#include "LibLsp/JsonRpc/RequestInMessage.h" +#include "LibLsp/JsonRpc/lsResponseMessage.h" + +#include "LibLsp/lsp/lsWorkspaceEdit.h" +#include "LibLsp/lsp/lsTextDocumentIdentifier.h" + +namespace TextDocumentRename { + + struct Params { + // The document to format. + lsTextDocumentIdentifier textDocument; + + // The position at which this request was sent. + lsPosition position; + + // The new name of the symbol. If the given name is not valid the + // request must return a [ResponseError](#ResponseError) with an + // appropriate message set. + std::string newName; + MAKE_SWAP_METHOD(Params, + textDocument, + position, + newName); + }; + +}; +MAKE_REFLECT_STRUCT(TextDocumentRename::Params, + textDocument, + position, + newName); +/** + * The rename request is sent from the client to the server to do a + * workspace wide rename of a symbol. + * + * Registration Options: TextDocumentRegistrationOptions + */ +DEFINE_REQUEST_RESPONSE_TYPE(td_rename, TextDocumentRename::Params, lsWorkspaceEdit, "textDocument/rename"); + diff --git a/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/textDocument/resolveCodeLens.h b/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/textDocument/resolveCodeLens.h new file mode 100644 index 00000000000..07239851608 --- /dev/null +++ b/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/textDocument/resolveCodeLens.h @@ -0,0 +1,10 @@ +#pragma once + + +#include "LibLsp/JsonRpc/RequestInMessage.h" +#include "LibLsp/JsonRpc/lsResponseMessage.h" + +#include "code_lens.h" + +DEFINE_REQUEST_RESPONSE_TYPE(codeLens_resolve, lsCodeLens, lsCodeLens, "codeLens/resolve") + diff --git a/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/textDocument/resolveCompletionItem.h b/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/textDocument/resolveCompletionItem.h new file mode 100644 index 00000000000..f5576894ede --- /dev/null +++ b/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/textDocument/resolveCompletionItem.h @@ -0,0 +1,21 @@ +#pragma once + + +#include "LibLsp/JsonRpc/RequestInMessage.h" +#include "LibLsp/JsonRpc/lsResponseMessage.h" + +#include <regex> +#include "LibLsp/lsp/lsp_completion.h" +#include "LibLsp/lsp/lsTextDocumentPositionParams.h" +#include "completion.h" + +/** + * The request is sent from the client to the server to resolve additional + * information for a given completion item. + */ +DEFINE_REQUEST_RESPONSE_TYPE(completionItem_resolve, lsCompletionItem, lsCompletionItem, "completionItem/resolve"); + + + + + diff --git a/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/textDocument/resolveTypeHierarchy.h b/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/textDocument/resolveTypeHierarchy.h new file mode 100644 index 00000000000..eab5f838fcd --- /dev/null +++ b/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/textDocument/resolveTypeHierarchy.h @@ -0,0 +1,31 @@ +#pragma once + + + +#include "LibLsp/JsonRpc/RequestInMessage.h" +#include "LibLsp/JsonRpc/lsResponseMessage.h" + +#include "LibLsp/lsp/symbol.h" +#include "typeHierarchy.h" + +struct ResolveTypeHierarchyItemParams { + /** + * The hierarchy item to resolve. + */ + + TypeHierarchyItem item; + + /** + * The number of hierarchy levels to resolve. {@code 0} indicates no hierarchy level. + */ + boost::optional<int> resolve; + + /** + * The direction of the type hierarchy resolution. + */ + + TypeHierarchyDirection direction; + MAKE_SWAP_METHOD(ResolveTypeHierarchyItemParams, item, resolve, direction) +}; +MAKE_REFLECT_STRUCT(ResolveTypeHierarchyItemParams,item,resolve,direction) +DEFINE_REQUEST_RESPONSE_TYPE(typeHierarchy_resolve, ResolveTypeHierarchyItemParams, TypeHierarchyItem, "typeHierarchy/resolve") diff --git a/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/textDocument/selectionRange.h b/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/textDocument/selectionRange.h new file mode 100644 index 00000000000..47590e41522 --- /dev/null +++ b/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/textDocument/selectionRange.h @@ -0,0 +1,52 @@ +#pragma once + + +#include "LibLsp/JsonRpc/RequestInMessage.h" +#include "LibLsp/JsonRpc/lsResponseMessage.h" + +#include "LibLsp/lsp/lsPosition.h" +#include "LibLsp/lsp/lsTextDocumentIdentifier.h" + +struct SelectionRangeParams { + /** + * The text document. + */ + + lsTextDocumentIdentifier textDocument; + + /** + * The positions inside the text document. + */ + + std::vector<lsPosition> positions; + + MAKE_SWAP_METHOD(SelectionRangeParams, textDocument, positions) + +}; +MAKE_REFLECT_STRUCT(SelectionRangeParams, textDocument, positions) + +struct SelectionRange { + /** + * The [range](#Range) of this selection range. + */ + + lsRange range; + + /** + * The parent selection range containing this range. Therefore `parent.range` must contain `this.range`. + */ + boost::optional<SelectionRange*> parent; + MAKE_SWAP_METHOD(SelectionRange, range, parent) +}; + +extern void Reflect(Reader& visitor, boost::optional<SelectionRange*>& value); +extern void Reflect(Writer& visitor, SelectionRange* value); + +MAKE_REFLECT_STRUCT(SelectionRange,range,parent) +/** + * The {@code textDocument/selectionRange} request is sent from the client to the server to return + * suggested selection ranges at an array of given positions. A selection range is a range around + * the cursor position which the user might be interested in selecting. + */ +DEFINE_REQUEST_RESPONSE_TYPE(td_selectionRange, SelectionRangeParams, std::vector<SelectionRange>, "textDocument/selectionRange"); + diff --git a/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/textDocument/semanticHighlighting.h b/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/textDocument/semanticHighlighting.h new file mode 100644 index 00000000000..32bc86f5fb7 --- /dev/null +++ b/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/textDocument/semanticHighlighting.h @@ -0,0 +1,66 @@ +#pragma once +#include "LibLsp/lsp/lsDocumentUri.h" +#include "LibLsp/lsp/lsVersionedTextDocumentIdentifier.h" + +#include "LibLsp/JsonRpc/NotificationInMessage.h" +#include "LibLsp/JsonRpc/lsResponseMessage.h" + +/** + * Represents a semantic highlighting information that has to be applied on a specific line of the text document. + */ + +struct SemanticHighlightingInformation { + /** + * The zero-based line position in the text document. + */ + int line = 0; + + /** + * A base64 encoded string representing every single highlighted ranges in the line with its start position, length + * and the "lookup table" index of of the semantic highlighting <a href="https://manual.macromates.com/en/language_grammars"> + * TextMate scopes</a>. If the {@code tokens} is empty or not defined, then no highlighted positions are available for the line. + */ + std::string tokens; + + MAKE_SWAP_METHOD(SemanticHighlightingInformation, line, tokens) +}; + +MAKE_REFLECT_STRUCT(SemanticHighlightingInformation, line, tokens); + +/** + * Parameters for the semantic highlighting (server-side) push notification. + */ + +struct SemanticHighlightingParams { + /** + * The text document that has to be decorated with the semantic highlighting information. + */ + + lsVersionedTextDocumentIdentifier textDocument; + + /** + * An array of semantic highlighting information. + */ + + std::vector<SemanticHighlightingInformation> lines; + + MAKE_SWAP_METHOD(SemanticHighlightingParams, textDocument, lines) + +}; +MAKE_REFLECT_STRUCT(SemanticHighlightingParams, textDocument, lines); +/** + * The {@code textDocument/semanticHighlighting} notification is pushed from the server to the client + * to inform the client about additional semantic highlighting information that has to be applied + * on the text document. It is the server's responsibility to decide which lines are included in + * the highlighting information. In other words, the server is capable of sending only a delta + * information. For instance, after opening the text document ({@code DidOpenTextDocumentNotification}) + * the server sends the semantic highlighting information for the entire document, but if the server + * receives a {@code DidChangeTextDocumentNotification}, it pushes the information only about + * the affected lines in the document. + * + * <p> + * <b>Note:</b> the <a href= + * "https://github.com/Microsoft/vscode-languageserver-node/pull/367">{@code textDocument/semanticHighlighting} + * language feature</a> is not yet part of the official LSP specification. + */ +DEFINE_NOTIFICATION_TYPE(Notify_semanticHighlighting, SemanticHighlightingParams, "textDocument/semanticHighlighting");
\ No newline at end of file diff --git a/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/textDocument/signature_help.h b/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/textDocument/signature_help.h new file mode 100644 index 00000000000..2a83645901c --- /dev/null +++ b/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/textDocument/signature_help.h @@ -0,0 +1,92 @@ +#pragma once + + +#include "LibLsp/JsonRpc/RequestInMessage.h" +#include "LibLsp/JsonRpc/lsResponseMessage.h" +#include "LibLsp/lsp/lsMarkedString.h" +#include "LibLsp/lsp/lsTextDocumentPositionParams.h" + +extern void Reflect(Reader& visitor, + std::pair<boost::optional<std::string>, boost::optional<MarkupContent>>& value); + + + +// Represents a parameter of a callable-signature. A parameter can +// have a label and a doc-comment. +struct lsParameterInformation { + // The label of this parameter. Will be shown in + // the UI. + std::string label; + + // The human-readable doc-comment of this parameter. Will be shown + // in the UI but can be omitted. + boost::optional< std::pair< boost::optional<std::string> , boost::optional <MarkupContent> > > documentation; + + MAKE_SWAP_METHOD(lsParameterInformation, label, documentation) +}; +MAKE_REFLECT_STRUCT(lsParameterInformation, label, documentation); + +// Represents the signature of something callable. A signature +// can have a label, like a function-name, a doc-comment, and +// a set of parameters. +struct lsSignatureInformation { + // The label of this signature. Will be shown in + // the UI. + std::string label; + + // The human-readable doc-comment of this signature. Will be shown + // in the UI but can be omitted. + boost::optional< std::pair< boost::optional<std::string>, boost::optional <MarkupContent> > > documentation; + + // The parameters of this signature. + std::vector<lsParameterInformation> parameters; + + MAKE_SWAP_METHOD(lsSignatureInformation, label, documentation, parameters) +}; +MAKE_REFLECT_STRUCT(lsSignatureInformation, label, documentation, parameters); + +// Signature help represents the signature of something +// callable. There can be multiple signature but only one +// active and only one active parameter. +struct lsSignatureHelp { + // One or more signatures. + std::vector<lsSignatureInformation> signatures; + + // The active signature. If omitted or the value lies outside the + // range of `signatures` the value defaults to zero or is ignored if + // `signatures.length === 0`. Whenever possible implementors should + // make an active decision about the active signature and shouldn't + // rely on a default value. + // In future version of the protocol this property might become + // mandantory to better express this. + boost::optional<int> activeSignature; + + // The active parameter of the active signature. If omitted or the value + // lies outside the range of `signatures[activeSignature].parameters` + // defaults to 0 if the active signature has parameters. If + // the active signature has no parameters it is ignored. + // In future version of the protocol this property might become + // mandantory to better express the active parameter if the + // active signature does have any. + boost::optional<int> activeParameter; + + + MAKE_SWAP_METHOD(lsSignatureHelp, + signatures, + activeSignature, + activeParameter) +}; +MAKE_REFLECT_STRUCT(lsSignatureHelp, + signatures, + activeSignature, + activeParameter); + + + +/** + * The signature help request is sent from the client to the server to + * request signature information at a given cursor position. + * + * Registration Options: SignatureHelpRegistrationOptions + */ +DEFINE_REQUEST_RESPONSE_TYPE(td_signatureHelp, lsTextDocumentPositionParams, lsSignatureHelp, "textDocument/signatureHelp");
\ No newline at end of file diff --git a/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/textDocument/textDocument.cpp b/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/textDocument/textDocument.cpp new file mode 100644 index 00000000000..32f647436d1 --- /dev/null +++ b/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/textDocument/textDocument.cpp @@ -0,0 +1,349 @@ +#include "completion.h" +#include "document_symbol.h" +#include "LibLsp/lsp/lsMarkedString.h" +#include "hover.h" +#include "prepareRename.h" +#include <LibLsp/lsp/textDocument/typeHierarchy.h> + +#include "semanticHighlighting.h" +#include "SemanticTokens.h" +#include "LibLsp/JsonRpc/json.h" + + +constexpr unsigned SemanticTokenEncodingSize = 5; + +std::string to_string(SemanticTokenType _type) +{ + switch (_type) { + + case ls_namespace: return "namespace"; + /** + * Represents a generic type. Acts as a fallback for types which + * can"t be mapped to a specific type like class or enum. + */ + case ls_type: return "type"; + case ls_class: return "class"; + case ls_enum: return "enum"; + case ls_interface: return "interface"; + case ls_struct: return "struct"; + case ls_typeParameter: return "typeParameter"; + case ls_parameter: return "parameter"; + case ls_variable: return "variable"; + case ls_property: return "property"; + case ls_enumMember: return "enumMember"; + case ls_event: return "event"; + case ls_function: return "function"; + case ls_method: return "method"; + case ls_macro: return "macro"; + case ls_keyword: return "keyword"; + case ls_modifier: return "modifier"; + case ls_comment: return "comment"; + case ls_string: return "string"; + case ls_number: return "number"; + case ls_regexp: return "regexp"; + case ls_operator: return "operator"; + default: + return "unknown"; + } +} + +unsigned toSemanticTokenType(std::vector<SemanticTokenType>& modifiers) +{ + unsigned encode_type = 0; + for (auto bit : modifiers) { + encode_type = encode_type | (0b00000001 << bit); + } + return encode_type; +} + +std::string to_string(TokenType_JDT _type) +{ + switch (_type) + { + case PACKAGE_JDT:return "namespace"; + case CLASS_JDT:return "class"; + case INTERFACE_JDT:return "interface"; + case ENUM_JDT:return "enum"; + case ENUM_MEMBER_JDT:return "enumMember"; + case TYPE_JDT:return "type"; + case TYPE_PARAMETER_JDT:return "typeParameter"; + case ANNOTATION_JDT:return "annotation"; + case ANNOTATION_MEMBER_JDT:return "annotationMember"; + case METHOD_JDT:return "function"; + case PROPERTY_JDT:return "property"; + case VARIABLE_JDT:return "variable"; + case PARAMETER_JDT:return "parameter"; + } + return "unknown"; +} + +std::string to_string(SemanticTokenModifier modifier) +{ + switch (modifier) { + case ls_declaration: return "declaration"; + case ls_definition: return "definition"; + case ls_readonly: return "readonly"; + case ls_static: return "static"; + case ls_deprecated: return "deprecated"; + case ls_abstract: return "abstract"; + case ls_async: return "async"; + case ls_modification: return "modification"; + case ls_documentation: return "documentation"; + case ls_defaultLibrary: return "defaultLibrary"; + default: + return "unknown"; + } +} + +unsigned toSemanticTokenModifiers(std::vector<SemanticTokenModifier>& modifiers) +{ + unsigned encodedModifiers = 0; + for (auto bit : modifiers) { + encodedModifiers = encodedModifiers | (0b00000001 << bit); + } + return encodedModifiers; +} + + +std::string toSemanticTokenType(HighlightingKind_clangD kind) { + switch (kind) { + case HighlightingKind_clangD::Variable: + case HighlightingKind_clangD::LocalVariable: + case HighlightingKind_clangD::StaticField: + return "variable"; + case HighlightingKind_clangD::Parameter: + return "parameter"; + case HighlightingKind_clangD::Function: + return "function"; + case HighlightingKind_clangD::Method: + return "method"; + case HighlightingKind_clangD::StaticMethod: + // FIXME: better method with static modifier? + return "function"; + case HighlightingKind_clangD::Field: + return "property"; + case HighlightingKind_clangD::Class: + return "class"; + case HighlightingKind_clangD::Interface: + return "interface"; + case HighlightingKind_clangD::Enum: + return "enum"; + case HighlightingKind_clangD::EnumConstant: + return "enumMember"; + case HighlightingKind_clangD::Typedef: + case HighlightingKind_clangD::Type: + return "type"; + case HighlightingKind_clangD::Unknown: + return "unknown"; // nonstandard + case HighlightingKind_clangD::Namespace: + return "namespace"; + case HighlightingKind_clangD::TemplateParameter: + return "typeParameter"; + case HighlightingKind_clangD::Concept: + return "concept"; // nonstandard + case HighlightingKind_clangD::Primitive: + return "type"; + case HighlightingKind_clangD::Macro: + return "macro"; + case HighlightingKind_clangD::InactiveCode: + return "comment"; + } + return ("unhandled HighlightingKind_clangD"); +} + +std::string toSemanticTokenModifier(HighlightingModifier_clangD modifier) { + switch (modifier) { + case HighlightingModifier_clangD::Declaration: + return "declaration"; + case HighlightingModifier_clangD::Deprecated: + return "deprecated"; + case HighlightingModifier_clangD::Readonly: + return "readonly"; + case HighlightingModifier_clangD::Static: + return "static"; + case HighlightingModifier_clangD::Deduced: + return "deduced"; // nonstandard + case HighlightingModifier_clangD::Abstract: + return "abstract"; + case HighlightingModifier_clangD::DependentName: + return "dependentName"; // nonstandard + case HighlightingModifier_clangD::DefaultLibrary: + return "defaultLibrary"; + case HighlightingModifier_clangD::FunctionScope: + return "functionScope"; // nonstandard + case HighlightingModifier_clangD::ClassScope: + return "classScope"; // nonstandard + case HighlightingModifier_clangD::FileScope: + return "fileScope"; // nonstandard + case HighlightingModifier_clangD::GlobalScope: + return "globalScope"; // nonstandard + } + return ("unhandled HighlightingModifier_clangD"); +} + + + +bool operator==(const SemanticToken& l, const SemanticToken& r) { + return std::tie(l.deltaLine, l.deltaStart, l.length, l.tokenType, + l.tokenModifiers) == std::tie(r.deltaLine, r.deltaStart, + r.length, r.tokenType, + r.tokenModifiers); +} + +std::vector<int32_t> SemanticTokens::encodeTokens(std::vector<SemanticToken>& tokens) +{ + std::vector<int32_t> result; + result.reserve(SemanticTokenEncodingSize * tokens.size()); + for (const auto& tok : tokens) + { + result.push_back(tok.deltaLine); + result.push_back(tok.deltaStart); + result.push_back(tok.length); + result.push_back(tok.tokenType); + result.push_back(tok.tokenModifiers); + } + assert(result.size() == SemanticTokenEncodingSize * tokens.size()); + return result; +} + +void Reflect(Reader& visitor, TextDocumentComplete::Either& value) +{ + if(visitor.IsArray()) + { + Reflect(visitor, value.first); + } + else + { + + Reflect(visitor, value.second); + } + +} +void Reflect(Reader& visitor, TextDocumentDocumentSymbol::Either& value) +{ + if (visitor.HasMember("location")) + { + Reflect(visitor, value.first); + } + else + { + Reflect(visitor, value.second); + } +} + +void Reflect(Reader& visitor, std::pair<boost::optional<std::string>, boost::optional<lsMarkedString>>& value) +{ + + if (!visitor.IsString()) + { + Reflect(visitor, value.second); + } + else + { + Reflect(visitor, value.first); + } +} + +void Reflect(Reader& visitor, std::pair<boost::optional<std::string>, boost::optional<MarkupContent>>& value) +{ + if (!visitor.IsString()) + { + Reflect(visitor, value.second); + } + else + { + Reflect(visitor, value.first); + } +} + void Reflect(Reader& visitor, TextDocumentHover::Either& value) +{ + JsonReader& reader = dynamic_cast<JsonReader&>(visitor); + if (reader.IsArray()) + { + Reflect(visitor, value.first); + } + else if(reader.m_->IsObject()) + { + Reflect(visitor, value.second); + } +} + + void Reflect(Reader& visitor, TextDocumentPrepareRenameResult& value) +{ + if (visitor.HasMember("placeholder")) + { + Reflect(visitor, value.second); + } + else + { + Reflect(visitor, value.first); + } +} + + namespace + RefactorProposalUtility + { + const char* APPLY_REFACTORING_COMMAND_ID = "java.action.applyRefactoringCommand"; + const char* EXTRACT_VARIABLE_ALL_OCCURRENCE_COMMAND = "extractVariableAllOccurrence"; + const char* EXTRACT_VARIABLE_COMMAND = "extractVariable"; + const char* EXTRACT_CONSTANT_COMMAND = "extractConstant"; + const char* EXTRACT_METHOD_COMMAND = "extractMethod"; + const char* EXTRACT_FIELD_COMMAND = "extractField"; + const char* CONVERT_VARIABLE_TO_FIELD_COMMAND = "convertVariableToField"; + const char* MOVE_FILE_COMMAND = "moveFile"; + const char* MOVE_INSTANCE_METHOD_COMMAND = "moveInstanceMethod"; + const char* MOVE_STATIC_MEMBER_COMMAND = "moveStaticMember"; + const char* MOVE_TYPE_COMMAND = "moveType"; + }; + namespace QuickAssistProcessor { + + const char* SPLIT_JOIN_VARIABLE_DECLARATION_ID = "org.eclipse.jdt.ls.correction.splitJoinVariableDeclaration.assist"; //$NON-NLS-1$ + const char* CONVERT_FOR_LOOP_ID = "org.eclipse.jdt.ls.correction.convertForLoop.assist"; //$NON-NLS-1$ + const char* ASSIGN_TO_LOCAL_ID = "org.eclipse.jdt.ls.correction.assignToLocal.assist"; //$NON-NLS-1$ + const char* ASSIGN_TO_FIELD_ID = "org.eclipse.jdt.ls.correction.assignToField.assist"; //$NON-NLS-1$ + const char* ASSIGN_PARAM_TO_FIELD_ID = "org.eclipse.jdt.ls.correction.assignParamToField.assist"; //$NON-NLS-1$ + const char* ASSIGN_ALL_PARAMS_TO_NEW_FIELDS_ID = "org.eclipse.jdt.ls.correction.assignAllParamsToNewFields.assist"; //$NON-NLS-1$ + const char* ADD_BLOCK_ID = "org.eclipse.jdt.ls.correction.addBlock.assist"; //$NON-NLS-1$ + const char* EXTRACT_LOCAL_ID = "org.eclipse.jdt.ls.correction.extractLocal.assist"; //$NON-NLS-1$ + const char* EXTRACT_LOCAL_NOT_REPLACE_ID = "org.eclipse.jdt.ls.correction.extractLocalNotReplaceOccurrences.assist"; //$NON-NLS-1$ + const char* EXTRACT_CONSTANT_ID = "org.eclipse.jdt.ls.correction.extractConstant.assist"; //$NON-NLS-1$ + const char* INLINE_LOCAL_ID = "org.eclipse.jdt.ls.correction.inlineLocal.assist"; //$NON-NLS-1$ + const char* CONVERT_LOCAL_TO_FIELD_ID = "org.eclipse.jdt.ls.correction.convertLocalToField.assist"; //$NON-NLS-1$ + const char* CONVERT_ANONYMOUS_TO_LOCAL_ID = "org.eclipse.jdt.ls.correction.convertAnonymousToLocal.assist"; //$NON-NLS-1$ + const char* CONVERT_TO_STRING_BUFFER_ID = "org.eclipse.jdt.ls.correction.convertToStringBuffer.assist"; //$NON-NLS-1$ + const char* CONVERT_TO_MESSAGE_FORMAT_ID = "org.eclipse.jdt.ls.correction.convertToMessageFormat.assist"; //$NON-NLS-1$; + const char* EXTRACT_METHOD_INPLACE_ID = "org.eclipse.jdt.ls.correction.extractMethodInplace.assist"; //$NON-NLS-1$; + + const char* CONVERT_ANONYMOUS_CLASS_TO_NESTED_COMMAND = "convertAnonymousClassToNestedCommand"; + }; + + void Reflect(Reader& reader, TypeHierarchyDirection& value) { + if (!reader.IsString()) + { + value = TypeHierarchyDirection::Both; + return; + } + std::string v = reader.GetString(); + if (v == "Children") + value = TypeHierarchyDirection::Both; + else if (v == "Parents") + value = TypeHierarchyDirection::Parents; + else if (v == "Both") + value = TypeHierarchyDirection::Both; + } + + + void Reflect(Writer& writer, TypeHierarchyDirection& value) { + switch (value) + { + case TypeHierarchyDirection::Children: + writer.String("Children"); + break; + case TypeHierarchyDirection::Parents: + writer.String("Parents"); + break; + case TypeHierarchyDirection::Both: + writer.String("Both"); + break; + } + } diff --git a/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/textDocument/typeHierarchy.h b/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/textDocument/typeHierarchy.h new file mode 100644 index 00000000000..b554d751f3a --- /dev/null +++ b/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/textDocument/typeHierarchy.h @@ -0,0 +1,133 @@ +#pragma once + +#include "LibLsp/JsonRpc/RequestInMessage.h" +#include "LibLsp/JsonRpc/lsResponseMessage.h" +#include "LibLsp/lsp/lsTextDocumentPositionParams.h" +#include "LibLsp/lsp/symbol.h" +#include "LibLsp/lsp/lsAny.h" +/** + * The {@code textDocument/typeHierarchy} request is sent from the client to the + * server to retrieve a {@link TypeHierarchyItem type hierarchy item} based on + * the {@link TypeHierarchyParams cursor position in the text document}. This + * request would also allow to specify if the item should be resolved and + * whether sub- or supertypes are to be resolved. If no type hierarchy item can + * be found under the given text document position, resolves to {@code null}. + * + * <p> + * <b>Note:</b> the <a href= + * "https://github.com/Microsoft/vscode-languageserver-node/pull/426">{@code textDocument/typeHierarchy} + * language feature</a> is not yet part of the official LSP specification. + */ +enum class TypeHierarchyDirection : uint32_t{ + + /** + * Flag for retrieving/resolving the subtypes. Value: {@code 0}. + */ + Children = 0, + + /** + * Flag to use when retrieving/resolving the supertypes. Value: {@code 1}. + */ + Parents =1, + + /** + * Flag for resolving both the super- and subtypes. Value: {@code 2}. + */ + Both=2 +}; +void Reflect(Reader& reader, TypeHierarchyDirection& value); + + +void Reflect(Writer& writer, TypeHierarchyDirection& value); + +struct TypeHierarchyParams :public lsTextDocumentPositionParams +{ + boost::optional<int> resolve; + boost::optional<TypeHierarchyDirection> direction ; + + MAKE_SWAP_METHOD(TypeHierarchyParams, textDocument, position, resolve, direction) +}; +MAKE_REFLECT_STRUCT(TypeHierarchyParams, textDocument, position, resolve, direction); + + + + + +/** + * Representation of an item that carries type information (such as class, interface, enumeration, etc) with additional parentage details. + */ + +struct TypeHierarchyItem { + /** + * The human readable name of the hierarchy item. + */ + + std::string name; + + /** + * Optional detail for the hierarchy item. It can be, for instance, the signature of a function or method. + */ + boost::optional<std::string> + detail; + + /** + * The kind of the hierarchy item. For instance, class or interface. + */ + + SymbolKind kind; + + /** + * {@code true} if the hierarchy item is deprecated. Otherwise, {@code false}. It is {@code false} by default. + */ + + boost::optional<bool> deprecated; + + /** + * The URI of the text document where this type hierarchy item belongs to. + */ + + lsDocumentUri uri; + + /** + * The range enclosing this type hierarchy item not including leading/trailing whitespace but everything else + * like comments. This information is typically used to determine if the clients cursor is inside the type + * hierarchy item to reveal in the symbol in the UI. + * + * @see TypeHierarchyItem#selectionRange + */ + + lsRange range; + + /** + * The range that should be selected and revealed when this type hierarchy item is being picked, e.g the name of a function. + * Must be contained by the the {@link TypeHierarchyItem#getRange range}. + * + * @see TypeHierarchyItem#range + */ + + lsRange selectionRange; + + /** + * If this type hierarchy item is resolved, it contains the direct parents. Could be empty if the item does not have any + * direct parents. If not defined, the parents have not been resolved yet. + */ + boost::optional< std::vector<TypeHierarchyItem> > parents; + + /** + * If this type hierarchy item is resolved, it contains the direct children of the current item. + * Could be empty if the item does not have any descendants. If not defined, the children have not been resolved. + */ + boost::optional< std::vector<TypeHierarchyItem> > children; + + /** + * An boost::optional data field can be used to identify a type hierarchy item in a resolve request. + */ + boost::optional<lsp::Any> data; + + MAKE_SWAP_METHOD(TypeHierarchyItem, name, detail, kind, deprecated, uri, range, selectionRange, parents, children, data) +}; +MAKE_REFLECT_STRUCT(TypeHierarchyItem, name, detail, kind, deprecated, uri, range, selectionRange, parents, children, data); + + + +DEFINE_REQUEST_RESPONSE_TYPE(td_typeHierarchy, TypeHierarchyParams, TypeHierarchyItem, "textDocument/typeHierarchy");
\ No newline at end of file diff --git a/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/textDocument/type_definition.h b/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/textDocument/type_definition.h new file mode 100644 index 00000000000..38ced43b42d --- /dev/null +++ b/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/textDocument/type_definition.h @@ -0,0 +1,16 @@ +#pragma once + + +#include "LibLsp/JsonRpc/RequestInMessage.h" +#include "LibLsp/lsp/out_list.h" + +/** + * The goto type definition request is sent from the client to the server to resolve + * the type definition location of a symbol at a given text document position. + * + * Registration Options: TextDocumentRegistrationOptions + * + * Since version 3.6.0 + */ +DEFINE_REQUEST_RESPONSE_TYPE(td_typeDefinition, + lsTextDocumentPositionParams, LocationListEither::Either, "textDocument/typeDefinition");
\ No newline at end of file diff --git a/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/textDocument/willSave.h b/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/textDocument/willSave.h new file mode 100644 index 00000000000..84aa0badaa7 --- /dev/null +++ b/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/textDocument/willSave.h @@ -0,0 +1,71 @@ +#pragma once + + +#include "LibLsp/JsonRpc/RequestInMessage.h" +#include "LibLsp/JsonRpc/lsResponseMessage.h" + +#include "LibLsp/lsp/lsTextDocumentIdentifier.h" + +namespace WillSaveTextDocumentParams { + + /** + * Represents reasons why a text document is saved. + */ + enum class TextDocumentSaveReason { + + /** + * Manually triggered, e.g. by the user pressing save, by starting debugging, + * or by an API call. + */ + Manual=(1), + + /** + * Automatic after a delay. + */ + AfterDelay=(2), + + /** + * When the editor lost focus. + */ + FocusOut=(3) + }; + + struct Params { + /** + * The document that will be saved. + */ + lsTextDocumentIdentifier textDocument; + + /* + * A reason why a text document is saved. + */ + + boost::optional<TextDocumentSaveReason> reason; + + MAKE_SWAP_METHOD(Params, textDocument, reason); + }; + +}; +MAKE_REFLECT_TYPE_PROXY(WillSaveTextDocumentParams::TextDocumentSaveReason); + +MAKE_REFLECT_STRUCT(WillSaveTextDocumentParams::Params, textDocument, reason); + +/** + * The document save notification is sent from the client to the server when + * the document for saved in the client. + * + * Registration Options: TextDocumentSaveRegistrationOptions + */ +DEFINE_NOTIFICATION_TYPE(td_willSave, WillSaveTextDocumentParams::Params, "textDocument/willSave"); + +/** + * The document will save request is sent from the client to the server before the document is actually saved. + * The request can return an array of TextEdits which will be applied to the text document before it is saved. + * Please note that clients might drop results if computing the text edits took too long or if a server constantly fails on this request. + * This is done to keep the save fast and reliable. + * + * Registration Options: TextDocumentRegistrationOptions + */ +DEFINE_REQUEST_RESPONSE_TYPE(td_willSaveWaitUntil, + WillSaveTextDocumentParams::Params, std::vector<lsTextEdit>, "textDocument/willSaveWaitUntil"); + diff --git a/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/utils.cpp b/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/utils.cpp new file mode 100644 index 00000000000..532f4bf6d70 --- /dev/null +++ b/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/utils.cpp @@ -0,0 +1,602 @@ +#include "utils.h" + +#include <algorithm> +#include <cassert> +#include <cctype> +#include <cstring> +#include <fstream> +#include <functional> + +#include <queue> +#include <sstream> +#include <string> +#include <unordered_map> +#include <sys/stat.h> + +#include "lsPosition.h" +#include "utf8.h" +#ifdef _WIN32 +#include <Windows.h> +#endif + + +// DEFAULT_RESOURCE_DIRECTORY is passed with quotes for non-MSVC compilers, ie, +// foo vs "foo". +#if defined(_MSC_VER) +#define _STRINGIFY(x) #x +#define ENSURE_STRING_MACRO_ARGUMENT(x) _STRINGIFY(x) +#else +#define ENSURE_STRING_MACRO_ARGUMENT(x) x +#endif +#include <boost/filesystem/path.hpp> +#include <boost/filesystem/operations.hpp> +#include <boost/algorithm/string.hpp> +namespace lsp +{ + + +// See http://stackoverflow.com/a/2072890 +bool EndsWith(std::string value, std::string ending) { + if (ending.size() > value.size()) + return false; + return std::equal(ending.rbegin(), ending.rend(), value.rbegin()); +} + +bool StartsWith(std::string value, std::string start) { + if (start.size() > value.size()) + return false; + return std::equal(start.begin(), start.end(), value.begin()); +} + +bool AnyStartsWith(const std::vector<std::string>& values, + const std::string& start) { + return std::any_of( + std::begin(values), std::end(values), + [&start](const std::string& value) { return StartsWith(value, start); }); +} + +bool StartsWithAny(const std::string& value, + const std::vector<std::string>& startings) { + return std::any_of(std::begin(startings), std::end(startings), + [&value](const std::string& starting) { + return StartsWith(value, starting); + }); +} + +bool EndsWithAny(const std::string& value, + const std::vector<std::string>& endings) { + return std::any_of( + std::begin(endings), std::end(endings), + [&value](const std::string& ending) { return EndsWith(value, ending); }); +} + +bool FindAnyPartial(const std::string& value, + const std::vector<std::string>& values) { + return std::any_of(std::begin(values), std::end(values), + [&value](const std::string& v) { + return value.find(v) != std::string::npos; + }); +} + +std::string GetDirName(std::string path) { + + ReplaceAll(path, "\\", "/"); + if (path.size() && path.back() == '/') + path.pop_back(); + size_t last_slash = path.find_last_of('/'); + if (last_slash == std::string::npos) + return "./"; + return path.substr(0, last_slash + 1); +} + +std::string GetBaseName(const std::string& path) { + size_t last_slash = path.find_last_of('/'); + if (last_slash != std::string::npos && (last_slash + 1) < path.size()) + return path.substr(last_slash + 1); + return path; +} + +std::string StripFileType(const std::string& path) { + size_t last_period = path.find_last_of('.'); + if (last_period != std::string::npos) + return path.substr(0, last_period); + return path; +} + +// See http://stackoverflow.com/a/29752943 +std::string ReplaceAll(const std::string& source, + const std::string& from, + const std::string& to) { + std::string result; + result.reserve(source.length()); // avoids a few memory allocations + + std::string::size_type last_pos = 0; + std::string::size_type find_pos; + + while (std::string::npos != (find_pos = source.find(from, last_pos))) { + result.append(source, last_pos, find_pos - last_pos); + result += to; + last_pos = find_pos + from.length(); + } + + // Care for the rest after last occurrence + result += source.substr(last_pos); + + return result; +} + +std::vector<std::string> SplitString(const std::string& str, + const std::string& delimiter) { + // http://stackoverflow.com/a/13172514 + std::vector<std::string> strings; + + std::string::size_type pos = 0; + std::string::size_type prev = 0; + while ((pos = str.find(delimiter, prev)) != std::string::npos) { + strings.emplace_back(str.substr(prev, pos - prev)); + prev = pos + 1; + } + + // To get the last substring (or only, if delimiter is not found) + strings.emplace_back(str.substr(prev)); + + return strings; +} + +void EnsureEndsInSlash(std::string& path) { + if (path.empty() || path[path.size() - 1] != '/') + path += '/'; +} + +std::string EscapeFileName(std::string path) { + if (path.size() && path.back() == '/') + path.pop_back(); + std::replace(path.begin(), path.end(), '\\', '@'); + std::replace(path.begin(), path.end(), '/', '@'); + std::replace(path.begin(), path.end(), ':', '@'); + return path; +} + +// http://stackoverflow.com/a/6089413 +std::istream& SafeGetline(std::istream& is, std::string& t) { + t.clear(); + + // The characters in the stream are read one-by-one using a std::streambuf. + // That is faster than reading them one-by-one using the std::istream. Code + // that uses streambuf this way must be guarded by a sentry object. The sentry + // object performs various tasks, such as thread synchronization and updating + // the stream state. + + std::istream::sentry se(is, true); + std::streambuf* sb = is.rdbuf(); + + for (;;) { + int c = sb->sbumpc(); + if (c == EOF) { + // Also handle the case when the last line has no line ending + if (t.empty()) + is.setstate(std::ios::eofbit); + return is; + } + + t += (char)c; + + if (c == '\n') + return is; + } +} + +bool FileExists(const std::string& filename) { + std::ifstream cache(filename); + return cache.is_open(); +} + +boost::optional<std::string> ReadContent(const AbsolutePath& filename) { + + std::ifstream cache; + cache.open(filename.path); + + try { + return std::string(std::istreambuf_iterator<char>(cache), + std::istreambuf_iterator<char>()); + } catch (std::ios_base::failure&) { + return {}; + } +} + +std::vector<std::string> ReadLinesWithEnding(const AbsolutePath& filename) { + std::vector<std::string> result; + + std::ifstream input(filename.path); + for (std::string line; SafeGetline(input, line);) + result.emplace_back(line); + + return result; +} + +bool WriteToFile(const std::string& filename, const std::string& content) { + std::ofstream file(filename, + std::ios::out | std::ios::trunc | std::ios::binary); + if (!file.good()) { + + return false; + } + + file << content; + return true; +} + + +std::string FormatMicroseconds(long long microseconds) { + long long milliseconds = microseconds / 1000; + long long remaining = microseconds - milliseconds; + + // Only show two digits after the dot. + while (remaining >= 100) + remaining /= 10; + + return std::to_string(milliseconds) + "." + std::to_string(remaining) + "ms"; +} + + + +std::string UpdateToRnNewlines(std::string output) { + size_t idx = 0; + while (true) { + idx = output.find('\n', idx); + + // No more matches. + if (idx == std::string::npos) + break; + + // Skip an existing "\r\n" match. + if (idx > 0 && output[idx - 1] == '\r') { + ++idx; + continue; + } + + // Replace "\n" with "\r|n". + output.replace(output.begin() + idx, output.begin() + idx + 1, "\r\n"); + } + + return output; +} + + + +bool IsAbsolutePath(const std::string& path) { + return IsUnixAbsolutePath(path) || IsWindowsAbsolutePath(path); +} + +bool IsUnixAbsolutePath(const std::string& path) { + return !path.empty() && path[0] == '/'; +} + +bool IsWindowsAbsolutePath(const std::string& path) { + auto is_drive_letter = [](char c) { + return (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z'); + }; + + return path.size() > 3 && path[1] == ':' && + (path[2] == '/' || path[2] == '\\') && is_drive_letter(path[0]); +} + +bool IsDirectory(const std::string& path) { + struct stat path_stat; + + if (stat(path.c_str(), &path_stat) != 0) { + perror("cannot access path"); + return false; + } + + return path_stat.st_mode & S_IFDIR; +} + + +std::string ws2s(std::wstring const& wstr) { + + std::string narrow; + utf8::utf32to8(wstr.begin(), wstr.end(), std::back_inserter(narrow)); + return narrow; +} +std::wstring s2ws(const std::string& str) { + std::wstring wide; + utf8::utf8to32(str.begin(), str.end(), std::back_inserter(wide)); + return wide; +} + + +#ifdef _WIN32 + +#else +// Returns the canonicalized absolute pathname, without expanding symbolic +// links. This is a variant of realpath(2), C++ rewrite of +// https://github.com/freebsd/freebsd/blob/master/lib/libc/stdlib/realpath.c +AbsolutePath RealPathNotExpandSymlink(std::string path, + bool ensure_exists) { + if (path.empty()) { + errno = EINVAL; + return {}; + } + if (path[0] == '\0') { + errno = ENOENT; + return {}; + } + + // Do not use PATH_MAX because it is tricky on Linux. + // See https://eklitzke.org/path-max-is-tricky + char tmp[1024]; + std::string resolved; + size_t i = 0; + struct stat sb; + if (path[0] == '/') { + resolved = "/"; + i = 1; + } + else { + if (!getcwd(tmp, sizeof tmp) && ensure_exists) + return {}; + resolved = tmp; + } + + while (i < path.size()) { + auto j = path.find('/', i); + if (j == std::string::npos) + j = path.size(); + auto next_token = path.substr(i, j - i); + i = j + 1; + if (resolved.back() != '/') + resolved += '/'; + if (next_token.empty() || next_token == ".") { + // Handle consequential slashes and "." + continue; + } + else if (next_token == "..") { + // Strip the last path component except when it is single "/" + if (resolved.size() > 1) + resolved.resize(resolved.rfind('/', resolved.size() - 2) + 1); + continue; + } + // Append the next path component. + // Here we differ from realpath(3), we use stat(2) instead of + // lstat(2) because we do not want to resolve symlinks. + resolved += next_token; + if (stat(resolved.c_str(), &sb) != 0 && ensure_exists) + return {}; + if (!S_ISDIR(sb.st_mode) && j < path.size() && ensure_exists) { + errno = ENOTDIR; + return {}; + } + } + + // Remove trailing slash except when a single "/". + if (resolved.size() > 1 && resolved.back() == '/') + resolved.pop_back(); + return AbsolutePath(resolved, true /*validate*/); +} +#endif + + +AbsolutePath NormalizePath(const std::string& path0, + bool ensure_exists , + bool force_lower_on_windows) { +#ifdef _WIN32 + + std::wstring path = lsp::s2ws(path0); + + wchar_t buffer[MAX_PATH] = (L""); + + // Normalize the path name, ie, resolve `..`. + unsigned long len = GetFullPathNameW(path.c_str(), MAX_PATH, buffer, nullptr); + if (!len) + return {}; + path = std::wstring(buffer, len); + + // Get the actual casing of the path, ie, if the file on disk is `C:\FooBar` + // and this function is called with `c:\fooBar` this will return `c:\FooBar`. + // (drive casing is lowercase). + if (ensure_exists) { + len = GetLongPathNameW(path.c_str(), buffer, MAX_PATH); + if (!len) + return {}; + path = std::wstring(buffer, len); + } + + // Empty paths have no meaning. + if (path.empty()) + return {}; + + // We may need to normalize the drive name to upper-case; at the moment + // vscode sends lower-case path names. + /* + path[0] = toupper(path[0]); + */ + // Make the path all lower-case, since windows is case-insensitive. + if (force_lower_on_windows) { + for (size_t i = 0; i < path.size(); ++i) + path[i] = (wchar_t)tolower(path[i]); + } + + // cquery assumes forward-slashes. + std::replace(path.begin(), path.end(), '\\', '/'); + + + return AbsolutePath(lsp::ws2s(path), false /*validate*/); +#else + + return RealPathNotExpandSymlink(path0, ensure_exists); + +#endif + + +} + +// VSCode (UTF-16) disagrees with Emacs lsp-mode (UTF-8) on how to represent +// text documents. +// We use a UTF-8 iterator to approximate UTF-16 in the specification (weird). +// This is good enough and fails only for UTF-16 surrogate pairs. +int GetOffsetForPosition(lsPosition position, const std::string& content) { + size_t i = 0; + // Iterate lines until we have found the correct line. + while (position.line > 0 && i < content.size()) { + if (content[i] == '\n') + position.line--; + i++; + } + // Iterate characters on the target line. + while (position.character > 0 && i < content.size()) { + if (uint8_t(content[i++]) >= 128) { + // Skip 0b10xxxxxx + while (i < content.size() && uint8_t(content[i]) >= 128 && + uint8_t(content[i]) < 192) + i++; + } + position.character--; + } + return int(i); +} + + +lsPosition GetPositionForOffset(size_t offset,const std::string& content) { + lsPosition result; + for (size_t i = 0; i < offset && i < content.length(); ++i) { + if (content[i] == '\n') { + result.line++; + result.character = 0; + } + else { + result.character++; + } + } + return result; +} + +lsPosition CharPos(const std::string& search, + char character, + int character_offset) { + lsPosition result; + size_t index = 0; + while (index < search.size()) { + char c = search[index]; + if (c == character) + break; + if (c == '\n') { + result.line += 1; + result.character = 0; + } + else { + result.character += 1; + } + ++index; + } + assert(index < search.size()); + result.character += character_offset; + return result; +} + +void scanDirsUseRecursive(const std::wstring& rootPath, std::vector<std::wstring>& ret) +{ + namespace fs = boost::filesystem; + fs::path fullpath(rootPath); + if (!fs::exists(fullpath)) { return; } + fs::recursive_directory_iterator end_iter; + for (fs::recursive_directory_iterator iter(fullpath); iter != end_iter; iter++) { + try { + if (fs::is_directory(*iter)) { + ret.push_back(iter->path().wstring()); + } + } + catch (const std::exception& ex) { + continue; + } + } +} + +void scanDirsNoRecursive(const std::wstring& rootPath, std::vector<std::wstring>& ret) +{ + namespace fs = boost::filesystem; + boost::filesystem::path myPath(rootPath); + if (!fs::exists(rootPath)) { return; } + boost::filesystem::directory_iterator endIter; + for (boost::filesystem::directory_iterator iter(myPath); iter != endIter; iter++) { + if (boost::filesystem::is_directory(*iter)) { + ret.push_back(iter->path().wstring()); + } + } +} + +void scanFilesUseRecursive( + const std::wstring& rootPath, + std::vector<std::wstring>& ret, + std::wstring suf) { + namespace fs = boost::filesystem; + boost::to_lower(suf); + + fs::path fullpath(rootPath); + if (!fs::exists(fullpath)) { return; } + fs::recursive_directory_iterator end_iter; + for (fs::recursive_directory_iterator iter(fullpath); iter != end_iter; iter++) { + try { + if (!fs::is_directory(*iter) && fs::is_regular_file(*iter)) { + auto temp_path = iter->path().wstring(); + auto size = suf.size(); + if (!size) + { + ret.push_back(std::move(temp_path)); + } + else + { + + if (temp_path.size() < size) continue; + auto suf_temp = temp_path.substr(temp_path.size() - size); + boost::to_lower(suf_temp); + if (suf_temp == suf) + { + ret.push_back(std::move(temp_path)); + } + } + } + } + catch (const std::exception&) { + continue; + } + } +} + +void scanFileNamesUseRecursive(const std::wstring& rootPath, std::vector<std::wstring>& ret, + std::wstring strSuf) +{ + scanFilesUseRecursive(rootPath, ret, strSuf); + std::vector<std::wstring> names; + for (auto& it : ret) + { + if (it.size() >= rootPath.size()) + { + names.push_back(it.substr(rootPath.size())); + } + } + ret.swap(names); +} + +void scanFileNamesUseRecursive(const std::string& rootPath, std::vector<std::string>& ret, std::string strSuf) +{ + std::vector<std::wstring> out; + scanFileNamesUseRecursive(s2ws(rootPath), out, s2ws(strSuf)); + for (auto& it : out) + { + ret.push_back(ws2s(it)); + } +} + +void scanFilesUseRecursive(const std::string& rootPath, std::vector<std::string>& ret, std::string strSuf) +{ + std::vector<std::wstring> out; + scanFilesUseRecursive(s2ws(rootPath), out, s2ws(strSuf)); + for (auto& it : out) + { + ret.push_back(ws2s(it)); + } +} + + +} diff --git a/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/utils.h b/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/utils.h new file mode 100644 index 00000000000..796b5d2569d --- /dev/null +++ b/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/utils.h @@ -0,0 +1,141 @@ +#pragma once +#include <algorithm> +#include <codecvt> +#include <functional> +#include <iterator> +#include <locale> +#include <memory> +#include <string> +#include <vector> +#include <boost/optional/optional.hpp> +#include <LibLsp/lsp/AbsolutePath.h> + +#include "lsPosition.h" + + +namespace lsp +{ + + +// Returns true if |value| starts/ends with |start| or |ending|. +bool StartsWith(std::string value, std::string start); +bool EndsWith(std::string value, std::string ending); +bool AnyStartsWith(const std::vector<std::string>& values, + const std::string& start); +bool StartsWithAny(const std::string& value, + const std::vector<std::string>& startings); +bool EndsWithAny(const std::string& value, + const std::vector<std::string>& endings); +bool FindAnyPartial(const std::string& value, + const std::vector<std::string>& values); +// Returns the dirname of |path|, i.e. "foo/bar.cc" => "foo/", "foo" => "./", +// "/foo" => "/". The result always ends in '/'. +std::string GetDirName(std::string path); +// Returns the basename of |path|, ie, "foo/bar.cc" => "bar.cc". +std::string GetBaseName(const std::string& path); +// Returns |path| without the filetype, ie, "foo/bar.cc" => "foo/bar". +std::string StripFileType(const std::string& path); + +std::string ReplaceAll(const std::string& source, + const std::string& from, + const std::string& to); + +std::vector<std::string> SplitString(const std::string& str, + const std::string& delimiter); + +template <typename TValues, typename TMap> +std::string StringJoinMap(const TValues& values, + const TMap& map, + const std::string& sep = ", ") { + std::string result; + bool first = true; + for (auto& entry : values) { + if (!first) + result += sep; + first = false; + result += map(entry); + } + return result; +} + +template <typename TValues> +std::string StringJoin(const TValues& values, const std::string& sep = ", ") { + return StringJoinMap(values, [](const std::string& entry) { return entry; }, + sep); +} + +template <typename TCollection, typename TValue> +bool ContainsValue(const TCollection& collection, const TValue& value) { + return std::find(std::begin(collection), std::end(collection), value) != + std::end(collection); +} + + +// Ensures that |path| ends in a slash. +void EnsureEndsInSlash(std::string& path); + +// Converts a file path to one that can be used as filename. +// e.g. foo/bar.c => foo_bar.c +std::string EscapeFileName(std::string path); + +// FIXME: Move ReadContent into ICacheManager? +bool FileExists(const std::string& filename); +boost::optional<std::string> ReadContent(const AbsolutePath& filename); +std::vector<std::string> ReadLinesWithEnding(const AbsolutePath& filename); + +bool WriteToFile(const std::string& filename, const std::string& content); + + +template <typename T, typename Fn> +void RemoveIf(std::vector<T>* vec, Fn predicate) { + vec->erase(std::remove_if(vec->begin(), vec->end(), predicate), vec->end()); +} + +std::string FormatMicroseconds(long long microseconds); + +// Makes sure all newlines in |output| are in \r\n format. +std::string UpdateToRnNewlines(std::string output); + +// Utility methods to check if |path| is absolute. +bool IsAbsolutePath(const std::string& path); +bool IsUnixAbsolutePath(const std::string& path); +bool IsWindowsAbsolutePath(const std::string& path); + +bool IsDirectory(const std::string& path); + +// string <-> wstring conversion (UTF-16), e.g. for use with Window's wide APIs. + std::string ws2s(std::wstring const& wstr); + std::wstring s2ws(std::string const& str); + +AbsolutePath NormalizePath(const std::string& path, + bool ensure_exists = true, + bool force_lower_on_windows = true); + + +int GetOffsetForPosition(lsPosition position, const std::string& content); + +// Finds the position for an |offset| in |content|. +lsPosition GetPositionForOffset(int offset, const std::string& content); + +// Utility method to find a position for the given character. +lsPosition CharPos(const std::string& search, + char character, + int character_offset = 0); + + + void scanDirsNoRecursive(const std::wstring& rootPath, std::vector<std::wstring>& ret); + + void scanFilesUseRecursive(const std::wstring& rootPath, std::vector<std::wstring>& ret, + std::wstring strSuf = L""); + + void scanFileNamesUseRecursive(const std::wstring& rootPath, std::vector<std::wstring>& ret, + std::wstring strSuf = L""); + void scanFileNamesUseRecursive(const std::string& rootPath, std::vector<std::string>& ret, + std::string strSuf = ""); + + void scanFilesUseRecursive(const std::string& rootPath, std::vector<std::string>& ret, + std::string strSuf = ""); + + void scanDirsUseRecursive(const std::wstring& rootPath, std::vector<std::wstring>& ret); + +} diff --git a/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/windows/MessageNotify.h b/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/windows/MessageNotify.h new file mode 100644 index 00000000000..8499304f558 --- /dev/null +++ b/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/windows/MessageNotify.h @@ -0,0 +1,83 @@ +#pragma once + +#include "LibLsp/JsonRpc/NotificationInMessage.h" +#include "LibLsp/JsonRpc/RequestInMessage.h" +#include "LibLsp/JsonRpc/lsResponseMessage.h" + +// Show a message to the user. +enum class lsMessageType : int { Error = 1, Warning = 2, Info = 3, Log = 4 }; +MAKE_REFLECT_TYPE_PROXY(lsMessageType) +struct MessageParams { +/** + * The message type. + */ + + lsMessageType type = lsMessageType::Error; + +/** + * The actual message. + */ + std::string message; + + void swap(MessageParams& arg) noexcept { + lsMessageType temp = type; + type = arg.type; + arg.type = temp; + message.swap(arg.message); + } +}; +MAKE_REFLECT_STRUCT(MessageParams, type, message) + + /** + * The log message notification is send from the server to the client to ask + * the client to log a particular message. + */ +DEFINE_NOTIFICATION_TYPE(Notify_LogMessage, MessageParams, "window/logMessage") + + +/** + * The show message notification is sent from a server to a client to ask + * the client to display a particular message in the user interface. + */ +DEFINE_NOTIFICATION_TYPE(Notify_ShowMessage, MessageParams, "window/showMessage") + + + +/** + * The show message request is sent from a server to a client to ask the client to display a particular message in the + * user class. In addition to the show message notification the request allows to pass actions and to wait for an + * answer from the client. + */ +struct MessageActionItem { + /** + * A short title like 'Retry', 'Open Log' etc. + */ + + std::string title; + MAKE_SWAP_METHOD(MessageActionItem, title) +}; +MAKE_REFLECT_STRUCT(MessageActionItem, title); + + +struct ShowMessageRequestParams :public MessageParams { + /** + * The message action items to present. + */ + std::vector<MessageActionItem> actions; + + MAKE_SWAP_METHOD(ShowMessageRequestParams, type, message, actions) + +}; +MAKE_REFLECT_STRUCT(ShowMessageRequestParams, type, message, actions) + +/** +* The show message request is sent from a server to a client to ask the +* client to display a particular message in the user interface. In addition +* to the show message notification the request allows to pass actions and +* to wait for an answer from the client. +*/ + +DEFINE_REQUEST_RESPONSE_TYPE(WindowShowMessage, ShowMessageRequestParams, MessageActionItem, "window/showMessage") + + + diff --git a/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/working_files.cpp b/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/working_files.cpp new file mode 100644 index 00000000000..370a0382741 --- /dev/null +++ b/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/working_files.cpp @@ -0,0 +1,186 @@ +#include "working_files.h" +#include <algorithm> +#include <climits> +#include <numeric> +#include "utils.h" +#include <memory> +#include "LibLsp/lsp/AbsolutePath.h" +using namespace lsp; +struct WorkingFilesData +{ + std::map<AbsolutePath, std::shared_ptr<WorkingFile> > files; + std::mutex files_mutex; // Protects |d_ptr->files|. +}; + +WorkingFile::WorkingFile(WorkingFiles& _parent, const AbsolutePath& filename, + const std::string& buffer_content) + : filename(filename), directory(filename), parent(_parent), counter(0), buffer_content(buffer_content) +{ + directory = Directory(GetDirName(filename.path)); +} + +WorkingFile::WorkingFile(WorkingFiles& _parent, const AbsolutePath& filename, + std::string&& buffer_content) + : filename(filename), directory(filename), parent(_parent), counter(0), buffer_content(buffer_content) +{ + directory = Directory(GetDirName(filename.path)); +} + +WorkingFiles::WorkingFiles():d_ptr(new WorkingFilesData()) +{ +} + +WorkingFiles::~WorkingFiles() +{ + delete d_ptr; + +} + + + +void WorkingFiles::CloseFilesInDirectory(const std::vector<Directory>& directories) +{ + std::lock_guard<std::mutex> lock(d_ptr->files_mutex); + std::vector<AbsolutePath> files_to_be_delete; + + for(auto& it : d_ptr->files) + { + for (auto& dir : directories) + { + if (it.second->directory == dir) { + files_to_be_delete.emplace_back(it.first); + } + } + } + + for(auto& it : files_to_be_delete) + { + d_ptr->files.erase(it); + } +} + + + + +std::shared_ptr<WorkingFile> WorkingFiles::GetFileByFilename(const AbsolutePath& filename) { + std::lock_guard<std::mutex> lock(d_ptr->files_mutex); + return GetFileByFilenameNoLock(filename); +} + +std::shared_ptr<WorkingFile> WorkingFiles::GetFileByFilenameNoLock( + const AbsolutePath& filename) { + const auto findIt = d_ptr->files.find(filename); + if ( findIt != d_ptr->files.end()) + { + return findIt->second; + } + return nullptr; +} + + + +std::shared_ptr<WorkingFile> WorkingFiles::OnOpen( lsTextDocumentItem& open) { + std::lock_guard<std::mutex> lock(d_ptr->files_mutex); + + AbsolutePath filename = open.uri.GetAbsolutePath(); + + // The file may already be open. + if (auto file = GetFileByFilenameNoLock(filename)) { + file->version = open.version; + file->buffer_content.swap(open.text); + + return file; + } + + const auto& it = d_ptr->files.insert({ filename,std::make_shared<WorkingFile>(*this,filename, std::move(open.text)) }); + return it.first->second; +} + + +std::shared_ptr<WorkingFile> WorkingFiles::OnChange(const lsTextDocumentDidChangeParams& change) { + std::lock_guard<std::mutex> lock(d_ptr->files_mutex); + + AbsolutePath filename = change.textDocument.uri.GetAbsolutePath(); + auto file = GetFileByFilenameNoLock(filename); + if (!file) { + return {}; + } + + if (change.textDocument.version) + file->version = *change.textDocument.version; + file->counter.fetch_add(1, std::memory_order_relaxed); + for (const lsTextDocumentContentChangeEvent& diff : change.contentChanges) { + // Per the spec replace everything if the rangeLength and range are not set. + // See https://github.com/Microsoft/language-server-protocol/issues/9. + if (!diff.range) { + file->buffer_content = diff.text; + + } else { + int start_offset = + GetOffsetForPosition(diff.range->start, file->buffer_content); + // Ignore TextDocumentContentChangeEvent.rangeLength which causes trouble + // when UTF-16 surrogate pairs are used. + int end_offset = + GetOffsetForPosition(diff.range->end, file->buffer_content); + file->buffer_content.replace(file->buffer_content.begin() + start_offset, + file->buffer_content.begin() + end_offset, + diff.text); + + } + } + return file; +} + +bool WorkingFiles::OnClose(const lsTextDocumentIdentifier& close) { + std::lock_guard<std::mutex> lock(d_ptr->files_mutex); + + AbsolutePath filename = close.uri.GetAbsolutePath(); + const auto findIt = d_ptr->files.find(filename); + if( findIt != d_ptr->files.end()) + { + d_ptr->files.erase(findIt); + return true; + } + return false; +} + +std::shared_ptr<WorkingFile> WorkingFiles::OnSave(const lsTextDocumentIdentifier& _save) +{ + std::lock_guard<std::mutex> lock(d_ptr->files_mutex); + + AbsolutePath filename = _save.uri.GetAbsolutePath(); + const auto findIt = d_ptr->files.find(filename); + if (findIt != d_ptr->files.end()) + { + std::shared_ptr<WorkingFile>& file = findIt->second; + lsp::WriteToFile(file->filename, file->GetContentNoLock()); + return findIt->second; + } + return {}; + +} + +bool WorkingFiles::GetFileBufferContent(std::shared_ptr<WorkingFile>&file, std::string& out) +{ + std::lock_guard<std::mutex> lock(d_ptr->files_mutex); + if (file) + { + out = file->buffer_content; + return true; + } + return false; +} +bool WorkingFiles::GetFileBufferContent(std::shared_ptr<WorkingFile>& file, std::wstring& out) +{ + std::lock_guard<std::mutex> lock(d_ptr->files_mutex); + if (file) + { + out = lsp::s2ws(file->buffer_content); + return true; + } + return false; +} +void WorkingFiles::Clear() { + std::lock_guard<std::mutex> lock(d_ptr->files_mutex); + d_ptr->files.clear(); +}
\ No newline at end of file diff --git a/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/working_files.h b/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/working_files.h new file mode 100644 index 00000000000..e305fee8d06 --- /dev/null +++ b/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/working_files.h @@ -0,0 +1,72 @@ +#pragma once + +#include "LibLsp/lsp/lsp_diagnostic.h" +#include "LibLsp/lsp/AbsolutePath.h" +#include "LibLsp/lsp/textDocument/did_change.h" +#include "LibLsp/lsp/textDocument/did_close.h" +#include "LibLsp/lsp/textDocument/did_open.h" +#include <mutex> +#include <string> +#include <memory> +#include "Directory.h" + +struct WorkingFiles; +struct WorkingFilesData; +struct WorkingFile { + + int version = 0; + AbsolutePath filename; + Directory directory; + WorkingFiles& parent; + std::atomic<long long> counter; + WorkingFile(WorkingFiles& ,const AbsolutePath& filename, const std::string& buffer_content); + WorkingFile(WorkingFiles&, const AbsolutePath& filename, std::string&& buffer_content); + const std::string& GetContentNoLock() const + { + return buffer_content; + } +protected: + friend struct WorkingFiles; + std::string buffer_content; +}; + +struct WorkingFiles { + + WorkingFiles(); + ~WorkingFiles(); + + void CloseFilesInDirectory(const std::vector<Directory>&); + std::shared_ptr<WorkingFile> OnOpen(lsTextDocumentItem& open); + std::shared_ptr<WorkingFile> OnChange(const lsTextDocumentDidChangeParams& change); + bool OnClose(const lsTextDocumentIdentifier& close); + std::shared_ptr<WorkingFile> OnSave(const lsTextDocumentIdentifier& _save); + + bool GetFileBufferContent(const AbsolutePath& filename, std::wstring& out) + { + auto file = GetFileByFilename(filename); + if(!file) + return false; + return GetFileBufferContent(file, out); + } + bool GetFileBufferContent(const AbsolutePath& filename,std::string& out) + { + auto file = GetFileByFilename(filename); + if (!file) + return false; + return GetFileBufferContent(file, out); + } + bool GetFileBufferContent(std::shared_ptr<WorkingFile>&, std::string& out); + bool GetFileBufferContent(std::shared_ptr<WorkingFile>&, std::wstring& out); + + + // Find the file with the given filename. + std::shared_ptr<WorkingFile> GetFileByFilename(const AbsolutePath& filename); + + void Clear(); +private: + std::shared_ptr<WorkingFile> GetFileByFilenameNoLock(const AbsolutePath& filename); + + WorkingFilesData* d_ptr; + + +}; diff --git a/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/workspace/applyEdit.h b/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/workspace/applyEdit.h new file mode 100644 index 00000000000..7e2d8bee0a6 --- /dev/null +++ b/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/workspace/applyEdit.h @@ -0,0 +1,42 @@ +#pragma once + +#include "LibLsp/JsonRpc/RequestInMessage.h" +#include "LibLsp/JsonRpc/lsResponseMessage.h" + +#include "LibLsp/lsp/lsDocumentUri.h" +#include "LibLsp/lsp/lsWorkspaceEdit.h" + +struct ApplyWorkspaceEditParams +{ + /** + * The edits to apply. + */ + + lsWorkspaceEdit edit; + + /** + * An optional label of the workspace edit. This label is + * presented in the user interface for example on an undo + * stack to undo the workspace edit. + */ + std::string label; + + MAKE_SWAP_METHOD(ApplyWorkspaceEditParams, edit, label) +}; +/** + * The workspace/applyEdit request is sent from the server to the client to modify resource on the client side. + */ +MAKE_REFLECT_STRUCT(ApplyWorkspaceEditParams, edit, label); + + + +struct ApplyWorkspaceEditResponse +{ + bool applied; + boost::optional<std::string> failureReason; + MAKE_SWAP_METHOD(ApplyWorkspaceEditResponse, applied, failureReason) +}; +MAKE_REFLECT_STRUCT(ApplyWorkspaceEditResponse, applied, failureReason); + + +DEFINE_REQUEST_RESPONSE_TYPE(WorkspaceApply, ApplyWorkspaceEditParams, ApplyWorkspaceEditResponse, "workspace/applyEdit"); diff --git a/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/workspace/configuration.h b/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/workspace/configuration.h new file mode 100644 index 00000000000..f7709aa6076 --- /dev/null +++ b/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/workspace/configuration.h @@ -0,0 +1,37 @@ +#pragma once + +#include "LibLsp/JsonRpc/RequestInMessage.h" +#include "LibLsp/JsonRpc/lsResponseMessage.h" + +#include "LibLsp/lsp/lsDocumentUri.h" + + +struct ConfigurationItem { + /** + * The scope to get the configuration section for. + */ + lsDocumentUri scopeUri; + + /** + * The configuration section asked for. + */ + std::string section; + MAKE_SWAP_METHOD(ConfigurationItem, scopeUri, section); +}; +MAKE_REFLECT_STRUCT(ConfigurationItem, scopeUri, section); +struct ConfigurationParams +{ + std::vector<ConfigurationItem> items; + MAKE_SWAP_METHOD(ConfigurationParams, items) +}; + +MAKE_REFLECT_STRUCT(ConfigurationParams, items); + +/** + * The workspace/configuration request is sent from the server to the client to fetch + * configuration settings from the client. The request can fetch n configuration settings + * in one roundtrip. The order of the returned configuration settings correspond to the + * order of the passed ConfigurationItems (e.g. the first item in the response is the + * result for the first configuration item in the params). + */ +DEFINE_REQUEST_RESPONSE_TYPE(WorkspaceConfiguration, ConfigurationParams,std::vector<lsp::Any>, "workspace/configuration");
\ No newline at end of file diff --git a/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/workspace/didChangeWorkspaceFolders.h b/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/workspace/didChangeWorkspaceFolders.h new file mode 100644 index 00000000000..78f000f30d5 --- /dev/null +++ b/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/workspace/didChangeWorkspaceFolders.h @@ -0,0 +1,48 @@ +#pragma once +#include "LibLsp/JsonRpc/NotificationInMessage.h" +#include "LibLsp/lsp/workspace/workspaceFolders.h" +/** + * The workspace folder change event. + */ +struct WorkspaceFoldersChangeEvent { + /** + * The array of added workspace folders + */ + + std::vector<WorkspaceFolder> added; + + /** + * The array of the removed workspace folders + */ + + std::vector <WorkspaceFolder> removed; + MAKE_SWAP_METHOD(WorkspaceFoldersChangeEvent, added, removed); + +}; +MAKE_REFLECT_STRUCT(WorkspaceFoldersChangeEvent, added, removed); + +struct DidChangeWorkspaceFoldersParams { + /** + * The actual workspace folder change event. + */ + + WorkspaceFoldersChangeEvent event; + + MAKE_SWAP_METHOD(DidChangeWorkspaceFoldersParams, event); +}; +MAKE_REFLECT_STRUCT(DidChangeWorkspaceFoldersParams, event); + + +/** + * The workspace/didChangeWorkspaceFolders notification is sent from the client + * to the server to inform the server about workspace folder configuration changes. + * The notification is sent by default if both ServerCapabilities/workspaceFolders + * and ClientCapabilities/workspace/workspaceFolders are true; or if the server has + * registered to receive this notification it first. + */ +DEFINE_NOTIFICATION_TYPE(Notify_WorkspaceDidChangeWorkspaceFolders, + DidChangeWorkspaceFoldersParams, "workspace/didChangeWorkspaceFolders"); + + + + diff --git a/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/workspace/did_change_configuration.h b/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/workspace/did_change_configuration.h new file mode 100644 index 00000000000..8f8acceea41 --- /dev/null +++ b/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/workspace/did_change_configuration.h @@ -0,0 +1,25 @@ +#pragma once + +#include "LibLsp/JsonRpc/NotificationInMessage.h" + + +#include "workspaceFolders.h" + + + + +struct lsDidChangeConfigurationParams { + /** + * The actual changed settings. + */ + lsp::Any settings; + MAKE_SWAP_METHOD(lsDidChangeConfigurationParams, settings); +}; + +MAKE_REFLECT_STRUCT(lsDidChangeConfigurationParams, settings); + +/** + * A notification sent from the client to the server to signal the change of + * configuration settings. + */ +DEFINE_NOTIFICATION_TYPE(Notify_WorkspaceDidChangeConfiguration, lsDidChangeConfigurationParams, "workspace/didChangeConfiguration"); diff --git a/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/workspace/did_change_watched_files.h b/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/workspace/did_change_watched_files.h new file mode 100644 index 00000000000..c14a7e0eda4 --- /dev/null +++ b/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/workspace/did_change_watched_files.h @@ -0,0 +1,46 @@ +#pragma once + +#include "LibLsp/JsonRpc/NotificationInMessage.h" +#include "LibLsp/lsp/lsDocumentUri.h" +enum class lsFileChangeType { + Created = 1, + Changed = 2, + Deleted = 3, +}; + +#ifdef _WIN32 +MAKE_REFLECT_TYPE_PROXY(lsFileChangeType); +#else +//#pragma clang diagnostic push +//#pragma clang diagnostic ignored "-Wunused-function" +MAKE_REFLECT_TYPE_PROXY(lsFileChangeType); +//#pragma clang diagnostic pop +#endif + + +/** + * An event describing a file change. + */ +struct lsFileEvent { + lsDocumentUri uri; + lsFileChangeType type; + + MAKE_SWAP_METHOD(lsFileEvent, uri, type) +}; +MAKE_REFLECT_STRUCT(lsFileEvent, uri, type); + +struct lsDidChangeWatchedFilesParams { + std::vector<lsFileEvent> changes; + MAKE_SWAP_METHOD(lsDidChangeWatchedFilesParams, changes); +}; +MAKE_REFLECT_STRUCT(lsDidChangeWatchedFilesParams, changes); + + /** + * The workspace/didChangeWorkspaceFolders notification is sent from the client + * to the server to inform the server about workspace folder configuration changes. + * The notification is sent by default if both ServerCapabilities/workspaceFolders + * and ClientCapabilities/workspace/workspaceFolders are true; or if the server has + * registered to receive this notification it first. + */ + +DEFINE_NOTIFICATION_TYPE(Notify_WorkspaceDidChangeWatchedFiles, lsDidChangeWatchedFilesParams, "workspace/didChangeWatchedFiles"); diff --git a/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/workspace/execute_command.h b/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/workspace/execute_command.h new file mode 100644 index 00000000000..c656ee5ef70 --- /dev/null +++ b/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/workspace/execute_command.h @@ -0,0 +1,24 @@ +#pragma once + +#include "LibLsp/lsp/ExecuteCommandParams.h" + +#include "LibLsp/JsonRpc/RequestInMessage.h" +#include "LibLsp/JsonRpc/lsResponseMessage.h" + +#include "LibLsp/JsonRpc/NotificationInMessage.h" + + + +/** + * The workspace/executeCommand request is sent from the client to the + * server to trigger command execution on the server. In most cases the + * server creates a WorkspaceEdit structure and applies the changes to the + * workspace using the request workspace/applyEdit which is sent from the + * server to the client. + * + * Registration Options: ExecuteCommandRegistrationOptions + */ +DEFINE_REQUEST_RESPONSE_TYPE(wp_executeCommand, ExecuteCommandParams, lsp::Any, "workspace/executeCommand"); + + +DEFINE_NOTIFICATION_TYPE(Notify_sendNotification, ExecuteCommandParams, "workspace/notify")
\ No newline at end of file diff --git a/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/workspace/symbol.h b/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/workspace/symbol.h new file mode 100644 index 00000000000..129fb5e822f --- /dev/null +++ b/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/workspace/symbol.h @@ -0,0 +1,16 @@ +#pragma once + +#include "LibLsp/lsp/symbol.h" + +#include "LibLsp/JsonRpc/RequestInMessage.h" +#include "LibLsp/JsonRpc/lsResponseMessage.h" + +/** + * The workspace symbol request is sent from the client to the server to + * list project-wide symbols matching the query string. + * + * Registration Options: void + */ + +DEFINE_REQUEST_RESPONSE_TYPE(wp_symbol, WorkspaceSymbolParams, std::vector<lsSymbolInformation>, "workspace/symbol"); + diff --git a/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/workspace/workspaceFolders.h b/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/workspace/workspaceFolders.h new file mode 100644 index 00000000000..7cedcfa5f48 --- /dev/null +++ b/Build/source/utils/asymptote/LspCpp/LibLsp/lsp/workspace/workspaceFolders.h @@ -0,0 +1,34 @@ +#pragma once + +#include "LibLsp/JsonRpc/RequestInMessage.h" +#include "LibLsp/JsonRpc/lsResponseMessage.h" + +#include "LibLsp/lsp/lsDocumentUri.h" +struct WorkspaceFolder { + /** + * The associated URI for this workspace folder. + */ + + lsDocumentUri uri; + + /** + * The name of the workspace folder. Defaults to the uri's basename. + */ + std::string name; + + MAKE_SWAP_METHOD(WorkspaceFolder, uri, name) +}; +MAKE_REFLECT_STRUCT(WorkspaceFolder, uri, name); + + +/** + * The workspace/workspaceFolders request is sent from the server to the client + * to fetch the current open list of workspace folders. + * + * @return null in the response if only a single file is open in the tool, + * an empty array if a workspace is open but no folders are configured, + * the workspace folders otherwise. + */ +DEFINE_REQUEST_RESPONSE_TYPE(WorkspaceFolders, + boost::optional<JsonNull>, boost::optional<std::vector< WorkspaceFolder>>, "workspace/workspaceFolders"); + |