@@ -24,6 +24,28 @@ llvm::cl::opt<int> ClientProcessID{
2424 " Client process ID, if this PID died, the server should exit." ),
2525 llvm::cl::init (getppid ())};
2626
27+ std::string jsonToString (llvm::json::Value &Message) {
28+ std::string Result;
29+ llvm::raw_string_ostream OS (Result);
30+ OS << Message;
31+ return Result;
32+ }
33+
34+ class ReadEOF : public llvm ::ErrorInfo<ReadEOF> {
35+ public:
36+ static char ID;
37+ ReadEOF () = default ;
38+
39+ // / No need to implement this, we don't need to log this error.
40+ void log (llvm::raw_ostream &OS) const override { __builtin_unreachable (); }
41+
42+ std::error_code convertToErrorCode () const override {
43+ return std::make_error_code (std::errc::io_error);
44+ }
45+ };
46+
47+ char ReadEOF::ID;
48+
2749} // namespace
2850
2951namespace lspserver {
@@ -184,12 +206,13 @@ bool readLine(int fd, const std::atomic<bool> &Close,
184206 }
185207}
186208
187- bool InboundPort::readStandardMessage (std::string &JSONString) {
209+ llvm::Expected<llvm::json::Value>
210+ InboundPort::readStandardMessage (std::string &Buffer) {
188211 unsigned long long ContentLength = 0 ;
189212 llvm::SmallString<128 > Line;
190213 while (true ) {
191214 if (!readLine (In, Close, Line))
192- return false ;
215+ return llvm::make_error<ReadEOF>(); // EOF
193216
194217 llvm::StringRef LineRef = Line;
195218
@@ -205,76 +228,112 @@ bool InboundPort::readStandardMessage(std::string &JSONString) {
205228 // It's another header, ignore it.
206229 }
207230
208- JSONString .resize (ContentLength);
231+ Buffer .resize (ContentLength);
209232 for (size_t Pos = 0 , Read; Pos < ContentLength; Pos += Read) {
210233
211- Read = read (In, JSONString .data () + Pos, ContentLength - Pos);
234+ Read = read (In, Buffer .data () + Pos, ContentLength - Pos);
212235
213236 if (Read == 0 ) {
214237 elog (" Input was aborted. Read only {0} bytes of expected {1}." , Pos,
215238 ContentLength);
216- return false ;
239+ return llvm::make_error<ReadEOF>() ;
217240 }
218241 }
219- return true ;
242+ return llvm::json::parse (Buffer) ;
220243}
221244
222- bool InboundPort::readDelimitedMessage (std::string &JSONString) {
223- JSONString.clear ();
245+ llvm::Expected<llvm::json::Value>
246+ InboundPort::readDelimitedMessage (std::string &Buffer) {
247+ enum class State { Prose, JSONBlock, NixBlock };
248+ State State = State::Prose;
249+ Buffer.clear ();
224250 llvm::SmallString<128 > Line;
225- bool IsInputBlock = false ;
251+ std::string NixDocURI ;
226252 while (readLine (In, Close, Line)) {
227253 auto LineRef = Line.str ().trim ();
228- if (IsInputBlock) {
229- // We are in input blocks, read lines and append JSONString.
254+ if (State == State::Prose) {
255+ if (LineRef.starts_with (" ```json" ))
256+ State = State::JSONBlock;
257+ else if (LineRef.consume_front (" ```nix " )) {
258+ State = State::NixBlock;
259+ NixDocURI = LineRef.str ();
260+ }
261+ } else if (State == State::JSONBlock) {
262+ // We are in a JSON block, read lines and append JSONString.
230263 if (LineRef.starts_with (" #" )) // comment
231264 continue ;
232265
233266 // End of the block
234267 if (LineRef.starts_with (" ```" )) {
235- IsInputBlock = false ;
236- break ;
268+ return llvm::json::parse (Buffer);
237269 }
238270
239- JSONString += Line;
271+ Buffer += Line;
272+ } else if (State == State::NixBlock) {
273+ // We are in a Nix block. (This was implemented to make the .md test
274+ // files more readable, particularly regarding multiline Nix documents,
275+ // so that the newlines don't have to be \n escaped.)
276+
277+ if (LineRef.starts_with (" ```" )) {
278+ return llvm::json::Object{
279+ {" jsonrpc" , " 2.0" },
280+ {" method" , " textDocument/didOpen" },
281+ {
282+ " params" ,
283+ llvm::json::Object{
284+ {
285+ " textDocument" ,
286+ llvm::json::Object{
287+ {" uri" , NixDocURI},
288+ {" languageId" , " nix" },
289+ {" version" , 1 },
290+ {" text" , llvm::StringRef (Buffer).rtrim ().str ()},
291+ },
292+ },
293+ },
294+ }};
295+ }
296+ Buffer += Line;
297+ Buffer += " \n " ;
240298 } else {
241- if (LineRef.starts_with (" ```json" ))
242- IsInputBlock = true ;
299+ assert (false && " unreachable" );
243300 }
244301 }
245- return true ; // Including at EOF
302+ return llvm::make_error<ReadEOF>() ; // EOF
246303}
247304
248- bool InboundPort::readMessage (std::string &JSONString) {
305+ llvm::Expected<llvm::json::Value>
306+ InboundPort::readMessage (std::string &Buffer) {
249307 switch (StreamStyle) {
250308
251309 case JSONStreamStyle::Standard:
252- return readStandardMessage (JSONString );
310+ return readStandardMessage (Buffer );
253311 case JSONStreamStyle::Delimited:
254- return readDelimitedMessage (JSONString);
255- break ;
312+ return readDelimitedMessage (Buffer);
256313 }
257314 assert (false && " Invalid stream style" );
258315 __builtin_unreachable ();
259316}
260317
261318void InboundPort::loop (MessageHandler &Handler) {
262- std::string JSONString;
263- llvm::SmallString<128 > Line;
319+ std::string Buffer;
264320
265321 for (;;) {
266- if (readMessage (JSONString)) {
267- vlog (" <<< {0}" , JSONString);
268- if (auto ExpectedParsedJSON = llvm::json::parse (JSONString)) {
269- if (!dispatch (*ExpectedParsedJSON, Handler))
270- return ;
271- } else {
272- auto Err = ExpectedParsedJSON.takeError ();
273- elog (" The received json cannot be parsed, reason: {0}" , Err);
322+ if (auto Message = readMessage (Buffer)) {
323+ vlog (" <<< {0}" , jsonToString (*Message));
324+ if (!dispatch (*Message, Handler))
274325 return ;
275- }
276326 } else {
277- return ;
327+ // Handle error while reading message.
328+ return [&]() {
329+ auto Err = Message.takeError ();
330+ if (Err.isA <ReadEOF>())
331+ return ; // Stop reading.
332+ else if (Err.isA <llvm::json::ParseError>())
333+ elog (" The received json cannot be parsed, reason: {0}" , Err);
334+ else
335+ elog (" Error reading message: {0}" , llvm::toString (std::move (Err)));
336+ }();
278337 }
279338 }
280339}
0 commit comments