Some update for Server.
This commit is contained in:
@@ -18,20 +18,16 @@
|
||||
#include <coroutine>
|
||||
#include <type_traits>
|
||||
|
||||
namespace clice {
|
||||
namespace clice::async {
|
||||
|
||||
template <typename T>
|
||||
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");
|
||||
assert(u && u->data && "uv_cast: invalid uv handle");
|
||||
return *static_cast<T*>(u->data);
|
||||
}
|
||||
|
||||
@@ -62,8 +58,8 @@ struct result {
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void return_value(T&& value) noexcept {
|
||||
new (&value) Value(std::forward<T>(value));
|
||||
void return_value(T&& val) noexcept {
|
||||
new (&value) Value(std::forward<T>(val));
|
||||
}
|
||||
};
|
||||
|
||||
@@ -96,138 +92,131 @@ void schedule(promise<T> promise) {
|
||||
schedule(promise.handle());
|
||||
}
|
||||
|
||||
template <typename Task, typename Ret = std::invoke_result_t<Task>>
|
||||
struct task_awaiter : result<Ret> {
|
||||
std::remove_cvref_t<Task> task;
|
||||
std::coroutine_handle<> caller;
|
||||
|
||||
void await_suspend(std::coroutine_handle<> caller) noexcept {
|
||||
static_assert(!std::is_reference_v<Ret>, "return type must not be a reference");
|
||||
this->caller = caller;
|
||||
uv_work_t* work = new uv_work_t{.data = this};
|
||||
uv_queue_work(
|
||||
loop,
|
||||
work,
|
||||
[](uv_work_t* work) {
|
||||
auto& awaiter = uv_cast<task_awaiter>(work);
|
||||
if constexpr(!std::is_void_v<Ret>) {
|
||||
new (&awaiter.value) Ret(awaiter.task());
|
||||
} else {
|
||||
awaiter.task();
|
||||
}
|
||||
},
|
||||
[](uv_work_t* work, int status) {
|
||||
auto& awaiter = uv_cast<task_awaiter>(work);
|
||||
awaiter.caller.resume();
|
||||
delete work;
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
/// Schedule a task to run in the thread pool.
|
||||
template <std::invocable Task>
|
||||
auto schedule_task(Task&& task) {
|
||||
using Func = std::remove_cvref_t<Task>;
|
||||
using Ret = std::invoke_result_t<Func>;
|
||||
|
||||
static_assert(!std::is_reference_v<Ret>, "return type must not be a reference");
|
||||
|
||||
struct Awaiter : result<Ret> {
|
||||
Func func;
|
||||
std::coroutine_handle<> caller;
|
||||
|
||||
void await_suspend(std::coroutine_handle<> caller) noexcept {
|
||||
this->caller = caller;
|
||||
uv_work_t* work = new uv_work_t{.data = this};
|
||||
uv_queue_work(
|
||||
loop,
|
||||
work,
|
||||
[](uv_work_t* work) {
|
||||
auto& awaiter = uv_cast<Awaiter>(work);
|
||||
if constexpr(!std::is_void_v<Ret>) {
|
||||
new (&awaiter.value) Ret(awaiter.func());
|
||||
} else {
|
||||
awaiter.func();
|
||||
}
|
||||
},
|
||||
[](uv_work_t* work, int status) {
|
||||
auto& awaiter = uv_cast<Awaiter>(work);
|
||||
awaiter.caller.resume();
|
||||
delete work;
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
return Awaiter{{}, std::forward<Task>(task)};
|
||||
task_awaiter<Task> schedule_task(Task&& task) {
|
||||
return {{}, std::forward<Task>(task)};
|
||||
}
|
||||
|
||||
inline auto sleep(std::chrono::milliseconds ms) {
|
||||
struct Awaiter {
|
||||
std::chrono::milliseconds ms;
|
||||
std::coroutine_handle<> caller;
|
||||
struct sleep_awaiter {
|
||||
std::chrono::milliseconds ms;
|
||||
std::coroutine_handle<> caller;
|
||||
|
||||
bool await_ready() noexcept {
|
||||
return ms.count() == 0;
|
||||
}
|
||||
bool await_ready() noexcept {
|
||||
return ms.count() == 0;
|
||||
}
|
||||
|
||||
void await_suspend(std::coroutine_handle<> caller) noexcept {
|
||||
this->caller = caller;
|
||||
uv_timer_t* timer = new uv_timer_t{.data = this};
|
||||
uv_timer_init(loop, timer);
|
||||
uv_timer_start(
|
||||
timer,
|
||||
[](uv_timer_t* timer) {
|
||||
auto& awaiter = uv_cast<Awaiter>(timer);
|
||||
awaiter.caller.resume();
|
||||
uv_close((uv_handle_t*)timer, [](uv_handle_t* handle) { delete handle; });
|
||||
},
|
||||
ms.count(),
|
||||
0);
|
||||
}
|
||||
void await_suspend(std::coroutine_handle<> caller) noexcept {
|
||||
this->caller = caller;
|
||||
uv_timer_t* timer = new uv_timer_t{.data = this};
|
||||
uv_timer_init(loop, timer);
|
||||
uv_timer_start(
|
||||
timer,
|
||||
[](uv_timer_t* timer) {
|
||||
auto& awaiter = uv_cast<sleep_awaiter>(timer);
|
||||
awaiter.caller.resume();
|
||||
uv_close((uv_handle_t*)timer, [](uv_handle_t* handle) { delete handle; });
|
||||
},
|
||||
ms.count(),
|
||||
0);
|
||||
}
|
||||
|
||||
void await_resume() noexcept {}
|
||||
};
|
||||
void await_resume() noexcept {}
|
||||
};
|
||||
|
||||
return Awaiter{ms};
|
||||
inline sleep_awaiter sleep(std::chrono::milliseconds ms) {
|
||||
return {ms};
|
||||
}
|
||||
|
||||
struct fs_awaiter {
|
||||
std::string path;
|
||||
std::coroutine_handle<> caller;
|
||||
std::chrono::system_clock::time_point modified;
|
||||
|
||||
bool await_ready() noexcept {
|
||||
return false;
|
||||
}
|
||||
|
||||
void await_suspend(std::coroutine_handle<> caller) noexcept {
|
||||
this->caller = caller;
|
||||
uv_fs_t* req = new uv_fs_t{.data = this};
|
||||
uv_fs_open(loop, req, path.c_str(), UV_FS_O_RDONLY, 0, [](uv_fs_t* req) {
|
||||
auto& awaiter = uv_cast<fs_awaiter>(req);
|
||||
if(req->result < 0) {
|
||||
llvm::errs() << "Error: " << uv_strerror(req->result) << "\n";
|
||||
awaiter.caller.resume();
|
||||
delete req;
|
||||
return;
|
||||
}
|
||||
|
||||
uv_fs_close(loop, req, req->result, [](uv_fs_t* req) {
|
||||
auto& awaiter = uv_cast<fs_awaiter>(req);
|
||||
uv_timespec_t& mtime = req->statbuf.st_mtim;
|
||||
using namespace std::chrono;
|
||||
awaiter.modified =
|
||||
system_clock::time_point(seconds(mtime.tv_sec) + nanoseconds(mtime.tv_nsec));
|
||||
awaiter.caller.resume();
|
||||
delete req;
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
decltype(auto) await_resume() noexcept {
|
||||
return modified;
|
||||
}
|
||||
};
|
||||
|
||||
inline fs_awaiter modified_time(llvm::StringRef path) {
|
||||
return {path.str()};
|
||||
}
|
||||
|
||||
template <typename... Ps>
|
||||
int run(Ps&&... ps) {
|
||||
(schedule(std::forward<Ps>(ps)), ...);
|
||||
return uv_run(uv_default_loop(), UV_RUN_DEFAULT);
|
||||
return uv_run(loop, UV_RUN_DEFAULT);
|
||||
}
|
||||
|
||||
} // namespace clice::async
|
||||
|
||||
namespace clice {
|
||||
|
||||
template <typename T>
|
||||
class promise {
|
||||
public:
|
||||
struct promise_type : async::result<T> {
|
||||
std::coroutine_handle<> caller;
|
||||
struct awaiter {
|
||||
using coroutine_handle = typename promise<T>::coroutine_handle;
|
||||
|
||||
auto get_return_object() {
|
||||
return promise{std::coroutine_handle<promise_type>::from_promise(*this)};
|
||||
}
|
||||
|
||||
void unhandled_exception() {
|
||||
std::abort();
|
||||
}
|
||||
|
||||
std::suspend_always initial_suspend() {
|
||||
return {};
|
||||
}
|
||||
|
||||
auto final_suspend() noexcept {
|
||||
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};
|
||||
}
|
||||
};
|
||||
|
||||
using coroutine_handle = std::coroutine_handle<promise_type>;
|
||||
|
||||
promise(coroutine_handle handle) : h(handle) {}
|
||||
coroutine_handle h;
|
||||
|
||||
bool await_ready() noexcept {
|
||||
return false;
|
||||
}
|
||||
|
||||
void await_suspend(std::coroutine_handle<> handle) noexcept {
|
||||
this->h.promise().caller = handle;
|
||||
async::schedule(*this);
|
||||
h.promise().caller = handle;
|
||||
async::schedule(h);
|
||||
}
|
||||
|
||||
decltype(auto) await_resume() noexcept
|
||||
@@ -239,6 +228,68 @@ public:
|
||||
void await_resume() noexcept
|
||||
requires (std::is_void_v<T>)
|
||||
{}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct promise_type : result<T> {
|
||||
std::coroutine_handle<> caller;
|
||||
|
||||
auto get_return_object() {
|
||||
return promise{std::coroutine_handle<promise_type>::from_promise(*this)};
|
||||
}
|
||||
|
||||
void unhandled_exception() {
|
||||
std::abort();
|
||||
}
|
||||
|
||||
std::suspend_always initial_suspend() {
|
||||
return {};
|
||||
}
|
||||
|
||||
auto final_suspend() noexcept {
|
||||
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};
|
||||
}
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
class promise {
|
||||
public:
|
||||
using promise_type = async::promise_type<T>;
|
||||
|
||||
using coroutine_handle = std::coroutine_handle<promise_type>;
|
||||
|
||||
promise(coroutine_handle handle) : h(handle) {}
|
||||
|
||||
promise(const promise&) = delete;
|
||||
|
||||
promise(promise&& other) : h(other.h) {
|
||||
other.h = nullptr;
|
||||
}
|
||||
|
||||
awaiter<T> operator co_await() const noexcept {
|
||||
return {h};
|
||||
}
|
||||
|
||||
coroutine_handle handle() const noexcept {
|
||||
return h;
|
||||
@@ -248,5 +299,5 @@ private:
|
||||
coroutine_handle h;
|
||||
};
|
||||
|
||||
} // namespace clice
|
||||
} // namespace clice::async
|
||||
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
#include <spdlog/sinks/basic_file_sink.h>
|
||||
#include <spdlog/sinks/stdout_color_sinks.h>
|
||||
|
||||
#include <Support/Format.h>
|
||||
#include <Support/FileSystem.h>
|
||||
#include <llvm/ADT/SmallString.h>
|
||||
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
#include "Async.h"
|
||||
#include "Config.h"
|
||||
#include "Logger.h"
|
||||
#include "Basic/Document.h"
|
||||
#include "Compiler/Compiler.h"
|
||||
#include "Support/JSON.h"
|
||||
@@ -125,154 +126,123 @@ namespace clice {
|
||||
|
||||
class Server {
|
||||
public:
|
||||
Server() {
|
||||
addMethod("initialize", &Server::onInitialize);
|
||||
addMethod("initialized", &Server::onInitialized);
|
||||
addMethod("shutdown", &Server::onShutdown);
|
||||
addMethod("exit", &Server::onExit);
|
||||
Server();
|
||||
|
||||
addMethod("textDocument/didOpen", &Server::onDidOpen);
|
||||
addMethod("textDocument/didChange", &Server::onDidChange);
|
||||
addMethod("textDocument/didSave", &Server::onDidSave);
|
||||
addMethod("textDocument/didClose", &Server::onDidClose);
|
||||
|
||||
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);
|
||||
|
||||
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);
|
||||
}
|
||||
void run(int argc, const char** argv);
|
||||
|
||||
private:
|
||||
using onRequest = llvm::unique_function<promise<void>(json::Value, json::Value)>;
|
||||
using onNotification = llvm::unique_function<promise<void>(json::Value)>;
|
||||
using onRequest = llvm::unique_function<async::promise<void>(json::Value, json::Value)>;
|
||||
using onNotification = llvm::unique_function<async::promise<void>(json::Value)>;
|
||||
|
||||
template <typename Param>
|
||||
void addMethod(llvm::StringRef name,
|
||||
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),
|
||||
json::deserialize<Param>(value));
|
||||
});
|
||||
async::promise<void> (Server::*method)(json::Value, const Param&)) {
|
||||
requests.try_emplace(
|
||||
name,
|
||||
[this, method](json::Value id, json::Value value) -> async::promise<void> {
|
||||
co_await (this->*method)(std::move(id), json::deserialize<Param>(value));
|
||||
});
|
||||
}
|
||||
|
||||
template <typename Param>
|
||||
void addMethod(llvm::StringRef name, promise<void> (Server::*method)(const Param&)) {
|
||||
notifications.try_emplace(name, [this, method](json::Value value) -> promise<void> {
|
||||
void addMethod(llvm::StringRef name, async::promise<void> (Server::*method)(const Param&)) {
|
||||
notifications.try_emplace(name, [this, method](json::Value value) -> async::promise<void> {
|
||||
co_await (this->*method)(json::deserialize<Param>(value));
|
||||
});
|
||||
}
|
||||
|
||||
llvm::StringMap<onRequest> requests;
|
||||
llvm::StringMap<onNotification> notifications;
|
||||
|
||||
private:
|
||||
/// ============================================================================
|
||||
/// Lifestyle Message
|
||||
/// ============================================================================
|
||||
|
||||
promise<void> onInitialize(json::Value id, const proto::InitializeParams& params);
|
||||
async::promise<void> onInitialize(json::Value id, const proto::InitializeParams& params);
|
||||
|
||||
promise<void> onInitialized(const proto::InitializedParams& params);
|
||||
async::promise<void> onInitialized(const proto::InitializedParams& params);
|
||||
|
||||
promise<void> onShutdown(json::Value id, const proto::None&);
|
||||
async::promise<void> onShutdown(json::Value id, const proto::None&);
|
||||
|
||||
promise<void> onExit(const proto::None&);
|
||||
async::promise<void> onExit(const proto::None&);
|
||||
|
||||
/// ============================================================================
|
||||
/// Document Synchronization
|
||||
/// ============================================================================
|
||||
|
||||
promise<void> onDidOpen(const proto::DidOpenTextDocumentParams& document);
|
||||
async::promise<void> onDidOpen(const proto::DidOpenTextDocumentParams& document);
|
||||
|
||||
promise<void> onDidChange(const proto::DidChangeTextDocumentParams& document);
|
||||
async::promise<void> onDidChange(const proto::DidChangeTextDocumentParams& document);
|
||||
|
||||
promise<void> onDidSave(const proto::DidSaveTextDocumentParams& document);
|
||||
async::promise<void> onDidSave(const proto::DidSaveTextDocumentParams& document);
|
||||
|
||||
promise<void> onDidClose(const proto::DidCloseTextDocumentParams& document);
|
||||
async::promise<void> onDidClose(const proto::DidCloseTextDocumentParams& document);
|
||||
|
||||
/// ============================================================================
|
||||
/// Language Features
|
||||
/// ============================================================================
|
||||
|
||||
promise<void> onGotoDeclaration(json::Value id, const proto::DeclarationParams& params);
|
||||
async::promise<void> onGotoDeclaration(json::Value id, const proto::DeclarationParams& params);
|
||||
|
||||
promise<void> onGotoDefinition(json::Value id, const proto::DefinitionParams& params);
|
||||
async::promise<void> onGotoDefinition(json::Value id, const proto::DefinitionParams& params);
|
||||
|
||||
promise<void> onGotoTypeDefinition(json::Value id, const proto::TypeDefinitionParams& params);
|
||||
async::promise<void> onGotoTypeDefinition(json::Value id,
|
||||
const proto::TypeDefinitionParams& params);
|
||||
|
||||
promise<void> onGotoImplementation(json::Value id, const proto::ImplementationParams& params);
|
||||
async::promise<void> onGotoImplementation(json::Value id,
|
||||
const proto::ImplementationParams& params);
|
||||
|
||||
promise<void> onFindReferences(json::Value id, const proto::ReferenceParams& params);
|
||||
async::promise<void> onFindReferences(json::Value id, const proto::ReferenceParams& params);
|
||||
|
||||
promise<void> onPrepareCallHierarchy(json::Value id,
|
||||
const proto::CallHierarchyPrepareParams& params);
|
||||
async::promise<void> onPrepareCallHierarchy(json::Value id,
|
||||
const proto::CallHierarchyPrepareParams& params);
|
||||
|
||||
promise<void> onIncomingCall(json::Value id,
|
||||
const proto::CallHierarchyIncomingCallsParams& params);
|
||||
async::promise<void> onIncomingCall(json::Value id,
|
||||
const proto::CallHierarchyIncomingCallsParams& params);
|
||||
|
||||
promise<void> onOutgoingCall(json::Value id,
|
||||
const proto::CallHierarchyOutgoingCallsParams& params);
|
||||
async::promise<void> onOutgoingCall(json::Value id,
|
||||
const proto::CallHierarchyOutgoingCallsParams& params);
|
||||
|
||||
promise<void> onPrepareTypeHierarchy(json::Value id,
|
||||
const proto::TypeHierarchyPrepareParams& params);
|
||||
async::promise<void> onPrepareTypeHierarchy(json::Value id,
|
||||
const proto::TypeHierarchyPrepareParams& params);
|
||||
|
||||
promise<void> onSupertypes(json::Value id, const proto::TypeHierarchySupertypesParams& params);
|
||||
async::promise<void> onSupertypes(json::Value id,
|
||||
const proto::TypeHierarchySupertypesParams& params);
|
||||
|
||||
promise<void> onSubtypes(json::Value id, const proto::TypeHierarchySubtypesParams& params);
|
||||
async::promise<void> onSubtypes(json::Value id,
|
||||
const proto::TypeHierarchySubtypesParams& params);
|
||||
|
||||
promise<void> onDocumentHighlight(json::Value id, const proto::DocumentHighlightParams& params);
|
||||
async::promise<void> onDocumentHighlight(json::Value id,
|
||||
const proto::DocumentHighlightParams& params);
|
||||
|
||||
promise<void> onDocumentLink(json::Value id, const proto::DocumentLinkParams& params);
|
||||
async::promise<void> onDocumentLink(json::Value id, const proto::DocumentLinkParams& params);
|
||||
|
||||
promise<void> onHover(json::Value id, const proto::HoverParams& params);
|
||||
async::promise<void> onHover(json::Value id, const proto::HoverParams& params);
|
||||
|
||||
promise<void> onCodeLens(json::Value id, const proto::CodeLensParams& params);
|
||||
async::promise<void> onCodeLens(json::Value id, const proto::CodeLensParams& params);
|
||||
|
||||
promise<void> onFoldingRange(json::Value id, const proto::FoldingRangeParams& params);
|
||||
async::promise<void> onFoldingRange(json::Value id, const proto::FoldingRangeParams& params);
|
||||
|
||||
promise<void> onDocumentSymbol(json::Value id, const proto::DocumentSymbolParams& params);
|
||||
async::promise<void> onDocumentSymbol(json::Value id,
|
||||
const proto::DocumentSymbolParams& params);
|
||||
|
||||
promise<void> onSemanticTokens(json::Value id, const proto::SemanticTokensParams& params);
|
||||
async::promise<void> onSemanticTokens(json::Value id,
|
||||
const proto::SemanticTokensParams& params);
|
||||
|
||||
promise<void> onInlayHint(json::Value id, const proto::InlayHintParams& params);
|
||||
async::promise<void> onInlayHint(json::Value id, const proto::InlayHintParams& params);
|
||||
|
||||
promise<void> onCodeCompletion(json::Value id, const proto::CompletionParams& params);
|
||||
async::promise<void> onCodeCompletion(json::Value id, const proto::CompletionParams& params);
|
||||
|
||||
promise<void> onSignatureHelp(json::Value id, const proto::SignatureHelpParams& params);
|
||||
async::promise<void> onSignatureHelp(json::Value id, const proto::SignatureHelpParams& params);
|
||||
|
||||
promise<void> onCodeAction(json::Value id, const proto::CodeActionParams& params);
|
||||
async::promise<void> onCodeAction(json::Value id, const proto::CodeActionParams& params);
|
||||
|
||||
promise<void> onFormatting(json::Value id, const proto::DocumentFormattingParams& params);
|
||||
async::promise<void> onFormatting(json::Value id,
|
||||
const proto::DocumentFormattingParams& params);
|
||||
|
||||
promise<void> onRangeFormatting(json::Value id,
|
||||
const proto::DocumentRangeFormattingParams& params);
|
||||
async::promise<void> onRangeFormatting(json::Value id,
|
||||
const proto::DocumentRangeFormattingParams& params);
|
||||
|
||||
private:
|
||||
/// Information of building precompiled header.
|
||||
@@ -310,40 +280,51 @@ private:
|
||||
/// Information of building precompiled module.
|
||||
struct PCM {};
|
||||
|
||||
promise<void> updatePCH() {
|
||||
async::promise<void> updatePCH(llvm::StringRef filepath,
|
||||
llvm::StringRef content,
|
||||
llvm::ArrayRef<const char*> args);
|
||||
|
||||
async::promise<void> updatePCM() {
|
||||
co_return;
|
||||
}
|
||||
|
||||
promise<void> updatePCM() {
|
||||
co_return;
|
||||
}
|
||||
async::promise<void> buildAST(llvm::StringRef filepath, llvm::StringRef content);
|
||||
|
||||
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",
|
||||
struct TranslationUnit {
|
||||
enum class State {
|
||||
Building,
|
||||
Ready,
|
||||
};
|
||||
|
||||
/// through arguments to judge is it a module.
|
||||
bool isModule = false;
|
||||
co_await (isModule ? updatePCM() : updatePCH());
|
||||
enum class TaskKind {
|
||||
Build,
|
||||
Consume,
|
||||
};
|
||||
|
||||
auto compiler = co_await async::schedule_task([=]() {
|
||||
std::unique_ptr<Compiler> compiler = std::make_unique<Compiler>(path, content, args);
|
||||
compiler->buildAST();
|
||||
return compiler;
|
||||
});
|
||||
struct Task {
|
||||
TaskKind kind;
|
||||
async::promise<void> request;
|
||||
};
|
||||
|
||||
State state;
|
||||
std::unique_ptr<Compiler> compiler;
|
||||
std::vector<Task> tasks;
|
||||
};
|
||||
|
||||
async::promise<void> schedule(llvm::StringRef path, async::promise<void> request) {
|
||||
auto& unit = units[path];
|
||||
if(unit.state == TranslationUnit::State::Building) {
|
||||
// unit.requests.push_back(std::move(request));
|
||||
} else {
|
||||
co_await request;
|
||||
}
|
||||
|
||||
co_return;
|
||||
}
|
||||
|
||||
private:
|
||||
llvm::StringMap<onRequest> requests;
|
||||
llvm::StringMap<onNotification> notifications;
|
||||
llvm::StringMap<PCH> pchs;
|
||||
llvm::StringMap<TranslationUnit> units;
|
||||
};
|
||||
|
||||
} // namespace clice
|
||||
|
||||
@@ -46,7 +46,7 @@ bool Compiler::applyPCH(llvm::StringRef filepath, std::uint32_t bound, bool endA
|
||||
auto& preproc = instance->getPreprocessorOpts();
|
||||
preproc.UsePredefines = false;
|
||||
preproc.ImplicitPCHInclude = filepath;
|
||||
preproc.PrecompiledPreambleBytes.first = bound;
|
||||
preproc.PrecompiledPreambleBytes.first = {};
|
||||
preproc.PrecompiledPreambleBytes.second = endAtStart;
|
||||
preproc.DisablePCHOrModuleValidation = clang::DisableValidationForModuleKind::PCH;
|
||||
return true;
|
||||
|
||||
@@ -3,199 +3,303 @@
|
||||
|
||||
namespace clice {
|
||||
|
||||
promise<void> Server::onInitialize(json::Value id, const proto::InitializeParams& params) {
|
||||
llvm::outs() << "onInitialize\n";
|
||||
Server::Server() {
|
||||
addMethod("initialize", &Server::onInitialize);
|
||||
addMethod("initialized", &Server::onInitialized);
|
||||
addMethod("shutdown", &Server::onShutdown);
|
||||
addMethod("exit", &Server::onExit);
|
||||
|
||||
addMethod("textDocument/didOpen", &Server::onDidOpen);
|
||||
addMethod("textDocument/didChange", &Server::onDidChange);
|
||||
addMethod("textDocument/didSave", &Server::onDidSave);
|
||||
addMethod("textDocument/didClose", &Server::onDidClose);
|
||||
|
||||
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);
|
||||
}
|
||||
|
||||
void Server::run(int argc, const char** argv) {
|
||||
logger::init("console", argv[0]);
|
||||
|
||||
auto dispatch = [this](json::Value value) -> async::promise<void> {
|
||||
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()) {
|
||||
logger::info("Request: {0}", name.str());
|
||||
co_await iter->second(std::move(*id),
|
||||
params ? std::move(*params) : json::Value(nullptr));
|
||||
} else {
|
||||
logger::error("Unknown request: {0}", name.str());
|
||||
}
|
||||
} else {
|
||||
if(auto iter = notifications.find(name); iter != notifications.end()) {
|
||||
logger::info("Notification: {0}", name.str());
|
||||
co_await iter->second(params ? std::move(*params) : json::Value(nullptr));
|
||||
} else {
|
||||
logger::error("Unknown notification: {0}", name.str());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
co_return;
|
||||
};
|
||||
|
||||
async::start_server(dispatch, "127.0.0.1", 50051);
|
||||
}
|
||||
|
||||
async::promise<void> Server::onInitialize(json::Value id, const proto::InitializeParams& params) {
|
||||
async::write(std::move(id), json::serialize(proto::InitializeResult()));
|
||||
async::sleep(std::chrono::seconds(10));
|
||||
co_return;
|
||||
}
|
||||
|
||||
promise<void> Server::onInitialized(const proto::InitializedParams& params) {
|
||||
llvm::outs() << "onInitialized\n";
|
||||
async::promise<void> Server::onInitialized(const proto::InitializedParams& params) {
|
||||
co_return;
|
||||
}
|
||||
|
||||
promise<void> Server::onExit(const proto::None&) {
|
||||
llvm::outs() << "onExit\n";
|
||||
async::promise<void> Server::onExit(const proto::None&) {
|
||||
co_return;
|
||||
}
|
||||
|
||||
promise<void> Server::onShutdown(json::Value id, const proto::None&) {
|
||||
llvm::outs() << "onShutdown\n";
|
||||
async::promise<void> Server::onShutdown(json::Value id, const proto::None&) {
|
||||
co_return;
|
||||
}
|
||||
|
||||
promise<void> Server::onDidOpen(const proto::DidOpenTextDocumentParams& params) {
|
||||
llvm::outs() << "onDidOpen: " << params.textDocument.uri << "\n";
|
||||
async::promise<void> Server::onDidOpen(const proto::DidOpenTextDocumentParams& params) {
|
||||
auto path = URI::resolve(params.textDocument.uri);
|
||||
llvm::StringRef content = params.textDocument.text;
|
||||
|
||||
co_await async::schedule_task([&]() {
|
||||
// TODO: lookup
|
||||
std::vector<const char*> args = {
|
||||
"clang++",
|
||||
"-std=c++20",
|
||||
path.c_str(),
|
||||
"-resource-dir",
|
||||
"/home/ykiko/C++/clice2/build/lib/clang/20",
|
||||
};
|
||||
Compiler compiler(path, content, args);
|
||||
co_await buildAST(path, content);
|
||||
|
||||
auto bounds = clang::Lexer::ComputePreamble(content, {}, false);
|
||||
co_return;
|
||||
}
|
||||
|
||||
llvm::outs() << "Generating PCH\n";
|
||||
async::promise<void> Server::onDidChange(const proto::DidChangeTextDocumentParams& document) {
|
||||
auto path = URI::resolve(document.textDocument.uri);
|
||||
llvm::StringRef content = document.contentChanges[0].text;
|
||||
|
||||
compiler.generatePCH("/home/ykiko/C++/clice2/build/cache/xxx.pch",
|
||||
bounds.Size,
|
||||
bounds.PreambleEndsAtStartOfLine);
|
||||
co_await buildAST(path, content);
|
||||
co_return;
|
||||
}
|
||||
|
||||
async::promise<void> Server::onDidSave(const proto::DidSaveTextDocumentParams& document) {
|
||||
co_return;
|
||||
}
|
||||
|
||||
async::promise<void> Server::onDidClose(const proto::DidCloseTextDocumentParams& document) {
|
||||
co_return;
|
||||
}
|
||||
|
||||
async::promise<void> Server::onGotoDeclaration(json::Value id,
|
||||
const proto::DeclarationParams& params) {
|
||||
co_return;
|
||||
}
|
||||
|
||||
async::promise<void> Server::onGotoDefinition(json::Value id,
|
||||
const proto::DefinitionParams& params) {
|
||||
co_return;
|
||||
}
|
||||
|
||||
async::promise<void> Server::onGotoTypeDefinition(json::Value id,
|
||||
const proto::TypeDefinitionParams& params) {
|
||||
co_return;
|
||||
}
|
||||
|
||||
async::promise<void> Server::onGotoImplementation(json::Value id,
|
||||
const proto::ImplementationParams& params) {
|
||||
co_return;
|
||||
}
|
||||
|
||||
async::promise<void> Server::onFindReferences(json::Value id,
|
||||
const proto::ReferenceParams& params) {
|
||||
co_return;
|
||||
}
|
||||
|
||||
async::promise<void>
|
||||
Server::onPrepareCallHierarchy(json::Value id,
|
||||
const proto::CallHierarchyPrepareParams& params) {
|
||||
co_return;
|
||||
}
|
||||
|
||||
async::promise<void> Server::onIncomingCall(json::Value id,
|
||||
const proto::CallHierarchyIncomingCallsParams& params) {
|
||||
co_return;
|
||||
}
|
||||
|
||||
async::promise<void> Server::onOutgoingCall(json::Value id,
|
||||
const proto::CallHierarchyOutgoingCallsParams& params) {
|
||||
co_return;
|
||||
}
|
||||
|
||||
async::promise<void>
|
||||
Server::onPrepareTypeHierarchy(json::Value id,
|
||||
const proto::TypeHierarchyPrepareParams& params) {
|
||||
co_return;
|
||||
}
|
||||
|
||||
async::promise<void> Server::onSupertypes(json::Value id,
|
||||
const proto::TypeHierarchySupertypesParams& params) {
|
||||
co_return;
|
||||
}
|
||||
|
||||
async::promise<void> Server::onSubtypes(json::Value id,
|
||||
const proto::TypeHierarchySubtypesParams& params) {
|
||||
co_return;
|
||||
}
|
||||
|
||||
async::promise<void> Server::onDocumentHighlight(json::Value id,
|
||||
const proto::DocumentHighlightParams& params) {
|
||||
co_return;
|
||||
}
|
||||
|
||||
async::promise<void> Server::onDocumentLink(json::Value id,
|
||||
const proto::DocumentLinkParams& params) {
|
||||
co_return;
|
||||
}
|
||||
|
||||
async::promise<void> Server::onHover(json::Value id, const proto::HoverParams& params) {
|
||||
co_return;
|
||||
}
|
||||
|
||||
async::promise<void> Server::onCodeLens(json::Value id, const proto::CodeLensParams& params) {
|
||||
co_return;
|
||||
}
|
||||
|
||||
async::promise<void> Server::onFoldingRange(json::Value id,
|
||||
const proto::FoldingRangeParams& params) {
|
||||
co_return;
|
||||
}
|
||||
|
||||
async::promise<void> Server::onDocumentSymbol(json::Value id,
|
||||
const proto::DocumentSymbolParams& params) {
|
||||
co_return;
|
||||
}
|
||||
|
||||
async::promise<void> Server::onSemanticTokens(json::Value id,
|
||||
const proto::SemanticTokensParams& params) {
|
||||
|
||||
co_return;
|
||||
}
|
||||
|
||||
async::promise<void> Server::onInlayHint(json::Value id, const proto::InlayHintParams& params) {
|
||||
co_return;
|
||||
}
|
||||
|
||||
async::promise<void> Server::onCodeCompletion(json::Value id,
|
||||
const proto::CompletionParams& params) {
|
||||
co_return;
|
||||
}
|
||||
|
||||
async::promise<void> Server::onSignatureHelp(json::Value id,
|
||||
const proto::SignatureHelpParams& params) {
|
||||
co_return;
|
||||
}
|
||||
|
||||
async::promise<void> Server::onCodeAction(json::Value id, const proto::CodeActionParams& params) {
|
||||
co_return;
|
||||
}
|
||||
|
||||
async::promise<void> Server::onFormatting(json::Value id,
|
||||
const proto::DocumentFormattingParams& params) {
|
||||
co_return;
|
||||
}
|
||||
|
||||
async::promise<void> Server::onRangeFormatting(json::Value id,
|
||||
const proto::DocumentRangeFormattingParams& params) {
|
||||
co_return;
|
||||
}
|
||||
|
||||
async::promise<void> Server::updatePCH(llvm::StringRef filepath,
|
||||
llvm::StringRef content,
|
||||
llvm::ArrayRef<const char*> args) {
|
||||
logger::info("Start building PCH for {0}", filepath.str());
|
||||
clang::PreambleBounds bounds = {0, 0};
|
||||
std::string outpath = "/home/ykiko/C++/clice2/build/cache/xxx.pch";
|
||||
co_await async::schedule_task([&] {
|
||||
Compiler compiler(filepath, content, args);
|
||||
bounds = clang::Lexer::ComputePreamble(content, {}, false);
|
||||
compiler.generatePCH(outpath, bounds.Size, bounds.PreambleEndsAtStartOfLine);
|
||||
});
|
||||
logger::info("Build PCH success");
|
||||
|
||||
llvm::outs() << "build PCH success\n";
|
||||
|
||||
co_return;
|
||||
}
|
||||
|
||||
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),
|
||||
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(params ? std::move(*params) : json::Value(nullptr));
|
||||
} else {
|
||||
llvm::errs() << "Unknown notification: " << name << "\n";
|
||||
}
|
||||
}
|
||||
auto preamble2 = content.substr(0, bounds.Size).str();
|
||||
if(bounds.PreambleEndsAtStartOfLine) {
|
||||
preamble2.append("@");
|
||||
}
|
||||
|
||||
pchs.try_emplace(filepath, PCH{.path = outpath, .preamble = std::move(preamble2)});
|
||||
co_return;
|
||||
}
|
||||
|
||||
async::promise<void> Server::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(filepath, content, args));
|
||||
|
||||
auto& pch = pchs.at(filepath);
|
||||
|
||||
logger::info("Start building AST for {0}", filepath.str());
|
||||
auto compiler = co_await async::schedule_task([&] {
|
||||
std::uint32_t boundSize = pch.preamble.size();
|
||||
bool endAtStart = false;
|
||||
if(pch.preamble.back() == '@') {
|
||||
boundSize -= 1;
|
||||
endAtStart = true;
|
||||
}
|
||||
|
||||
std::unique_ptr<Compiler> compiler = std::make_unique<Compiler>(path, content, args);
|
||||
compiler->applyPCH(pch.path, boundSize, endAtStart);
|
||||
compiler->buildAST();
|
||||
return compiler;
|
||||
});
|
||||
logger::info("Build AST success");
|
||||
|
||||
auto& unit = units[filepath];
|
||||
unit.state = TranslationUnit::State::Ready;
|
||||
unit.compiler = std::move(compiler);
|
||||
|
||||
for(auto& task: unit.tasks) {
|
||||
co_await task.request;
|
||||
if(task.kind == TranslationUnit::TaskKind::Build) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
} // namespace clice
|
||||
|
||||
Reference in New Issue
Block a user