Index: clangd/ClangdLSPServer.cpp =================================================================== --- clangd/ClangdLSPServer.cpp +++ clangd/ClangdLSPServer.cpp @@ -9,6 +9,7 @@ #include "ClangdLSPServer.h" #include "JSONRPCDispatcher.h" +#include using namespace clang::clangd; using namespace clang; @@ -91,28 +92,32 @@ void ClangdLSPServer::onDocumentOnTypeFormatting( Ctx C, DocumentOnTypeFormattingParams &Params) { - auto File = Params.textDocument.uri.file; - std::string Code = Server.getDocument(File); - std::string Edits = - replacementsToEdits(Code, Server.formatOnType(File, Params.position)); - C.reply("[" + Edits + "]"); + const auto File = Params.textDocument.uri.file; + auto Edits = Server.formatOnType(File, Params.position); + if (Edits) + C.reply("[" + replacementsToEdits(Server.getDocument(File), *Edits) + "]"); + else + C.replyError(Edits.takeError()); } void ClangdLSPServer::onDocumentRangeFormatting( Ctx C, DocumentRangeFormattingParams &Params) { - auto File = Params.textDocument.uri.file; - std::string Code = Server.getDocument(File); - std::string Edits = - replacementsToEdits(Code, Server.formatRange(File, Params.range)); - C.reply("[" + Edits + "]"); + const auto File = Params.textDocument.uri.file; + auto Edits = Server.formatRange(File, Params.range); + if (Edits) + C.reply("[" + replacementsToEdits(Server.getDocument(File), *Edits) + "]"); + else + C.replyError(Edits.takeError()); } void ClangdLSPServer::onDocumentFormatting(Ctx C, DocumentFormattingParams &Params) { - auto File = Params.textDocument.uri.file; - std::string Code = Server.getDocument(File); - std::string Edits = replacementsToEdits(Code, Server.formatFile(File)); - C.reply("[" + Edits + "]"); + const auto File = Params.textDocument.uri.file; + auto Edits = Server.formatFile(File); + if (Edits) + C.reply("[" + replacementsToEdits(Server.getDocument(File), *Edits) + "]"); + else + C.replyError(Edits.takeError()); } void ClangdLSPServer::onCodeAction(Ctx C, CodeActionParams &Params) { Index: clangd/ClangdServer.h =================================================================== --- clangd/ClangdServer.h +++ clangd/ClangdServer.h @@ -285,11 +285,15 @@ llvm::Optional switchSourceHeader(PathRef Path); /// Run formatting for \p Rng inside \p File. - std::vector formatRange(PathRef File, Range Rng); + llvm::Expected> formatRange(PathRef File, + Range Rng); + /// Run formatting for the whole \p File. - std::vector formatFile(PathRef File); + llvm::Expected> formatFile(PathRef File); + /// Run formatting after a character was typed at \p Pos in \p File. - std::vector formatOnType(PathRef File, Position Pos); + llvm::Expected> formatOnType(PathRef File, + Position Pos); /// Gets current document contents for \p File. \p File must point to a /// currently tracked file. Index: clangd/ClangdServer.cpp =================================================================== --- clangd/ClangdServer.cpp +++ clangd/ClangdServer.cpp @@ -34,13 +34,14 @@ std::promise &Promise; }; -std::vector formatCode(StringRef Code, StringRef Filename, - ArrayRef Ranges) { +llvm::Expected> +formatCode(StringRef Code, StringRef Filename, + ArrayRef Ranges) { // Call clang-format. - // FIXME: Don't ignore style. - format::FormatStyle Style = format::getLLVMStyle(); - auto Result = format::reformat(Style, Code, Ranges, Filename); - + auto StyleOrError = format::getStyle("file", Filename, "LLVM", Code); + if (!StyleOrError) + return StyleOrError.takeError(); + auto Result = format::reformat(StyleOrError.get(), Code, Ranges, Filename); return std::vector(Result.begin(), Result.end()); } @@ -301,8 +302,8 @@ return make_tagged(std::move(Result), TaggedFS.Tag); } -std::vector ClangdServer::formatRange(PathRef File, - Range Rng) { +llvm::Expected> +ClangdServer::formatRange(PathRef File, Range Rng) { std::string Code = getDocument(File); size_t Begin = positionToOffset(Code, Rng.start); @@ -310,14 +311,15 @@ return formatCode(Code, File, {tooling::Range(Begin, Len)}); } -std::vector ClangdServer::formatFile(PathRef File) { +llvm::Expected> +ClangdServer::formatFile(PathRef File) { // Format everything. std::string Code = getDocument(File); return formatCode(Code, File, {tooling::Range(0, Code.size())}); } -std::vector ClangdServer::formatOnType(PathRef File, - Position Pos) { +llvm::Expected> +ClangdServer::formatOnType(PathRef File, Position Pos) { // Look for the previous opening brace from the character position and // format starting from there. std::string Code = getDocument(File); Index: clangd/JSONRPCDispatcher.h =================================================================== --- clangd/JSONRPCDispatcher.h +++ clangd/JSONRPCDispatcher.h @@ -15,6 +15,7 @@ #include "llvm/ADT/SmallString.h" #include "llvm/ADT/StringMap.h" #include "llvm/Support/YAMLParser.h" +#include "llvm/Support/Error.h" #include #include @@ -58,6 +59,8 @@ void reply(const Twine &Result); /// Sends an error response to the client, and logs it. void replyError(int code, const llvm::StringRef &Message); + /// Send all error messages contained in Err to the client, and log them. + void replyError(llvm::Error Err); private: JSONOutput &Out; Index: clangd/JSONRPCDispatcher.cpp =================================================================== --- clangd/JSONRPCDispatcher.cpp +++ clangd/JSONRPCDispatcher.cpp @@ -64,6 +64,11 @@ } } +void RequestContext::replyError(llvm::Error Err) { + const auto Message = llvm::toString(std::move(Err)); + replyError(/*UnknownErrorCode*/ -32001, Message); +} + void JSONRPCDispatcher::registerHandler(StringRef Method, Handler H) { assert(!Handlers.count(Method) && "Handler already registered!"); Handlers[Method] = std::move(H); Index: test/clangd/formatting.test =================================================================== --- test/clangd/formatting.test +++ test/clangd/formatting.test @@ -1,4 +1,4 @@ -# RUN: clangd < %s | FileCheck %s +# RUN: clangd -run-synchronously < %s | FileCheck %s # It is absolutely vital that this file has CRLF line endings. # Content-Length: 125