blob: 349ac904ab637166f8d54fb87311206c89549789 [file] [log] [blame]
Benjamin Kramerbb1cdb62017-02-07 10:28:20 +00001//===--- JSONRPCDispatcher.h - Main JSON parser entry point -----*- C++ -*-===//
2//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9
10#ifndef LLVM_CLANG_TOOLS_EXTRA_CLANGD_JSONRPCDISPATCHER_H
11#define LLVM_CLANG_TOOLS_EXTRA_CLANGD_JSONRPCDISPATCHER_H
12
13#include "clang/Basic/LLVM.h"
14#include "llvm/ADT/StringMap.h"
15#include "llvm/Support/YAMLParser.h"
Ilya Biryukov687b92a2017-05-16 15:23:55 +000016#include <iosfwd>
Benjamin Kramerd0b2ccd2017-02-10 14:08:40 +000017#include <mutex>
Benjamin Kramerbb1cdb62017-02-07 10:28:20 +000018
19namespace clang {
20namespace clangd {
21
Benjamin Kramerd0b2ccd2017-02-10 14:08:40 +000022/// Encapsulates output and logs streams and provides thread-safe access to
23/// them.
24class JSONOutput {
25public:
26 JSONOutput(llvm::raw_ostream &Outs, llvm::raw_ostream &Logs)
27 : Outs(Outs), Logs(Logs) {}
28
29 /// Emit a JSONRPC message.
30 void writeMessage(const Twine &Message);
31
Benjamin Kramere14bd422017-02-15 16:44:11 +000032 /// Write to the logging stream.
33 void log(const Twine &Message);
Benjamin Kramerd0b2ccd2017-02-10 14:08:40 +000034
Benjamin Kramerd0b2ccd2017-02-10 14:08:40 +000035private:
36 llvm::raw_ostream &Outs;
37 llvm::raw_ostream &Logs;
38
Benjamin Kramerd0b2ccd2017-02-10 14:08:40 +000039 std::mutex StreamMutex;
40};
41
Benjamin Kramerbb1cdb62017-02-07 10:28:20 +000042/// Callback for messages sent to the server, called by the JSONRPCDispatcher.
43class Handler {
44public:
Benjamin Kramerd0b2ccd2017-02-10 14:08:40 +000045 Handler(JSONOutput &Output) : Output(Output) {}
Benjamin Kramerbb1cdb62017-02-07 10:28:20 +000046 virtual ~Handler() = default;
47
48 /// Called when the server receives a method call. This is supposed to return
49 /// a result on Outs. The default implementation returns an "unknown method"
50 /// error to the client and logs a warning.
51 virtual void handleMethod(llvm::yaml::MappingNode *Params, StringRef ID);
52 /// Called when the server receives a notification. No result should be
53 /// written to Outs. The default implemetation logs a warning.
54 virtual void handleNotification(llvm::yaml::MappingNode *Params);
55
56protected:
Benjamin Kramerd0b2ccd2017-02-10 14:08:40 +000057 JSONOutput &Output;
Benjamin Kramerbb1cdb62017-02-07 10:28:20 +000058
Benjamin Kramerd0b2ccd2017-02-10 14:08:40 +000059 /// Helper to write a JSONRPC result to Output.
60 void writeMessage(const Twine &Message) { Output.writeMessage(Message); }
Benjamin Kramerbb1cdb62017-02-07 10:28:20 +000061};
62
63/// Main JSONRPC entry point. This parses the JSONRPC "header" and calls the
64/// registered Handler for the method received.
65class JSONRPCDispatcher {
66public:
67 /// Create a new JSONRPCDispatcher. UnknownHandler is called when an unknown
68 /// method is received.
69 JSONRPCDispatcher(std::unique_ptr<Handler> UnknownHandler)
70 : UnknownHandler(std::move(UnknownHandler)) {}
71
72 /// Registers a Handler for the specified Method.
73 void registerHandler(StringRef Method, std::unique_ptr<Handler> H);
74
75 /// Parses a JSONRPC message and calls the Handler for it.
76 bool call(StringRef Content) const;
77
78private:
79 llvm::StringMap<std::unique_ptr<Handler>> Handlers;
80 std::unique_ptr<Handler> UnknownHandler;
81};
82
Ilya Biryukovafb55542017-05-16 14:40:30 +000083/// Parses input queries from LSP client (coming from \p In) and runs call
84/// method of \p Dispatcher for each query.
85/// After handling each query checks if \p IsDone is set true and exits the loop
86/// if it is.
87/// Input stream(\p In) must be opened in binary mode to avoid preliminary
88/// replacements of \r\n with \n.
89void runLanguageServerLoop(std::istream &In, JSONOutput &Out,
90 JSONRPCDispatcher &Dispatcher, bool &IsDone);
91
Benjamin Kramerbb1cdb62017-02-07 10:28:20 +000092} // namespace clangd
93} // namespace clang
94
95#endif