[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/ClangdMain.cpp b/clang-tools-extra/clangd/ClangdMain.cpp
index 44f8665..d67f75b 100644
--- a/clang-tools-extra/clangd/ClangdMain.cpp
+++ b/clang-tools-extra/clangd/ClangdMain.cpp
@@ -7,10 +7,8 @@
 //
 //===----------------------------------------------------------------------===//
 
-#include "JSONRPCDispatcher.h"
 #include "ClangdLSPServer.h"
-#include "Protocol.h"
-#include "ProtocolHandlers.h"
+#include "JSONRPCDispatcher.h"
 #include "llvm/Support/CommandLine.h"
 #include "llvm/Support/FileSystem.h"
 #include "llvm/Support/Program.h"
@@ -29,6 +27,7 @@
 
 int main(int argc, char *argv[]) {
   llvm::cl::ParseCommandLineOptions(argc, argv, "clangd");
+
   llvm::raw_ostream &Outs = llvm::outs();
   llvm::raw_ostream &Logs = llvm::errs();
   JSONOutput Out(Outs, Logs);
@@ -36,89 +35,6 @@
   // Change stdin to binary to not lose \r\n on windows.
   llvm::sys::ChangeStdinToBinary();
 
-  // Set up a document store and intialize all the method handlers for JSONRPC
-  // dispatching.
   ClangdLSPServer LSPServer(Out, RunSynchronously);
-  JSONRPCDispatcher Dispatcher(llvm::make_unique<Handler>(Out));
-  Dispatcher.registerHandler("initialize",
-                             llvm::make_unique<InitializeHandler>(Out));
-  auto ShutdownPtr = llvm::make_unique<ShutdownHandler>(Out);
-  auto *ShutdownHandler = ShutdownPtr.get();
-  Dispatcher.registerHandler("shutdown", std::move(ShutdownPtr));
-  Dispatcher.registerHandler(
-      "textDocument/didOpen",
-      llvm::make_unique<TextDocumentDidOpenHandler>(Out, LSPServer));
-  Dispatcher.registerHandler(
-      "textDocument/didClose",
-      llvm::make_unique<TextDocumentDidCloseHandler>(Out, LSPServer));
-  Dispatcher.registerHandler(
-      "textDocument/didChange",
-      llvm::make_unique<TextDocumentDidChangeHandler>(Out, LSPServer));
-  Dispatcher.registerHandler(
-      "textDocument/rangeFormatting",
-      llvm::make_unique<TextDocumentRangeFormattingHandler>(Out, LSPServer));
-  Dispatcher.registerHandler(
-      "textDocument/onTypeFormatting",
-      llvm::make_unique<TextDocumentOnTypeFormattingHandler>(Out, LSPServer));
-  Dispatcher.registerHandler(
-      "textDocument/formatting",
-      llvm::make_unique<TextDocumentFormattingHandler>(Out, LSPServer));
-  Dispatcher.registerHandler("textDocument/codeAction",
-                             llvm::make_unique<CodeActionHandler>(Out, LSPServer));
-  Dispatcher.registerHandler("textDocument/completion",
-                             llvm::make_unique<CompletionHandler>(Out, LSPServer));
-
-  while (std::cin.good()) {
-    // A Language Server Protocol message starts with a HTTP header, delimited
-    // by \r\n.
-    std::string Line;
-    std::getline(std::cin, Line);
-    if (!std::cin.good() && errno == EINTR) {
-      std::cin.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];
-    std::cin.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');
-    std::cin.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 (ShutdownHandler->isDone())
-        break;
-    }
-  }
+  LSPServer.run(std::cin);
 }