Refactor async.
This commit is contained in:
@@ -27,22 +27,38 @@ struct promise;
|
||||
|
||||
namespace clice::async {
|
||||
|
||||
extern uv_loop_t* loop;
|
||||
|
||||
template <typename T, typename U>
|
||||
T& uv_cast(U* u) {
|
||||
assert(u->data && "uv_cast: invalid uv handle");
|
||||
return *static_cast<T*>(u->data);
|
||||
}
|
||||
|
||||
using Callback = llvm::unique_function<promise<void>(json::Value)>;
|
||||
|
||||
void start_server(Callback callback);
|
||||
|
||||
void start_server(Callback callback, const char* ip, unsigned int port);
|
||||
|
||||
void write(json::Value id, json::Value result);
|
||||
|
||||
template <typename Value>
|
||||
struct Result {
|
||||
struct result {
|
||||
union {
|
||||
Value value;
|
||||
};
|
||||
|
||||
Result() {}
|
||||
result() {}
|
||||
|
||||
~Result() {}
|
||||
~result() {}
|
||||
|
||||
bool await_ready() noexcept {
|
||||
return false;
|
||||
}
|
||||
|
||||
decltype(auto) await_resume() noexcept {
|
||||
return value;
|
||||
return std::move(value);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
@@ -52,7 +68,7 @@ struct Result {
|
||||
};
|
||||
|
||||
template <>
|
||||
struct Result<void> {
|
||||
struct result<void> {
|
||||
bool await_ready() noexcept {
|
||||
return false;
|
||||
}
|
||||
@@ -62,14 +78,6 @@ struct Result<void> {
|
||||
void return_void() noexcept {}
|
||||
};
|
||||
|
||||
template <typename T, typename U>
|
||||
T& uv_cast(U* u) {
|
||||
assert(u->data && "uv_cast: invalid uv handle");
|
||||
return *static_cast<T*>(u->data);
|
||||
}
|
||||
|
||||
inline uv_loop_t* loop = uv_default_loop();
|
||||
|
||||
/// Schedule a coroutine to run in the event loop.
|
||||
inline void schedule(std::coroutine_handle<> handle) {
|
||||
assert(handle && "schedule: invalid coroutine handle");
|
||||
@@ -96,7 +104,7 @@ auto schedule_task(Task&& task) {
|
||||
|
||||
static_assert(!std::is_reference_v<Ret>, "return type must not be a reference");
|
||||
|
||||
struct Awaiter : Result<Ret> {
|
||||
struct Awaiter : result<Ret> {
|
||||
Func func;
|
||||
std::coroutine_handle<> caller;
|
||||
|
||||
@@ -115,7 +123,7 @@ auto schedule_task(Task&& task) {
|
||||
}
|
||||
},
|
||||
[](uv_work_t* work, int status) {
|
||||
auto awaiter = uv_cast<Awaiter>(work);
|
||||
auto& awaiter = uv_cast<Awaiter>(work);
|
||||
awaiter.caller.resume();
|
||||
delete work;
|
||||
});
|
||||
@@ -155,26 +163,11 @@ inline auto sleep(std::chrono::milliseconds ms) {
|
||||
return Awaiter{ms};
|
||||
}
|
||||
|
||||
struct FinalAwaiter {
|
||||
std::coroutine_handle<> caller;
|
||||
|
||||
bool await_ready() noexcept {
|
||||
return false;
|
||||
}
|
||||
|
||||
void await_suspend(std::coroutine_handle<> self) noexcept {
|
||||
self.destroy();
|
||||
/// If this coroutine is a top-level coroutine, its caller is empty.
|
||||
if(!caller) {
|
||||
return;
|
||||
}
|
||||
|
||||
/// Schedule the caller to run in the event loop.
|
||||
schedule(caller);
|
||||
}
|
||||
|
||||
void await_resume() noexcept {}
|
||||
};
|
||||
template <typename... Ps>
|
||||
int run(Ps&&... ps) {
|
||||
(schedule(std::forward<Ps>(ps)), ...);
|
||||
return uv_run(uv_default_loop(), UV_RUN_DEFAULT);
|
||||
}
|
||||
|
||||
} // namespace clice::async
|
||||
|
||||
@@ -183,7 +176,7 @@ namespace clice {
|
||||
template <typename T>
|
||||
class promise {
|
||||
public:
|
||||
struct promise_type : async::Result<T> {
|
||||
struct promise_type : async::result<T> {
|
||||
std::coroutine_handle<> caller;
|
||||
|
||||
auto get_return_object() {
|
||||
@@ -199,7 +192,28 @@ public:
|
||||
}
|
||||
|
||||
auto final_suspend() noexcept {
|
||||
return async::FinalAwaiter{.caller = caller};
|
||||
struct FinalAwaiter {
|
||||
std::coroutine_handle<> caller;
|
||||
|
||||
bool await_ready() noexcept {
|
||||
return false;
|
||||
}
|
||||
|
||||
void await_suspend(std::coroutine_handle<> self) noexcept {
|
||||
self.destroy();
|
||||
/// If this coroutine is a top-level coroutine, its caller is empty.
|
||||
if(!caller) {
|
||||
return;
|
||||
}
|
||||
|
||||
/// Schedule the caller to run in the event loop.
|
||||
async::schedule(caller);
|
||||
}
|
||||
|
||||
void await_resume() noexcept {}
|
||||
};
|
||||
|
||||
return FinalAwaiter{.caller = caller};
|
||||
}
|
||||
};
|
||||
|
||||
@@ -234,68 +248,5 @@ private:
|
||||
coroutine_handle h;
|
||||
};
|
||||
|
||||
template <typename T = bool>
|
||||
class Future {
|
||||
public:
|
||||
bool await_ready() {
|
||||
return false;
|
||||
}
|
||||
|
||||
void setReady() {
|
||||
isReady = true;
|
||||
if(isReady) {
|
||||
for(auto handle: handles) {
|
||||
handle.resume();
|
||||
}
|
||||
handles.clear();
|
||||
}
|
||||
}
|
||||
|
||||
void await_suspend(std::coroutine_handle<> handle) {
|
||||
handles.emplace_back(handle);
|
||||
if(isReady) {
|
||||
for(auto handle: handles) {
|
||||
handle.resume();
|
||||
}
|
||||
handles.clear();
|
||||
}
|
||||
}
|
||||
|
||||
void await_resume() {}
|
||||
|
||||
private:
|
||||
bool isReady = false;
|
||||
llvm::SmallVector<std::coroutine_handle<>, 6> handles;
|
||||
};
|
||||
|
||||
template <typename... Ps>
|
||||
int run(Ps&&... ps) {
|
||||
(schedule(std::forward<Ps>(ps)), ...);
|
||||
return uv_run(uv_default_loop(), UV_RUN_DEFAULT);
|
||||
}
|
||||
|
||||
struct Writer {
|
||||
void write(json::Value id, json::Value result);
|
||||
|
||||
public:
|
||||
void* handle;
|
||||
};
|
||||
|
||||
struct Server {
|
||||
public:
|
||||
using Callback = llvm::unique_function<promise<void>(json::Value, Writer&)>;
|
||||
|
||||
Server(Callback callback);
|
||||
|
||||
Server(Callback callback, const char* ip, unsigned int port);
|
||||
|
||||
void run() {
|
||||
uv_run(async::loop, UV_RUN_DEFAULT);
|
||||
}
|
||||
|
||||
public:
|
||||
Writer writer;
|
||||
Callback callback;
|
||||
};
|
||||
|
||||
} // namespace clice
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
#include "Basic/Document.h"
|
||||
#include "Compiler/Compiler.h"
|
||||
#include "Support/JSON.h"
|
||||
#include "Support/FileSystem.h"
|
||||
|
||||
#include "Feature/Lookup.h"
|
||||
#include "Feature/DocumentHighlight.h"
|
||||
@@ -122,54 +123,53 @@ struct DidCloseTextDocumentParams {
|
||||
|
||||
namespace clice {
|
||||
|
||||
class CacheManager {
|
||||
class Server {
|
||||
public:
|
||||
promise<void> buildPCH(std::string file, std::string content);
|
||||
Server() {
|
||||
addMethod("initialize", &Server::onInitialize);
|
||||
addMethod("initialized", &Server::onInitialized);
|
||||
addMethod("shutdown", &Server::onShutdown);
|
||||
addMethod("exit", &Server::onExit);
|
||||
|
||||
private:
|
||||
std::string outDir;
|
||||
};
|
||||
addMethod("textDocument/didOpen", &Server::onDidOpen);
|
||||
addMethod("textDocument/didChange", &Server::onDidChange);
|
||||
addMethod("textDocument/didSave", &Server::onDidSave);
|
||||
addMethod("textDocument/didClose", &Server::onDidClose);
|
||||
|
||||
class LSPServer {
|
||||
public:
|
||||
LSPServer() {
|
||||
addMethod("initialize", &LSPServer::onInitialize);
|
||||
addMethod("initialized", &LSPServer::onInitialized);
|
||||
addMethod("shutdown", &LSPServer::onShutdown);
|
||||
addMethod("exit", &LSPServer::onExit);
|
||||
|
||||
addMethod("textDocument/didOpen", &LSPServer::onDidOpen);
|
||||
addMethod("textDocument/didChange", &LSPServer::onDidChange);
|
||||
addMethod("textDocument/didSave", &LSPServer::onDidSave);
|
||||
addMethod("textDocument/didClose", &LSPServer::onDidClose);
|
||||
|
||||
addMethod("textDocument/declaration", &LSPServer::onGotoDeclaration);
|
||||
addMethod("textDocument/definition", &LSPServer::onGotoDefinition);
|
||||
addMethod("textDocument/typeDefinition", &LSPServer::onGotoTypeDefinition);
|
||||
addMethod("textDocument/implementation", &LSPServer::onGotoImplementation);
|
||||
addMethod("textDocument/references", &LSPServer::onFindReferences);
|
||||
addMethod("textDocument/callHierarchy/prepare", &LSPServer::onPrepareCallHierarchy);
|
||||
addMethod("textDocument/callHierarchy/incomingCalls", &LSPServer::onIncomingCall);
|
||||
addMethod("textDocument/callHierarchy/outgoingCalls", &LSPServer::onOutgoingCall);
|
||||
addMethod("textDocument/typeHierarchy/prepare", &LSPServer::onPrepareTypeHierarchy);
|
||||
addMethod("textDocument/typeHierarchy/supertypes", &LSPServer::onSupertypes);
|
||||
addMethod("textDocument/typeHierarchy/subtypes", &LSPServer::onSubtypes);
|
||||
addMethod("textDocument/documentHighlight", &LSPServer::onDocumentHighlight);
|
||||
addMethod("textDocument/documentLink", &LSPServer::onDocumentLink);
|
||||
addMethod("textDocument/hover", &LSPServer::onHover);
|
||||
addMethod("textDocument/codeLens", &LSPServer::onCodeLens);
|
||||
addMethod("textDocument/foldingRange", &LSPServer::onFoldingRange);
|
||||
addMethod("textDocument/documentSymbol", &LSPServer::onDocumentSymbol);
|
||||
addMethod("textDocument/semanticTokens", &LSPServer::onSemanticTokens);
|
||||
addMethod("textDocument/inlayHint", &LSPServer::onInlayHint);
|
||||
addMethod("textDocument/completion", &LSPServer::onCodeCompletion);
|
||||
addMethod("textDocument/signatureHelp", &LSPServer::onSignatureHelp);
|
||||
addMethod("textDocument/codeAction", &LSPServer::onCodeAction);
|
||||
addMethod("textDocument/formatting", &LSPServer::onFormatting);
|
||||
addMethod("textDocument/rangeFormatting", &LSPServer::onRangeFormatting);
|
||||
addMethod("textDocument/declaration", &Server::onGotoDeclaration);
|
||||
addMethod("textDocument/definition", &Server::onGotoDefinition);
|
||||
addMethod("textDocument/typeDefinition", &Server::onGotoTypeDefinition);
|
||||
addMethod("textDocument/implementation", &Server::onGotoImplementation);
|
||||
addMethod("textDocument/references", &Server::onFindReferences);
|
||||
addMethod("textDocument/callHierarchy/prepare", &Server::onPrepareCallHierarchy);
|
||||
addMethod("textDocument/callHierarchy/incomingCalls", &Server::onIncomingCall);
|
||||
addMethod("textDocument/callHierarchy/outgoingCalls", &Server::onOutgoingCall);
|
||||
addMethod("textDocument/typeHierarchy/prepare", &Server::onPrepareTypeHierarchy);
|
||||
addMethod("textDocument/typeHierarchy/supertypes", &Server::onSupertypes);
|
||||
addMethod("textDocument/typeHierarchy/subtypes", &Server::onSubtypes);
|
||||
addMethod("textDocument/documentHighlight", &Server::onDocumentHighlight);
|
||||
addMethod("textDocument/documentLink", &Server::onDocumentLink);
|
||||
addMethod("textDocument/hover", &Server::onHover);
|
||||
addMethod("textDocument/codeLens", &Server::onCodeLens);
|
||||
addMethod("textDocument/foldingRange", &Server::onFoldingRange);
|
||||
addMethod("textDocument/documentSymbol", &Server::onDocumentSymbol);
|
||||
addMethod("textDocument/semanticTokens", &Server::onSemanticTokens);
|
||||
addMethod("textDocument/inlayHint", &Server::onInlayHint);
|
||||
addMethod("textDocument/completion", &Server::onCodeCompletion);
|
||||
addMethod("textDocument/signatureHelp", &Server::onSignatureHelp);
|
||||
addMethod("textDocument/codeAction", &Server::onCodeAction);
|
||||
addMethod("textDocument/formatting", &Server::onFormatting);
|
||||
addMethod("textDocument/rangeFormatting", &Server::onRangeFormatting);
|
||||
}
|
||||
|
||||
promise<void> dispatch(json::Value value, Writer& writer);
|
||||
promise<void> dispatch(json::Value value);
|
||||
|
||||
void run(int argc, const char** argv) {
|
||||
auto loop = [this](json::Value value) -> promise<void> {
|
||||
co_await dispatch(std::move(value));
|
||||
};
|
||||
async::start_server(loop, "127.0.0.1", 50051);
|
||||
}
|
||||
|
||||
private:
|
||||
using onRequest = llvm::unique_function<promise<void>(json::Value, json::Value)>;
|
||||
@@ -177,7 +177,7 @@ private:
|
||||
|
||||
template <typename Param>
|
||||
void addMethod(llvm::StringRef name,
|
||||
promise<void> (LSPServer::*method)(json::Value, const Param&)) {
|
||||
promise<void> (Server::*method)(json::Value, const Param&)) {
|
||||
requests.try_emplace(name,
|
||||
[this, method](json::Value id, json::Value value) -> promise<void> {
|
||||
co_await (this->*method)(std::move(id),
|
||||
@@ -186,7 +186,7 @@ private:
|
||||
}
|
||||
|
||||
template <typename Param>
|
||||
void addMethod(llvm::StringRef name, promise<void> (LSPServer::*method)(const Param&)) {
|
||||
void addMethod(llvm::StringRef name, promise<void> (Server::*method)(const Param&)) {
|
||||
notifications.try_emplace(name, [this, method](json::Value value) -> promise<void> {
|
||||
co_await (this->*method)(json::deserialize<Param>(value));
|
||||
});
|
||||
@@ -275,7 +275,73 @@ private:
|
||||
const proto::DocumentRangeFormattingParams& params);
|
||||
|
||||
private:
|
||||
Writer* writer;
|
||||
/// Information of building precompiled header.
|
||||
struct PCH {
|
||||
/// The path of this PCH.
|
||||
std::string path;
|
||||
/// The source file path.
|
||||
std::string sourcePath;
|
||||
/// The header part of source file used to build this PCH.
|
||||
std::string preamble;
|
||||
/// The arguments used to build this PCH.
|
||||
std::string arguments;
|
||||
/// All files involved in building this PCH(excluding the source file).
|
||||
std::vector<std::string> deps;
|
||||
|
||||
/// FIXME: use asyncronous file system API.
|
||||
bool needUpdate(llvm::StringRef sourceContent) {
|
||||
/// Check whether the header part changed.
|
||||
if(sourceContent.substr(0, preamble.size()) != preamble) {
|
||||
return true;
|
||||
}
|
||||
|
||||
/// Check timestamp of all files involved in building this PCH.
|
||||
fs::file_status build;
|
||||
if(auto error = fs::status(path, build)) {
|
||||
llvm::errs() << "Error: " << error.message() << "\n";
|
||||
std::terminate();
|
||||
}
|
||||
|
||||
/// TODO: check whether deps changed through comparing timestamps.
|
||||
return false;
|
||||
}
|
||||
};
|
||||
|
||||
/// Information of building precompiled module.
|
||||
struct PCM {};
|
||||
|
||||
promise<void> updatePCH() {
|
||||
co_return;
|
||||
}
|
||||
|
||||
promise<void> updatePCM() {
|
||||
co_return;
|
||||
}
|
||||
|
||||
promise<void> buildAST(llvm::StringRef filepath, llvm::StringRef content) {
|
||||
llvm::SmallString<128> path = filepath;
|
||||
|
||||
/// FIXME: lookup from CDB file and adjust and remove unnecessary arguments.
|
||||
llvm::SmallVector<const char*> args = {
|
||||
"clang++",
|
||||
"-std=c++20",
|
||||
path.c_str(),
|
||||
"-resource-dir",
|
||||
"/home/ykiko/C++/clice2/build/lib/clang/20",
|
||||
};
|
||||
|
||||
/// through arguments to judge is it a module.
|
||||
bool isModule = false;
|
||||
co_await (isModule ? updatePCM() : updatePCH());
|
||||
|
||||
auto compiler = co_await async::schedule_task([=]() {
|
||||
std::unique_ptr<Compiler> compiler = std::make_unique<Compiler>(path, content, args);
|
||||
compiler->buildAST();
|
||||
return compiler;
|
||||
});
|
||||
}
|
||||
|
||||
private:
|
||||
llvm::StringMap<onRequest> requests;
|
||||
llvm::StringMap<onNotification> notifications;
|
||||
};
|
||||
|
||||
@@ -2,11 +2,17 @@
|
||||
|
||||
#include "llvm/ADT/SmallString.h"
|
||||
|
||||
namespace clice {
|
||||
namespace clice::async {
|
||||
|
||||
using Callback = llvm::unique_function<promise<void>(json::Value)>;
|
||||
uv_loop_t* loop = uv_default_loop();
|
||||
|
||||
namespace {
|
||||
|
||||
static void onAlloc(uv_handle_t* handle, size_t suggested_size, uv_buf_t* buf) {
|
||||
Callback callback = {};
|
||||
uv_stream_t* writer = {};
|
||||
|
||||
void on_alloc(uv_handle_t* handle, size_t suggested_size, uv_buf_t* buf) {
|
||||
/// This function is called synchronously before `on_read`. See the implementation of
|
||||
/// `uv__read` in libuv/src/unix/stream.c. So it is safe to use a static buffer here.
|
||||
static llvm::SmallString<65536> buffer;
|
||||
@@ -45,7 +51,7 @@ private:
|
||||
llvm::SmallString<4096> buffer;
|
||||
};
|
||||
|
||||
void onRead(uv_stream_t* stream, ssize_t nread, const uv_buf_t* buf) {
|
||||
void on_read(uv_stream_t* stream, ssize_t nread, const uv_buf_t* buf) {
|
||||
/// We have at most one connection and use default event loop. So there is no data race
|
||||
/// risk. It is safe to use a static buffer here.
|
||||
|
||||
@@ -54,9 +60,8 @@ void onRead(uv_stream_t* stream, ssize_t nread, const uv_buf_t* buf) {
|
||||
if(nread > 0) {
|
||||
buffer.append({buf->base, static_cast<std::size_t>(nread)});
|
||||
if(auto message = buffer.peek(); !message.empty()) {
|
||||
auto& server = *static_cast<Server*>(stream->data);
|
||||
if(auto json = json::parse(message)) {
|
||||
async::schedule(server.callback(std::move(*json), server.writer));
|
||||
async::schedule(callback(std::move(*json)));
|
||||
buffer.consume();
|
||||
} else {
|
||||
llvm::errs() << "JSON PARSE ERROR " << json.takeError() << "\n";
|
||||
@@ -72,34 +77,28 @@ void onRead(uv_stream_t* stream, ssize_t nread, const uv_buf_t* buf) {
|
||||
|
||||
} // namespace
|
||||
|
||||
Server::Server(Callback callback) : callback(std::move(callback)) {
|
||||
void start_server(Callback callback) {
|
||||
static uv_pipe_t in;
|
||||
static uv_pipe_t out;
|
||||
|
||||
writer.handle = &out;
|
||||
async::callback = std::move(callback);
|
||||
writer = reinterpret_cast<uv_stream_t*>(&out);
|
||||
|
||||
uv_pipe_init(async::loop, &in, 0);
|
||||
uv_pipe_init(async::loop, &out, 0);
|
||||
int r = uv_read_start((uv_stream_t*)&in, async::on_alloc, async::on_read);
|
||||
|
||||
in.data = this;
|
||||
out.data = this;
|
||||
|
||||
int r = uv_read_start((uv_stream_t*)&in, onAlloc, onRead);
|
||||
uv_run(async::loop, UV_RUN_DEFAULT);
|
||||
}
|
||||
|
||||
Server::Server(Callback callback, const char* ip, unsigned int port) :
|
||||
callback(std::move(callback)) {
|
||||
void start_server(Callback callback, const char* ip, unsigned int port) {
|
||||
static uv_tcp_t server;
|
||||
static uv_tcp_t client;
|
||||
|
||||
writer.handle = &client;
|
||||
async::callback = std::move(callback);
|
||||
writer = reinterpret_cast<uv_stream_t*>(&client);
|
||||
|
||||
uv_tcp_init(async::loop, &server);
|
||||
uv_tcp_init(async::loop, &client);
|
||||
|
||||
server.data = this;
|
||||
client.data = this;
|
||||
|
||||
struct sockaddr_in addr;
|
||||
uv_ip4_addr(ip, port, &addr);
|
||||
|
||||
@@ -112,14 +111,16 @@ Server::Server(Callback callback, const char* ip, unsigned int port) :
|
||||
|
||||
if(uv_accept(server, (uv_stream_t*)&client) == 0) {
|
||||
llvm::errs() << "Client connected.\n";
|
||||
uv_read_start((uv_stream_t*)&client, onAlloc, onRead);
|
||||
uv_read_start((uv_stream_t*)&client, async::on_alloc, async::on_read);
|
||||
} else {
|
||||
uv_close((uv_handle_t*)&client, NULL);
|
||||
}
|
||||
});
|
||||
|
||||
uv_run(async::loop, UV_RUN_DEFAULT);
|
||||
}
|
||||
|
||||
void Writer::write(json::Value id, json::Value result) {
|
||||
void write(json::Value id, json::Value result) {
|
||||
json::Value response = json::Object{
|
||||
{"jsonrpc", "2.0" },
|
||||
{"id", id },
|
||||
@@ -156,11 +157,11 @@ void Writer::write(json::Value id, json::Value result) {
|
||||
delete req;
|
||||
};
|
||||
|
||||
int r = uv_write(req, static_cast<uv_stream_t*>(handle), bufs, 2, on_write);
|
||||
int r = uv_write(req, writer, bufs, 2, on_write);
|
||||
|
||||
if(r) {
|
||||
llvm::errs() << "Write error: " << uv_strerror(r) << "\n";
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace clice
|
||||
} // namespace clice::async
|
||||
|
||||
@@ -3,34 +3,29 @@
|
||||
|
||||
namespace clice {
|
||||
|
||||
promise<void> CacheManager::buildPCH(std::string file, std::string content) {
|
||||
|
||||
co_return;
|
||||
}
|
||||
|
||||
promise<void> LSPServer::onInitialize(json::Value id, const proto::InitializeParams& params) {
|
||||
promise<void> Server::onInitialize(json::Value id, const proto::InitializeParams& params) {
|
||||
llvm::outs() << "onInitialize\n";
|
||||
writer->write(std::move(id), json::serialize(proto::InitializeResult()));
|
||||
async::write(std::move(id), json::serialize(proto::InitializeResult()));
|
||||
async::sleep(std::chrono::seconds(10));
|
||||
co_return;
|
||||
}
|
||||
|
||||
promise<void> LSPServer::onInitialized(const proto::InitializedParams& params) {
|
||||
promise<void> Server::onInitialized(const proto::InitializedParams& params) {
|
||||
llvm::outs() << "onInitialized\n";
|
||||
co_return;
|
||||
}
|
||||
|
||||
promise<void> LSPServer::onExit(const proto::None&) {
|
||||
promise<void> Server::onExit(const proto::None&) {
|
||||
llvm::outs() << "onExit\n";
|
||||
co_return;
|
||||
}
|
||||
|
||||
promise<void> LSPServer::onShutdown(json::Value id, const proto::None&) {
|
||||
promise<void> Server::onShutdown(json::Value id, const proto::None&) {
|
||||
llvm::outs() << "onShutdown\n";
|
||||
co_return;
|
||||
}
|
||||
|
||||
promise<void> LSPServer::onDidOpen(const proto::DidOpenTextDocumentParams& params) {
|
||||
promise<void> Server::onDidOpen(const proto::DidOpenTextDocumentParams& params) {
|
||||
llvm::outs() << "onDidOpen: " << params.textDocument.uri << "\n";
|
||||
auto path = URI::resolve(params.textDocument.uri);
|
||||
llvm::StringRef content = params.textDocument.text;
|
||||
@@ -60,22 +55,140 @@ promise<void> LSPServer::onDidOpen(const proto::DidOpenTextDocumentParams& param
|
||||
co_return;
|
||||
}
|
||||
|
||||
promise<void> LSPServer::dispatch(json::Value value, Writer& writer) {
|
||||
this->writer = &writer;
|
||||
promise<void> Server::onDidChange(const proto::DidChangeTextDocumentParams& document) {
|
||||
co_return;
|
||||
}
|
||||
|
||||
promise<void> Server::onDidSave(const proto::DidSaveTextDocumentParams& document) {
|
||||
co_return;
|
||||
}
|
||||
|
||||
promise<void> Server::onDidClose(const proto::DidCloseTextDocumentParams& document) {
|
||||
co_return;
|
||||
}
|
||||
|
||||
promise<void> Server::onGotoDeclaration(json::Value id, const proto::DeclarationParams& params) {
|
||||
co_return;
|
||||
}
|
||||
|
||||
promise<void> Server::onGotoDefinition(json::Value id, const proto::DefinitionParams& params) {
|
||||
co_return;
|
||||
}
|
||||
|
||||
promise<void> Server::onGotoTypeDefinition(json::Value id,
|
||||
const proto::TypeDefinitionParams& params) {
|
||||
co_return;
|
||||
}
|
||||
|
||||
promise<void> Server::onGotoImplementation(json::Value id,
|
||||
const proto::ImplementationParams& params) {
|
||||
co_return;
|
||||
}
|
||||
|
||||
promise<void> Server::onFindReferences(json::Value id, const proto::ReferenceParams& params) {
|
||||
co_return;
|
||||
}
|
||||
|
||||
promise<void> Server::onPrepareCallHierarchy(json::Value id,
|
||||
const proto::CallHierarchyPrepareParams& params) {
|
||||
co_return;
|
||||
}
|
||||
|
||||
promise<void> Server::onIncomingCall(json::Value id,
|
||||
const proto::CallHierarchyIncomingCallsParams& params) {
|
||||
co_return;
|
||||
}
|
||||
|
||||
promise<void> Server::onOutgoingCall(json::Value id,
|
||||
const proto::CallHierarchyOutgoingCallsParams& params) {
|
||||
co_return;
|
||||
}
|
||||
|
||||
promise<void> Server::onPrepareTypeHierarchy(json::Value id,
|
||||
const proto::TypeHierarchyPrepareParams& params) {
|
||||
co_return;
|
||||
}
|
||||
|
||||
promise<void> Server::onSupertypes(json::Value id,
|
||||
const proto::TypeHierarchySupertypesParams& params) {
|
||||
co_return;
|
||||
}
|
||||
|
||||
promise<void> Server::onSubtypes(json::Value id, const proto::TypeHierarchySubtypesParams& params) {
|
||||
co_return;
|
||||
}
|
||||
|
||||
promise<void> Server::onDocumentHighlight(json::Value id,
|
||||
const proto::DocumentHighlightParams& params) {
|
||||
co_return;
|
||||
}
|
||||
|
||||
promise<void> Server::onDocumentLink(json::Value id, const proto::DocumentLinkParams& params) {
|
||||
co_return;
|
||||
}
|
||||
|
||||
promise<void> Server::onHover(json::Value id, const proto::HoverParams& params) {
|
||||
co_return;
|
||||
}
|
||||
|
||||
promise<void> Server::onCodeLens(json::Value id, const proto::CodeLensParams& params) {
|
||||
co_return;
|
||||
}
|
||||
|
||||
promise<void> Server::onFoldingRange(json::Value id, const proto::FoldingRangeParams& params) {
|
||||
co_return;
|
||||
}
|
||||
|
||||
promise<void> Server::onDocumentSymbol(json::Value id, const proto::DocumentSymbolParams& params) {
|
||||
co_return;
|
||||
}
|
||||
|
||||
promise<void> Server::onSemanticTokens(json::Value id, const proto::SemanticTokensParams& params) {
|
||||
co_return;
|
||||
}
|
||||
|
||||
promise<void> Server::onInlayHint(json::Value id, const proto::InlayHintParams& params) {
|
||||
co_return;
|
||||
}
|
||||
|
||||
promise<void> Server::onCodeCompletion(json::Value id, const proto::CompletionParams& params) {
|
||||
co_return;
|
||||
}
|
||||
|
||||
promise<void> Server::onSignatureHelp(json::Value id, const proto::SignatureHelpParams& params) {
|
||||
co_return;
|
||||
}
|
||||
|
||||
promise<void> Server::onCodeAction(json::Value id, const proto::CodeActionParams& params) {
|
||||
co_return;
|
||||
}
|
||||
|
||||
promise<void> Server::onFormatting(json::Value id, const proto::DocumentFormattingParams& params) {
|
||||
co_return;
|
||||
}
|
||||
|
||||
promise<void> Server::onRangeFormatting(json::Value id,
|
||||
const proto::DocumentRangeFormattingParams& params) {
|
||||
co_return;
|
||||
}
|
||||
|
||||
promise<void> Server::dispatch(json::Value value) {
|
||||
assert(value.kind() == json::Value::Object);
|
||||
auto object = value.getAsObject();
|
||||
assert(object && "value is not an object");
|
||||
if(auto method = object->get("method")) {
|
||||
auto name = *method->getAsString();
|
||||
auto params = object->get("params");
|
||||
if(auto id = object->get("id")) {
|
||||
if(auto iter = requests.find(name); iter != requests.end()) {
|
||||
co_await iter->second(std::move(*id), std::move(*object->get("params")));
|
||||
co_await iter->second(std::move(*id),
|
||||
params ? std::move(*params) : json::Value(nullptr));
|
||||
} else {
|
||||
llvm::errs() << "Unknown request: " << name << "\n";
|
||||
}
|
||||
} else {
|
||||
if(auto iter = notifications.find(name); iter != notifications.end()) {
|
||||
co_await iter->second(std::move(*object->get("params")));
|
||||
co_await iter->second(params ? std::move(*params) : json::Value(nullptr));
|
||||
} else {
|
||||
llvm::errs() << "Unknown notification: " << name << "\n";
|
||||
}
|
||||
|
||||
@@ -1,15 +1,10 @@
|
||||
#include "Basic/Basic.h"
|
||||
#include "Server/Server.h"
|
||||
|
||||
using namespace clice;
|
||||
|
||||
int main(int argc, const char** argv) {
|
||||
LSPServer LSP;
|
||||
auto loop = [&LSP](json::Value value, Writer& writer) -> promise<void> {
|
||||
co_await LSP.dispatch(std::move(value), writer);
|
||||
};
|
||||
Server server(loop, "127.0.0.1", 50051);
|
||||
server.run();
|
||||
Server server;
|
||||
server.run(argc, argv);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user