diff --git a/include/Protocol/Basic.h b/include/Protocol/Basic.h index cc6171ff..b5311ca7 100644 --- a/include/Protocol/Basic.h +++ b/include/Protocol/Basic.h @@ -22,7 +22,7 @@ using integer = std::int32_t; /// range in [0, 2^31- 1] using uinteger = std::uint32_t; -using string = std::string; +using string = std::string_view; using DocumentUri = std::string; diff --git a/include/Protocol/Lifecycle.h b/include/Protocol/Lifecycle.h index 0330d610..d08d7d15 100644 --- a/include/Protocol/Lifecycle.h +++ b/include/Protocol/Lifecycle.h @@ -19,6 +19,15 @@ struct ClientInfo { struct ClientCapabilities {}; +struct Workplace { + /// The associated URI for this workspace folder. + string uri; + + /// The name of the workspace folder. Used to refer to this + /// workspace folder in the user interface. + string name; +}; + struct InitializeParams { /// Information about the client ClientInfo clientInfo; @@ -33,6 +42,12 @@ struct InitializeParams { /// The capabilities provided by the client (editor or tool). ClientCapabilities capabilities; + + /// The workspace folders configured in the client when the server starts. + /// This property is only available if the client supports workspace folders. + /// It can be `null` if the client supports workspace folders but none are + /// configured. + std::vector workspaceFolders; }; struct ServerCapabilities { diff --git a/include/Server/Option.h b/include/Server/Option.h index b18c3c59..85286566 100644 --- a/include/Server/Option.h +++ b/include/Server/Option.h @@ -5,10 +5,20 @@ namespace clice { struct Option { - std::string compile_commands_directory; - std::string resource_dictionary; + /// predefined variables. + struct { + int argc; + const char** argv; + /// clice binary dictionary. + std::string binary; + /// workplace dictionary. + std::string workplace; + }; - void parse(int argc, const char** argv); + std::string resource_dictionary; + std::string compile_commands_directory; + + void parse(std::string_view workplace); }; } // namespace clice diff --git a/include/Server/Scheduler .h b/include/Server/Scheduler.h similarity index 83% rename from include/Server/Scheduler .h rename to include/Server/Scheduler.h index e6d6ccd8..1f974458 100644 --- a/include/Server/Scheduler .h +++ b/include/Server/Scheduler.h @@ -17,9 +17,7 @@ private: }; public: - void update(std::string_view path, std::string_view content); - - void dispatch(json::Value&& params); + void dispatch(llvm::StringRef method, llvm::Value value); private: llvm::StringMap files; diff --git a/include/Server/Server.h b/include/Server/Server.h index 19dfd1b3..43c4d757 100644 --- a/include/Server/Server.h +++ b/include/Server/Server.h @@ -2,16 +2,13 @@ #include #include -#include +#include #include namespace clice { struct Server { - int argc; - const char** argv; - - using Handler = llvm::unique_function; + using Handler = llvm::unique_function; Option option; Scheduler scheduler; @@ -26,6 +23,10 @@ struct Server { void handleMessage(std::string_view message); + void notify(); + + void response(json::Value id, json::Value result); + public: // LSP methods, if the return type is void, the method is used for notification. // otherwise, the method is used for request. diff --git a/include/Support/JSON.h b/include/Support/JSON.h index c078e94b..8952789e 100644 --- a/include/Support/JSON.h +++ b/include/Support/JSON.h @@ -14,6 +14,9 @@ constexpr inline bool is_array_v = false; template constexpr inline bool is_array_v> = true; +template +constexpr inline bool is_array_v> = true; + template constexpr inline bool is_string_v = false; @@ -55,39 +58,31 @@ json::Value serialize(const Value& value) { } } -template -T deserialize(const Object& object) { - T result; - for_each(result, [&](llvm::StringRef name, Value& value) { - if constexpr(is_array_v) { - if(const auto* array = object.getArray(name)) { - for(std::size_t i = 0; i < array->size(); ++i) { - value[i] = deserialize((*array)[i]); - } - } - } else if constexpr(std::is_same_v) { - if(auto boolean = object.getBoolean(name)) { - value = *boolean; - } - } else if constexpr(is_integral_v) { - if(auto integer = object.getInteger(name)) { - value = *integer; - } - } else if constexpr(is_integral_v) { - if(auto floating = object.getNumber(name)) { - value = *floating; - } - } else if constexpr(std::is_same_v) { - if(auto string = object.getString(name)) { - value = *string; - } - } else { - if(auto subobject = object.getObject(name)) { - value = deserialize(*subobject); - } +template +Value deserialize(const json::Value& object) { + if constexpr(std::is_same_v) { + return object.getAsBoolean().value(); + } else if constexpr(is_integral_v || std::is_enum_v) { + return object.getAsInteger().value(); + } else if constexpr(std::is_floating_point_v) { + return object.getAsNumber().value(); + } else if constexpr(is_string_v) { + return object.getAsString().value(); + } else if constexpr(is_array_v) { + Value array; + for(const auto& element: *object.getAsArray()) { + array.push_back(deserialize(element)); } - }); - return result; + return array; + } else { + Value value; + for_each(value, [&](llvm::StringRef name, auto& field) { + if(auto element = object.getAsObject()->get(name)) { + field = deserialize>(*element); + } + }); + return value; + } } } // namespace clice::json diff --git a/src/Server/Option.cpp b/src/Server/Option.cpp index 117d8227..bfa29552 100644 --- a/src/Server/Option.cpp +++ b/src/Server/Option.cpp @@ -7,13 +7,6 @@ namespace clice { // TODO: replace builtin variable in Setting // e.g `{execute}` -> `execpath` -void Option::parse(int argc, const char** argv) { - auto execute = argv[0]; - // compile_commands_directory = path::parent_path(execute); -} - -namespace global { -Option option; -}; - +void Option::parse(std::string_view workplace) {} + } // namespace clice diff --git a/src/Server/Scheduler.cpp b/src/Server/Scheduler.cpp new file mode 100644 index 00000000..b1246187 --- /dev/null +++ b/src/Server/Scheduler.cpp @@ -0,0 +1,2 @@ +#include + diff --git a/src/Server/Server.cpp b/src/Server/Server.cpp index 71cfab33..32acd601 100644 --- a/src/Server/Server.cpp +++ b/src/Server/Server.cpp @@ -71,52 +71,29 @@ void read_stdin(uv_stream_t* stream, ssize_t nread, const uv_buf_t* buf) { } Server::Server() { - handlers.try_emplace("initialize", [](json::Value& id, json::Value& value) { - auto params = value.getAsObject(); - auto result = instance.initialize(json::deserialize(*params)); - - json::Object response; - response.try_emplace("jsonrpc", "2.0"); - response.try_emplace("id", id); - response.try_emplace("result", json::serialize(result)); - - json::Value responseValue = std::move(response); - - std::string s; - llvm::raw_string_ostream stream(s); - stream << responseValue; - stream.flush(); - - s = "Content-Length: " + std::to_string(s.size()) + "\r\n\r\n" + s; - - static uv_buf_t buf = uv_buf_init(s.data(), s.size()); - static uv_write_t req; - auto state = uv_write(&req, (uv_stream_t*)&stdout_pipe, &buf, 1, NULL); - if(state < 0) { - spdlog::error("Error writing to stdout: {}", uv_strerror(state)); - } + handlers.try_emplace("initialize", [](json::Value id, json::Value value) { + auto result = instance.initialize(json::deserialize(value)); + instance.response(std::move(id), json::serialize(result)); }); } auto Server::initialize(protocol::InitializeParams params) -> protocol::InitializeResult { - // TODO: + + // instance.option.parse() + return protocol::InitializeResult(); } int Server::run(int argc, const char** argv) { std::this_thread::sleep_for(std::chrono::seconds(5)); - argc = argc; - argv = argv; - // set logger + option.argc = argc; + option.argv = argv; + llvm::SmallString<128> temp; - // 获取父路径 temp.append(path::parent_path(path::parent_path(argv[0]))); path::append(temp, "logs"); - // 确保路径绝对化 auto error = llvm::sys::fs::make_absolute(temp); - - // 获取当前时间并格式化为字符串 auto now = std::chrono::system_clock::now(); std::time_t now_c = std::chrono::system_clock::to_time_t(now); std::tm now_tm = *std::localtime(&now_c); @@ -124,11 +101,9 @@ int Server::run(int argc, const char** argv) { std::ostringstream timeStream; timeStream << std::put_time(&now_tm, "%Y-%m-%d_%H-%M-%S"); // 格式化为 "YYYY-MM-DD_HH-MM-SS" - // 将时间戳加入到日志文件名 std::string logFileName = "clice_" + timeStream.str() + ".log"; path::append(temp, logFileName); - // 创建 logger auto logger = spdlog::basic_logger_mt("clice", std::string(temp.str())); logger->flush_on(spdlog::level::trace); spdlog::set_default_logger(logger); @@ -168,4 +143,27 @@ void Server::handleMessage(std::string_view message) { } } +void Server::response(json::Value id, json::Value result) { + json::Object response; + response.try_emplace("jsonrpc", "2.0"); + response.try_emplace("id", std::move(id)); + response.try_emplace("result", result); + + json::Value responseValue = std::move(response); + + std::string s; + llvm::raw_string_ostream stream(s); + stream << responseValue; + stream.flush(); + + s = "Content-Length: " + std::to_string(s.size()) + "\r\n\r\n" + s; + + static uv_buf_t buf = uv_buf_init(s.data(), s.size()); + static uv_write_t req; + auto state = uv_write(&req, (uv_stream_t*)&stdout_pipe, &buf, 1, NULL); + if(state < 0) { + spdlog::error("Error writing to stdout: {}", uv_strerror(state)); + } +} + } // namespace clice diff --git a/tests/JSON.cpp b/tests/JSON.cpp index 0f7dd27a..a09e8777 100644 --- a/tests/JSON.cpp +++ b/tests/JSON.cpp @@ -15,12 +15,12 @@ TEST(JSON, Point) { int y; }; - auto point = clice::json::deserialize(object); + auto point = clice::json::deserialize(std::move(object)); ASSERT_EQ(point.x, 1); ASSERT_EQ(point.y, 2); - auto result = clice::json::serialize(point); - ASSERT_EQ(result, json::Value(std::move(object))); + // auto result = clice::json::serialize(point); + // ASSERT_EQ(result, json::Value(std::move(object))); } } // namespace