diff options
Diffstat (limited to 'Build/source/utils/asymptote/LspCpp/src')
21 files changed, 7878 insertions, 0 deletions
diff --git a/Build/source/utils/asymptote/LspCpp/src/jsonrpc/Context.cpp b/Build/source/utils/asymptote/LspCpp/src/jsonrpc/Context.cpp new file mode 100755 index 00000000000..8d4094b41a8 --- /dev/null +++ b/Build/source/utils/asymptote/LspCpp/src/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 "LibLsp/JsonRpc/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/src/jsonrpc/Endpoint.cpp b/Build/source/utils/asymptote/LspCpp/src/jsonrpc/Endpoint.cpp new file mode 100755 index 00000000000..3c7c275d6da --- /dev/null +++ b/Build/source/utils/asymptote/LspCpp/src/jsonrpc/Endpoint.cpp @@ -0,0 +1,46 @@ +#include "LibLsp/JsonRpc/Endpoint.h" +#include "LibLsp/JsonRpc/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/src/jsonrpc/GCThreadContext.cpp b/Build/source/utils/asymptote/LspCpp/src/jsonrpc/GCThreadContext.cpp new file mode 100755 index 00000000000..f1420e964be --- /dev/null +++ b/Build/source/utils/asymptote/LspCpp/src/jsonrpc/GCThreadContext.cpp @@ -0,0 +1,17 @@ +#include "LibLsp/JsonRpc/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/src/jsonrpc/MessageJsonHandler.cpp b/Build/source/utils/asymptote/LspCpp/src/jsonrpc/MessageJsonHandler.cpp new file mode 100755 index 00000000000..4f79312a0c3 --- /dev/null +++ b/Build/source/utils/asymptote/LspCpp/src/jsonrpc/MessageJsonHandler.cpp @@ -0,0 +1,57 @@ +#include "LibLsp/JsonRpc/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/src/jsonrpc/RemoteEndPoint.cpp b/Build/source/utils/asymptote/LspCpp/src/jsonrpc/RemoteEndPoint.cpp new file mode 100755 index 00000000000..29ff69b2e24 --- /dev/null +++ b/Build/source/utils/asymptote/LspCpp/src/jsonrpc/RemoteEndPoint.cpp @@ -0,0 +1,612 @@ +#include "LibLsp/JsonRpc/MessageJsonHandler.h" +#include "LibLsp/JsonRpc/Endpoint.h" +#include "LibLsp/JsonRpc/message.h" +#include "LibLsp/JsonRpc/RemoteEndPoint.h" +#include <future> +#include "LibLsp/JsonRpc/Cancellation.h" +#include "LibLsp/JsonRpc/StreamMessageProducer.h" +#include "LibLsp/JsonRpc/NotificationInMessage.h" +#include "LibLsp/JsonRpc/lsResponseMessage.h" +#include "LibLsp/JsonRpc/Condition.h" +#include "LibLsp/JsonRpc/Context.h" +#include "rapidjson/error/en.h" +#include "LibLsp/JsonRpc/json.h" +#include "LibLsp/JsonRpc/GCThreadContext.h" +#include "LibLsp/JsonRpc/ScopeExit.h" +#include "LibLsp/JsonRpc/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/src/jsonrpc/StreamMessageProducer.cpp b/Build/source/utils/asymptote/LspCpp/src/jsonrpc/StreamMessageProducer.cpp new file mode 100755 index 00000000000..119e9040bdc --- /dev/null +++ b/Build/source/utils/asymptote/LspCpp/src/jsonrpc/StreamMessageProducer.cpp @@ -0,0 +1,191 @@ + +#include "LibLsp/JsonRpc/StreamMessageProducer.h" +#include <cassert> + +#include "LibLsp/JsonRpc/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/src/jsonrpc/TcpServer.cpp b/Build/source/utils/asymptote/LspCpp/src/jsonrpc/TcpServer.cpp new file mode 100755 index 00000000000..37a7a3a3af5 --- /dev/null +++ b/Build/source/utils/asymptote/LspCpp/src/jsonrpc/TcpServer.cpp @@ -0,0 +1,296 @@ +// +// server.cpp + +#include "LibLsp/JsonRpc/TcpServer.h" +#include <signal.h> +#include <utility> +#include <boost/bind/bind.hpp> + +#include "LibLsp/JsonRpc/MessageIssue.h" +#include "LibLsp/JsonRpc/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 )); + memcpy(str,some.data(),some.size()); + for (std::streamsize i = some.size(); 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/src/jsonrpc/WebSocketServer.cpp b/Build/source/utils/asymptote/LspCpp/src/jsonrpc/WebSocketServer.cpp new file mode 100755 index 00000000000..127cf2a9f45 --- /dev/null +++ b/Build/source/utils/asymptote/LspCpp/src/jsonrpc/WebSocketServer.cpp @@ -0,0 +1,337 @@ +#include "LibLsp/JsonRpc/MessageIssue.h" +#include "LibLsp/JsonRpc/WebSocketServer.h" +#include <iostream> +#include <signal.h> +#include <utility> +#include "LibLsp/JsonRpc/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)); + memcpy(str,some.data(),some.size()); + for (std::streamsize i = some.size(); 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/src/jsonrpc/message.cpp b/Build/source/utils/asymptote/LspCpp/src/jsonrpc/message.cpp new file mode 100755 index 00000000000..4a23d2016ab --- /dev/null +++ b/Build/source/utils/asymptote/LspCpp/src/jsonrpc/message.cpp @@ -0,0 +1,88 @@ +#include "LibLsp/JsonRpc/message.h" +#include <rapidjson/stringbuffer.h> +#include <rapidjson/writer.h> +#include "LibLsp/JsonRpc/serializer.h" +#include "LibLsp/JsonRpc/lsRequestId.h" +#include "LibLsp/JsonRpc/RequestInMessage.h" +#include "LibLsp/JsonRpc/Condition.h" +#include "LibLsp/JsonRpc/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/src/jsonrpc/optional.hpp b/Build/source/utils/asymptote/LspCpp/src/jsonrpc/optional.hpp new file mode 100644 index 00000000000..86e3b407c66 --- /dev/null +++ b/Build/source/utils/asymptote/LspCpp/src/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/src/jsonrpc/serializer.cpp b/Build/source/utils/asymptote/LspCpp/src/jsonrpc/serializer.cpp new file mode 100755 index 00000000000..526dcc88845 --- /dev/null +++ b/Build/source/utils/asymptote/LspCpp/src/jsonrpc/serializer.cpp @@ -0,0 +1,214 @@ +#include "LibLsp/JsonRpc/serializer.h" +#include <stdexcept> +#include <rapidjson/allocators.h> +#include "LibLsp/JsonRpc/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/src/jsonrpc/threaded_queue.cpp b/Build/source/utils/asymptote/LspCpp/src/jsonrpc/threaded_queue.cpp new file mode 100755 index 00000000000..1f9a02ac0dc --- /dev/null +++ b/Build/source/utils/asymptote/LspCpp/src/jsonrpc/threaded_queue.cpp @@ -0,0 +1,20 @@ +#include "LibLsp/JsonRpc/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/src/lsp/Markup.cpp b/Build/source/utils/asymptote/LspCpp/src/lsp/Markup.cpp new file mode 100755 index 00000000000..97860d969d9 --- /dev/null +++ b/Build/source/utils/asymptote/LspCpp/src/lsp/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 "LibLsp/lsp/Markup/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/src/lsp/ParentProcessWatcher.cpp b/Build/source/utils/asymptote/LspCpp/src/lsp/ParentProcessWatcher.cpp new file mode 100755 index 00000000000..57adb7e497a --- /dev/null +++ b/Build/source/utils/asymptote/LspCpp/src/lsp/ParentProcessWatcher.cpp @@ -0,0 +1,106 @@ +#include "LibLsp/lsp/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 "LibLsp/lsp/ProcessIoService.h" +#include "LibLsp/lsp/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/src/lsp/ProtocolJsonHandler.cpp b/Build/source/utils/asymptote/LspCpp/src/lsp/ProtocolJsonHandler.cpp new file mode 100755 index 00000000000..af008e9eb92 --- /dev/null +++ b/Build/source/utils/asymptote/LspCpp/src/lsp/ProtocolJsonHandler.cpp @@ -0,0 +1,716 @@ +#include "LibLsp/lsp/ProtocolJsonHandler.h" +#include "LibLsp/lsp/general/initialize.h" +#include "LibLsp/lsp/general/shutdown.h" +#include "LibLsp/lsp/textDocument/code_action.h" +#include "LibLsp/lsp/textDocument/code_lens.h" +#include "LibLsp/lsp/textDocument/completion.h" + + +#include "LibLsp/lsp/textDocument/did_close.h" + +#include "LibLsp/lsp/textDocument/highlight.h" +#include "LibLsp/lsp/textDocument/document_link.h" +#include "LibLsp/lsp/textDocument/formatting.h" +#include "LibLsp/lsp/textDocument/hover.h" +#include "LibLsp/lsp/textDocument/implementation.h" +#include "LibLsp/lsp/textDocument/range_formatting.h" +#include "LibLsp/lsp/textDocument/references.h" +#include "LibLsp/lsp/textDocument/rename.h" +#include "LibLsp/lsp/textDocument/signature_help.h" +#include "LibLsp/lsp/textDocument/type_definition.h" +#include "LibLsp/lsp/workspace/symbol.h" +#include "LibLsp/lsp/textDocument/typeHierarchy.h" +#include "LibLsp/lsp/out_list.h" +#include "LibLsp/lsp/extention/jdtls/codeActionResult.h" +#include "LibLsp/lsp/textDocument/declaration_definition.h" +#include "LibLsp/lsp/textDocument/resolveCompletionItem.h" +#include "LibLsp/lsp/textDocument/resolveCodeLens.h" +#include "LibLsp/lsp/textDocument/colorPresentation.h" +#include "LibLsp/lsp/textDocument/foldingRange.h" +#include "LibLsp/lsp/textDocument/prepareRename.h" +#include "LibLsp/lsp/textDocument/resolveTypeHierarchy.h" +#include "LibLsp/lsp/textDocument/callHierarchy.h" +#include "LibLsp/lsp/textDocument/selectionRange.h" +#include "LibLsp/lsp/extention/jdtls/classFileContents.h" +#include "LibLsp/lsp/extention/jdtls/buildWorkspace.h" +#include "LibLsp/lsp/extention/jdtls/listOverridableMethods.h" +#include "LibLsp/lsp/extention/jdtls/addOverridableMethods.h" +#include "LibLsp/lsp/extention/jdtls/checkHashCodeEqualsStatus.h" +#include "LibLsp/lsp/extention/jdtls/checkConstructorsStatus.h" +#include "LibLsp/lsp/extention/jdtls/checkDelegateMethodsStatus.h" +#include "LibLsp/lsp/extention/jdtls/checkToStringStatus.h" +#include "LibLsp/lsp/extention/jdtls/executeCommand.h" +#include "LibLsp/lsp/extention/jdtls/findLinks.h" +#include "LibLsp/lsp/extention/jdtls/generateAccessors.h" +#include "LibLsp/lsp/extention/jdtls/generateConstructors.h" +#include "LibLsp/lsp/extention/jdtls/generateDelegateMethods.h" +#include "LibLsp/lsp/extention/jdtls/generateHashCodeEquals.h" +#include "LibLsp/lsp/extention/jdtls/generateToString.h" +#include "LibLsp/lsp/extention/jdtls/getMoveDestinations.h" +#include "LibLsp/lsp/extention/jdtls/Move.h" +#include "LibLsp/lsp/extention/jdtls/organizeImports.h" +#include "LibLsp/lsp/general/exit.h" +#include "LibLsp/lsp/general/initialized.h" +#include "LibLsp/lsp/extention/jdtls/projectConfigurationUpdate.h" +#include "LibLsp/lsp/textDocument/did_change.h" +#include "LibLsp/lsp/textDocument/did_open.h" +#include "LibLsp/lsp/textDocument/did_save.h" +#include "LibLsp/lsp/textDocument/publishDiagnostics.h" +#include "LibLsp/lsp/textDocument/willSave.h" + +#include "LibLsp/lsp/workspace/didChangeWorkspaceFolders.h" +#include "LibLsp/lsp/workspace/did_change_configuration.h" +#include "LibLsp/lsp/workspace/did_change_watched_files.h" +#include "LibLsp/lsp/windows/MessageNotify.h" +#include "LibLsp/lsp/language/language.h" +#include "LibLsp/lsp/client/registerCapability.h" +#include "LibLsp/lsp/client/unregisterCapability.h" +#include "LibLsp/JsonRpc/Cancellation.h" +#include "LibLsp/lsp/textDocument/didRenameFiles.h" +#include "LibLsp/lsp/textDocument/semanticHighlighting.h" +#include "LibLsp/lsp/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/src/lsp/initialize.cpp b/Build/source/utils/asymptote/LspCpp/src/lsp/initialize.cpp new file mode 100755 index 00000000000..ebe3e334d04 --- /dev/null +++ b/Build/source/utils/asymptote/LspCpp/src/lsp/initialize.cpp @@ -0,0 +1,45 @@ +#include "LibLsp/lsp/general/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/src/lsp/lsp.cpp b/Build/source/utils/asymptote/LspCpp/src/lsp/lsp.cpp new file mode 100755 index 00000000000..bf39b9383ac --- /dev/null +++ b/Build/source/utils/asymptote/LspCpp/src/lsp/lsp.cpp @@ -0,0 +1,1089 @@ + + +#include "LibLsp/lsp/lru_cache.h" + + +#include <rapidjson/writer.h> + + +#include <stdio.h> +#include <iostream> +#include "LibLsp/lsp/location_type.h" +#include "LibLsp/lsp/out_list.h" +#include "LibLsp/lsp/lsTextDocumentIdentifier.h" +#include "LibLsp/lsp/lsVersionedTextDocumentIdentifier.h" +#include "LibLsp/lsp/lsResponseError.h" +#include "LibLsp/lsp/lsPosition.h" +#include "LibLsp/lsp/lsTextEdit.h" +#include "LibLsp/lsp/lsMarkedString.h" +#include "LibLsp/lsp/lsWorkspaceEdit.h" +#include "LibLsp/lsp/textDocument/code_action.h" +#include "LibLsp/lsp/textDocument/document_symbol.h" +#include "LibLsp/lsp/extention/jdtls/codeActionResult.h" + +#include "LibLsp/lsp/textDocument/selectionRange.h" +#include "LibLsp/lsp/AbsolutePath.h" + +#ifdef _WIN32 +#include <Windows.h> +#else +#include <climits> +#include <cstdlib> +#endif + +#include "LibLsp/lsp/Directory.h" +#include "LibLsp/lsp/lsFormattingOptions.h" +#include "LibLsp/JsonRpc/json.h" +#include "LibLsp/lsp/language/language.h" + +#include <network/uri/uri_builder.hpp> + +#include "LibLsp/lsp/lsp_completion.h" +#include "LibLsp/lsp/utils.h" +#include "LibLsp/lsp/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/src/lsp/lsp_diagnostic.cpp b/Build/source/utils/asymptote/LspCpp/src/lsp/lsp_diagnostic.cpp new file mode 100755 index 00000000000..79d9a6fc637 --- /dev/null +++ b/Build/source/utils/asymptote/LspCpp/src/lsp/lsp_diagnostic.cpp @@ -0,0 +1,75 @@ +#include "LibLsp/lsp/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/src/lsp/textDocument.cpp b/Build/source/utils/asymptote/LspCpp/src/lsp/textDocument.cpp new file mode 100755 index 00000000000..4d0b6b87131 --- /dev/null +++ b/Build/source/utils/asymptote/LspCpp/src/lsp/textDocument.cpp @@ -0,0 +1,349 @@ +#include "LibLsp/lsp/textDocument/completion.h" +#include "LibLsp/lsp/textDocument/document_symbol.h" +#include "LibLsp/lsp/lsMarkedString.h" +#include "LibLsp/lsp/textDocument/hover.h" +#include "LibLsp/lsp/textDocument/prepareRename.h" +#include <LibLsp/lsp/textDocument/typeHierarchy.h> + +#include "LibLsp/lsp/textDocument/semanticHighlighting.h" +#include "LibLsp/lsp/textDocument/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/src/lsp/utils.cpp b/Build/source/utils/asymptote/LspCpp/src/lsp/utils.cpp new file mode 100755 index 00000000000..32c70f517ad --- /dev/null +++ b/Build/source/utils/asymptote/LspCpp/src/lsp/utils.cpp @@ -0,0 +1,611 @@ +#include "LibLsp/lsp/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 "LibLsp/lsp/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) { + if(sizeof(wchar_t) == 2){ + std::string narrow; + utf8::utf16to8(wstr.begin(), wstr.end(), std::back_inserter(narrow)); + return narrow; + }else{ + 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; + if(sizeof(wchar_t) == 2){ + utf8::utf8to16(str.begin(), str.end(), std::back_inserter(wide)); + return wide; + }else{ + 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/src/lsp/working_files.cpp b/Build/source/utils/asymptote/LspCpp/src/lsp/working_files.cpp new file mode 100755 index 00000000000..09000210372 --- /dev/null +++ b/Build/source/utils/asymptote/LspCpp/src/lsp/working_files.cpp @@ -0,0 +1,186 @@ +#include "LibLsp/lsp/working_files.h" +#include <algorithm> +#include <climits> +#include <numeric> +#include "LibLsp/lsp/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 |