Add a prototype for clangd

clangd is a language server protocol implementation based on clang. It's
supposed to provide editor integration while not suffering from the
confined ABI of libclang.

This implementation is limited to the bare minimum functionality of
doing (whole-document) formatting and rangeFormatting. The JSON parsing
is based on LLVM's YAMLParser but yet most of the code of clangd is
currently dealing with JSON serialization and deserialization.

This was only tested with VS Code so far, mileage with other LSP clients
may vary.

Differential Revision: https://reviews.llvm.org/D29451

llvm-svn: 294291
diff --git a/clang-tools-extra/clangd/ClangDMain.cpp b/clang-tools-extra/clangd/ClangDMain.cpp
new file mode 100644
index 0000000..e851ea7
--- /dev/null
+++ b/clang-tools-extra/clangd/ClangDMain.cpp
@@ -0,0 +1,86 @@
+//===--- ClangDMain.cpp - clangd server loop ------------------------------===//
+//
+//                     The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+
+#include "DocumentStore.h"
+#include "JSONRPCDispatcher.h"
+#include "ProtocolHandlers.h"
+#include "llvm/Support/FileSystem.h"
+#include <iostream>
+#include <string>
+using namespace clang::clangd;
+
+int main(int argc, char *argv[]) {
+  llvm::raw_ostream &Outs = llvm::outs();
+  llvm::raw_ostream &Logs = llvm::errs();
+
+  // Set up a document store and intialize all the method handlers for JSONRPC
+  // dispatching.
+  DocumentStore Store;
+  JSONRPCDispatcher Dispatcher(llvm::make_unique<Handler>(Outs, Logs));
+  Dispatcher.registerHandler("initialize",
+                             llvm::make_unique<InitializeHandler>(Outs, Logs));
+  Dispatcher.registerHandler("shutdown",
+                             llvm::make_unique<ShutdownHandler>(Outs, Logs));
+  Dispatcher.registerHandler(
+      "textDocument/didOpen",
+      llvm::make_unique<TextDocumentDidOpenHandler>(Outs, Logs, Store));
+  // FIXME: Implement textDocument/didClose.
+  Dispatcher.registerHandler(
+      "textDocument/didChange",
+      llvm::make_unique<TextDocumentDidChangeHandler>(Outs, Logs, Store));
+  Dispatcher.registerHandler(
+      "textDocument/rangeFormatting",
+      llvm::make_unique<TextDocumentRangeFormattingHandler>(Outs, Logs, Store));
+  Dispatcher.registerHandler(
+      "textDocument/formatting",
+      llvm::make_unique<TextDocumentFormattingHandler>(Outs, Logs, Store));
+
+  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);
+
+    // Skip empty lines.
+    llvm::StringRef LineRef(Line);
+    if (LineRef.trim().empty())
+      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);
+    std::cin.read(JSON.data(), Len);
+
+    if (Len > 0) {
+      // Log the message.
+      Logs << "<-- ";
+      Logs.write(JSON.data(), JSON.size());
+      Logs << '\n';
+      Logs.flush();
+
+      // Finally, execute the action for this JSON message.
+      if (!Dispatcher.call(llvm::StringRef(JSON.data(), JSON.size() - 1)))
+        Logs << "JSON dispatch failed!\n";
+    }
+  }
+}