Index: clang-tools-extra/clangd/ClangdLSPServer.cpp =================================================================== --- clang-tools-extra/clangd/ClangdLSPServer.cpp +++ clang-tools-extra/clangd/ClangdLSPServer.cpp @@ -17,18 +17,29 @@ namespace { +TextEdit replacementToEdit(StringRef Code, const tooling::Replacement &R) { + Range ReplacementRange = { + offsetToPosition(Code, R.getOffset()), + offsetToPosition(Code, R.getOffset() + R.getLength())}; + return {ReplacementRange, R.getReplacementText()}; +} + std::vector replacementsToEdits(StringRef Code, const std::vector &Replacements) { // Turn the replacements into the format specified by the Language Server // Protocol. Fuse them into one big JSON array. std::vector Edits; - for (auto &R : Replacements) { - Range ReplacementRange = { - offsetToPosition(Code, R.getOffset()), - offsetToPosition(Code, R.getOffset() + R.getLength())}; - Edits.push_back({ReplacementRange, R.getReplacementText()}); - } + for (const auto &R : Replacements) + Edits.push_back(replacementToEdit(Code, R)); + return Edits; +} + +std::vector replacementsToEdits(StringRef Code, + const tooling::Replacements &Repls) { + std::vector Edits; + for (const auto &R : Repls) + Edits.push_back(replacementToEdit(Code, R)); return Edits; } @@ -152,23 +163,36 @@ Ctx C, DocumentOnTypeFormattingParams &Params) { auto File = Params.textDocument.uri.file; std::string Code = Server.getDocument(File); - C.reply(json::ary( - replacementsToEdits(Code, Server.formatOnType(File, Params.position)))); + auto ReplacementsOrError = Server.formatOnType(Code, File, Params.position); + if (ReplacementsOrError) + C.reply(json::ary(replacementsToEdits(Code, ReplacementsOrError.get()))); + else + C.replyError(ErrorCode::UnknownErrorCode, + llvm::toString(ReplacementsOrError.takeError())); } void ClangdLSPServer::onDocumentRangeFormatting( Ctx C, DocumentRangeFormattingParams &Params) { auto File = Params.textDocument.uri.file; std::string Code = Server.getDocument(File); - C.reply(json::ary( - replacementsToEdits(Code, Server.formatRange(File, Params.range)))); + auto ReplacementsOrError = Server.formatRange(Code, File, Params.range); + if (ReplacementsOrError) + C.reply(json::ary(replacementsToEdits(Code, ReplacementsOrError.get()))); + else + C.replyError(ErrorCode::UnknownErrorCode, + llvm::toString(ReplacementsOrError.takeError())); } void ClangdLSPServer::onDocumentFormatting(Ctx C, DocumentFormattingParams &Params) { auto File = Params.textDocument.uri.file; std::string Code = Server.getDocument(File); - C.reply(json::ary(replacementsToEdits(Code, Server.formatFile(File)))); + auto ReplacementsOrError = Server.formatFile(Code, File); + if (ReplacementsOrError) + C.reply(json::ary(replacementsToEdits(Code, ReplacementsOrError.get()))); + else + C.replyError(ErrorCode::UnknownErrorCode, + llvm::toString(ReplacementsOrError.takeError())); } void ClangdLSPServer::onCodeAction(Ctx C, CodeActionParams &Params) { Index: clang-tools-extra/clangd/ClangdServer.h =================================================================== --- clang-tools-extra/clangd/ClangdServer.h +++ clang-tools-extra/clangd/ClangdServer.h @@ -286,12 +286,19 @@ /// given a header file and vice versa. llvm::Optional switchSourceHeader(PathRef Path); - /// Run formatting for \p Rng inside \p File. - std::vector formatRange(PathRef File, Range Rng); - /// Run formatting for the whole \p File. - std::vector formatFile(PathRef File); - /// Run formatting after a character was typed at \p Pos in \p File. - std::vector formatOnType(PathRef File, Position Pos); + /// Run formatting for \p Rng inside \p File with content \p Code. + llvm::Expected formatRange(StringRef Code, + PathRef File, Range Rng); + + /// Run formatting for the whole \p File with content \p Code. + llvm::Expected formatFile(StringRef Code, + PathRef File); + + /// Run formatting after a character was typed at \p Pos in \p File with + /// content \p Code. + llvm::Expected + formatOnType(StringRef Code, PathRef File, Position Pos); + /// Rename all occurrences of the symbol at the \p Pos in \p File to /// \p NewName. Expected> rename(PathRef File, Position Pos, @@ -311,6 +318,13 @@ void onFileEvent(const DidChangeWatchedFilesParams &Params); private: + + /// FIXME: This stats several files to find a .clang-format file. I/O can be + /// slow. Think of a way to cache this. + llvm::Expected + formatCode(llvm::StringRef Code, PathRef File, + ArrayRef Ranges); + std::future scheduleReparseAndDiags(PathRef File, VersionedDraft Contents, std::shared_ptr Resources, Index: clang-tools-extra/clangd/ClangdServer.cpp =================================================================== --- clang-tools-extra/clangd/ClangdServer.cpp +++ clang-tools-extra/clangd/ClangdServer.cpp @@ -38,16 +38,6 @@ std::promise &Promise; }; -std::vector 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); - - return std::vector(Result.begin(), Result.end()); -} - std::string getStandardResourceDir() { static int Dummy; // Just an address in this process. return CompilerInvocation::GetResourcesPath("clangd", (void *)&Dummy); @@ -331,26 +321,23 @@ return make_tagged(std::move(Result), TaggedFS.Tag); } -std::vector ClangdServer::formatRange(PathRef File, - Range Rng) { - std::string Code = getDocument(File); - +llvm::Expected +ClangdServer::formatRange(StringRef Code, PathRef File, Range Rng) { size_t Begin = positionToOffset(Code, Rng.start); size_t Len = positionToOffset(Code, Rng.end) - Begin; return formatCode(Code, File, {tooling::Range(Begin, Len)}); } -std::vector ClangdServer::formatFile(PathRef File) { +llvm::Expected ClangdServer::formatFile(StringRef Code, + 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(StringRef Code, PathRef File, Position Pos) { // Look for the previous opening brace from the character position and // format starting from there. - std::string Code = getDocument(File); size_t CursorPos = positionToOffset(Code, Pos); size_t PreviousLBracePos = StringRef(Code).find_last_of('{', CursorPos); if (PreviousLBracePos == StringRef::npos) @@ -509,6 +496,20 @@ return llvm::None; } +llvm::Expected +ClangdServer::formatCode(llvm::StringRef Code, PathRef File, + ArrayRef Ranges) { + // Call clang-format. + auto TaggedFS = FSProvider.getTaggedFileSystem(File); + auto StyleOrError = + format::getStyle("file", File, "LLVM", Code, TaggedFS.Value.get()); + if (!StyleOrError) { + return StyleOrError.takeError(); + } else { + return format::reformat(StyleOrError.get(), Code, Ranges, File); + } +} + std::future ClangdServer::scheduleReparseAndDiags( PathRef File, VersionedDraft Contents, std::shared_ptr Resources, Tagged> TaggedFS) {