xref: /llvm-project/clang-tools-extra/clangd/Transport.h (revision 48e6ff9ad3eb1971de6d7ba12e31754781aff675)
1dc8f3cf8SSam McCall //===--- Transport.h - sending and receiving LSP messages -------*- C++ -*-===//
2dc8f3cf8SSam McCall //
32946cd70SChandler Carruth // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
42946cd70SChandler Carruth // See https://llvm.org/LICENSE.txt for license information.
52946cd70SChandler Carruth // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6dc8f3cf8SSam McCall //
7dc8f3cf8SSam McCall //===----------------------------------------------------------------------===//
8dc8f3cf8SSam McCall //
9dc8f3cf8SSam McCall // The language server protocol is usually implemented by writing messages as
10dc8f3cf8SSam McCall // JSON-RPC over the stdin/stdout of a subprocess. However other communications
11dc8f3cf8SSam McCall // mechanisms are possible, such as XPC on mac.
12dc8f3cf8SSam McCall //
13dc8f3cf8SSam McCall // The Transport interface allows the mechanism to be replaced, and the JSONRPC
14dc8f3cf8SSam McCall // Transport is the standard implementation.
15dc8f3cf8SSam McCall //
16dc8f3cf8SSam McCall //===----------------------------------------------------------------------===//
17dc8f3cf8SSam McCall 
18*48e6ff9aSHaojian Wu #ifndef LLVM_CLANG_TOOLS_EXTRA_CLANGD_TRANSPORT_H
19*48e6ff9aSHaojian Wu #define LLVM_CLANG_TOOLS_EXTRA_CLANGD_TRANSPORT_H
20dc8f3cf8SSam McCall 
214ad9ec8aSSam McCall #include "Feature.h"
22dc8f3cf8SSam McCall #include "llvm/ADT/StringRef.h"
23dc8f3cf8SSam McCall #include "llvm/Support/JSON.h"
24dc8f3cf8SSam McCall #include "llvm/Support/raw_ostream.h"
25dc8f3cf8SSam McCall 
26dc8f3cf8SSam McCall namespace clang {
27dc8f3cf8SSam McCall namespace clangd {
28dc8f3cf8SSam McCall 
29dc8f3cf8SSam McCall // A transport is responsible for maintaining the connection to a client
30dc8f3cf8SSam McCall // application, and reading/writing structured messages to it.
31dc8f3cf8SSam McCall //
32dc8f3cf8SSam McCall // Transports have limited thread safety requirements:
33dc8f3cf8SSam McCall //  - messages will not be sent concurrently
34dc8f3cf8SSam McCall //  - messages MAY be sent while loop() is reading, or its callback is active
35dc8f3cf8SSam McCall class Transport {
36dc8f3cf8SSam McCall public:
37dc8f3cf8SSam McCall   virtual ~Transport() = default;
38dc8f3cf8SSam McCall 
39dc8f3cf8SSam McCall   // Called by Clangd to send messages to the client.
40dc8f3cf8SSam McCall   virtual void notify(llvm::StringRef Method, llvm::json::Value Params) = 0;
41dc8f3cf8SSam McCall   virtual void call(llvm::StringRef Method, llvm::json::Value Params,
42dc8f3cf8SSam McCall                     llvm::json::Value ID) = 0;
43dc8f3cf8SSam McCall   virtual void reply(llvm::json::Value ID,
44dc8f3cf8SSam McCall                      llvm::Expected<llvm::json::Value> Result) = 0;
45dc8f3cf8SSam McCall 
46dc8f3cf8SSam McCall   // Implemented by Clangd to handle incoming messages. (See loop() below).
47dc8f3cf8SSam McCall   class MessageHandler {
48dc8f3cf8SSam McCall   public:
49dc8f3cf8SSam McCall     virtual ~MessageHandler() = default;
50dc8f3cf8SSam McCall     // Handler returns true to keep processing messages, or false to shut down.
51dc8f3cf8SSam McCall     virtual bool onNotify(llvm::StringRef Method, llvm::json::Value) = 0;
52dc8f3cf8SSam McCall     virtual bool onCall(llvm::StringRef Method, llvm::json::Value Params,
53dc8f3cf8SSam McCall                         llvm::json::Value ID) = 0;
54dc8f3cf8SSam McCall     virtual bool onReply(llvm::json::Value ID,
55dc8f3cf8SSam McCall                          llvm::Expected<llvm::json::Value> Result) = 0;
56dc8f3cf8SSam McCall   };
57dc8f3cf8SSam McCall   // Called by Clangd to receive messages from the client.
58dc8f3cf8SSam McCall   // The transport should in turn invoke the handler to process messages.
593b9715cbSKirill Bobyrev   // If handler returns false, the transport should immediately exit the loop.
60dc8f3cf8SSam McCall   // (This is used to implement the `exit` notification).
61dc8f3cf8SSam McCall   // Otherwise, it returns an error when the transport becomes unusable.
62dc8f3cf8SSam McCall   virtual llvm::Error loop(MessageHandler &) = 0;
63dc8f3cf8SSam McCall };
64dc8f3cf8SSam McCall 
65dc8f3cf8SSam McCall // Controls the way JSON-RPC messages are encoded (both input and output).
66dc8f3cf8SSam McCall enum JSONStreamStyle {
67dc8f3cf8SSam McCall   // Encoding per the LSP specification, with mandatory Content-Length header.
68dc8f3cf8SSam McCall   Standard,
69dc8f3cf8SSam McCall   // Messages are delimited by a '---' line. Comment lines start with #.
70dc8f3cf8SSam McCall   Delimited
71dc8f3cf8SSam McCall };
72dc8f3cf8SSam McCall 
73dc8f3cf8SSam McCall // Returns a Transport that speaks JSON-RPC over a pair of streams.
74dc8f3cf8SSam McCall // The input stream must be opened in binary mode.
75dc8f3cf8SSam McCall // If InMirror is set, data read will be echoed to it.
76dc8f3cf8SSam McCall //
77dc8f3cf8SSam McCall // The use of C-style std::FILE* input deserves some explanation.
78dc8f3cf8SSam McCall // Previously, std::istream was used. When a debugger attached on MacOS, the
79dc8f3cf8SSam McCall // process received EINTR, the stream went bad, and clangd exited.
80dc8f3cf8SSam McCall // A retry-on-EINTR loop around reads solved this problem, but caused clangd to
81dc8f3cf8SSam McCall // sometimes hang rather than exit on other OSes. The interaction between
82dc8f3cf8SSam McCall // istreams and signals isn't well-specified, so it's hard to get this right.
83dc8f3cf8SSam McCall // The C APIs seem to be clearer in this respect.
84dc8f3cf8SSam McCall std::unique_ptr<Transport>
85dc8f3cf8SSam McCall newJSONTransport(std::FILE *In, llvm::raw_ostream &Out,
86dc8f3cf8SSam McCall                  llvm::raw_ostream *InMirror, bool Pretty,
87dc8f3cf8SSam McCall                  JSONStreamStyle = JSONStreamStyle::Standard);
88dc8f3cf8SSam McCall 
899ff3afbeSFangrui Song #if CLANGD_BUILD_XPC
90dca9c7cfSJan Korous // Returns a Transport for macOS based on XPC.
91dca9c7cfSJan Korous // Clangd with this transport is meant to be run as bundled XPC service.
92dca9c7cfSJan Korous std::unique_ptr<Transport> newXPCTransport();
93dca9c7cfSJan Korous #endif
94dca9c7cfSJan Korous 
95dc8f3cf8SSam McCall } // namespace clangd
96dc8f3cf8SSam McCall } // namespace clang
97dc8f3cf8SSam McCall 
98dc8f3cf8SSam McCall #endif
99