[clangd] Refactor ProtocolHandlers to decouple them from ClangdLSPServer
Summary:
A refactoring to decouple ProtocolHandlers and Language Server input parsing
loop from the ClangdLSPServer.
The input parsing was extracted from `main` to a function(runLanguageServerLoop).
ProtocolHandlers now provide an interface to handle various LSP methods,
this interface is used by ClangdLSPServer.
Methods for code formatting were moved from ProtocolHandlers to ClangdServer.
ClangdLSPServer now provides a cleaner interface that only runs Language Server
input loop.
Reviewers: bkramer, krasimir
Reviewed By: krasimir
Subscribers: cfe-commits, klimek
Tags: #clang-tools-extra
Differential Revision: https://reviews.llvm.org/D33201
llvm-svn: 303173
diff --git a/clang-tools-extra/clangd/JSONRPCDispatcher.cpp b/clang-tools-extra/clangd/JSONRPCDispatcher.cpp
index f3045fb..be6be77 100644
--- a/clang-tools-extra/clangd/JSONRPCDispatcher.cpp
+++ b/clang-tools-extra/clangd/JSONRPCDispatcher.cpp
@@ -129,3 +129,61 @@
return true;
}
+
+void clangd::runLanguageServerLoop(std::istream &In, JSONOutput &Out,
+ JSONRPCDispatcher &Dispatcher,
+ bool &IsDone) {
+ while (In.good()) {
+ // A Language Server Protocol message starts with a HTTP header, delimited
+ // by \r\n.
+ std::string Line;
+ std::getline(In, Line);
+ if (!In.good() && errno == EINTR) {
+ In.clear();
+ continue;
+ }
+
+ // Skip empty lines.
+ llvm::StringRef LineRef(Line);
+ if (LineRef.trim().empty())
+ continue;
+
+ // We allow YAML-style comments. Technically this isn't part of the
+ // LSP specification, but makes writing tests easier.
+ if (LineRef.startswith("#"))
+ continue;
+
+ unsigned long long Len = 0;
+ // FIXME: Content-Type is a specified header, but does nothing.
+ // Content-Length is a mandatory header. It specifies the length of the
+ // following JSON.
+ if (LineRef.consume_front("Content-Length: "))
+ llvm::getAsUnsignedInteger(LineRef.trim(), 0, Len);
+
+ // Check if the next line only contains \r\n. If not this is another header,
+ // which we ignore.
+ char NewlineBuf[2];
+ In.read(NewlineBuf, 2);
+ if (std::memcmp(NewlineBuf, "\r\n", 2) != 0)
+ continue;
+
+ // Now read the JSON. Insert a trailing null byte as required by the YAML
+ // parser.
+ std::vector<char> JSON(Len + 1, '\0');
+ In.read(JSON.data(), Len);
+
+ if (Len > 0) {
+ llvm::StringRef JSONRef(JSON.data(), Len);
+ // Log the message.
+ Out.log("<-- " + JSONRef + "\n");
+
+ // Finally, execute the action for this JSON message.
+ if (!Dispatcher.call(JSONRef))
+ Out.log("JSON dispatch failed!\n");
+
+ // If we're done, exit the loop.
+ if (IsDone)
+ break;
+ }
+ }
+}