https://github.com/tom-anders updated https://github.com/llvm/llvm-project/pull/80180
>From 0377dc355affd982033469a3a6be97c434e88286 Mon Sep 17 00:00:00 2001 From: tom-anders <13141438+tom-and...@users.noreply.github.com> Date: Thu, 18 May 2023 12:05:01 +0200 Subject: [PATCH] [clangd] Add support for textDocument/rangesFormatting As part of the upcoming 3.18 spec: https://microsoft.github.io/language-server-protocol/specifications/lsp/3.18/specification/#documentRangesFormattingParams Issue: https://github.com/clangd/clangd/issues/1635 Differential Revision: https://reviews.llvm.org/D150852 --- clang-tools-extra/clangd/ClangdLSPServer.cpp | 18 ++++++++++-- clang-tools-extra/clangd/ClangdLSPServer.h | 2 ++ clang-tools-extra/clangd/ClangdServer.cpp | 29 ++++++++++--------- clang-tools-extra/clangd/ClangdServer.h | 4 +-- clang-tools-extra/clangd/Protocol.cpp | 9 ++++++ clang-tools-extra/clangd/Protocol.h | 13 +++++++++ .../clangd/test/initialize-params.test | 4 ++- .../clangd/unittests/ClangdTests.cpp | 2 +- .../clangd/unittests/SyncAPI.cpp | 5 ++-- clang-tools-extra/clangd/unittests/SyncAPI.h | 2 +- 10 files changed, 65 insertions(+), 23 deletions(-) diff --git a/clang-tools-extra/clangd/ClangdLSPServer.cpp b/clang-tools-extra/clangd/ClangdLSPServer.cpp index a87da252b7a7e..4074a5090b123 100644 --- a/clang-tools-extra/clangd/ClangdLSPServer.cpp +++ b/clang-tools-extra/clangd/ClangdLSPServer.cpp @@ -566,7 +566,10 @@ void ClangdLSPServer::onInitialize(const InitializeParams &Params, {"save", true}, }}, {"documentFormattingProvider", true}, - {"documentRangeFormattingProvider", true}, + {"documentRangeFormattingProvider", + llvm::json::Object{ + {"rangesSupport", true}, + }}, {"documentOnTypeFormattingProvider", llvm::json::Object{ {"firstTriggerCharacter", "\n"}, @@ -914,9 +917,17 @@ void ClangdLSPServer::onDocumentOnTypeFormatting( void ClangdLSPServer::onDocumentRangeFormatting( const DocumentRangeFormattingParams &Params, Callback<std::vector<TextEdit>> Reply) { + onDocumentRangesFormatting( + DocumentRangesFormattingParams{Params.textDocument, {Params.range}}, + std::move(Reply)); +} + +void ClangdLSPServer::onDocumentRangesFormatting( + const DocumentRangesFormattingParams &Params, + Callback<std::vector<TextEdit>> Reply) { auto File = Params.textDocument.uri.file(); auto Code = Server->getDraft(File); - Server->formatFile(File, Params.range, + Server->formatFile(File, Params.ranges, [Code = std::move(Code), Reply = std::move(Reply)]( llvm::Expected<tooling::Replacements> Result) mutable { if (Result) @@ -932,7 +943,7 @@ void ClangdLSPServer::onDocumentFormatting( auto File = Params.textDocument.uri.file(); auto Code = Server->getDraft(File); Server->formatFile(File, - /*Rng=*/std::nullopt, + /*Rngs=*/{}, [Code = std::move(Code), Reply = std::move(Reply)]( llvm::Expected<tooling::Replacements> Result) mutable { if (Result) @@ -1621,6 +1632,7 @@ void ClangdLSPServer::bindMethods(LSPBinder &Bind, Bind.method("shutdown", this, &ClangdLSPServer::onShutdown); Bind.method("sync", this, &ClangdLSPServer::onSync); Bind.method("textDocument/rangeFormatting", this, &ClangdLSPServer::onDocumentRangeFormatting); + Bind.method("textDocument/rangesFormatting", this, &ClangdLSPServer::onDocumentRangesFormatting); Bind.method("textDocument/onTypeFormatting", this, &ClangdLSPServer::onDocumentOnTypeFormatting); Bind.method("textDocument/formatting", this, &ClangdLSPServer::onDocumentFormatting); Bind.method("textDocument/codeAction", this, &ClangdLSPServer::onCodeAction); diff --git a/clang-tools-extra/clangd/ClangdLSPServer.h b/clang-tools-extra/clangd/ClangdLSPServer.h index 79579c22b788a..8d010c3bcacca 100644 --- a/clang-tools-extra/clangd/ClangdLSPServer.h +++ b/clang-tools-extra/clangd/ClangdLSPServer.h @@ -104,6 +104,8 @@ class ClangdLSPServer : private ClangdServer::Callbacks, Callback<std::vector<TextEdit>>); void onDocumentRangeFormatting(const DocumentRangeFormattingParams &, Callback<std::vector<TextEdit>>); + void onDocumentRangesFormatting(const DocumentRangesFormattingParams &, + Callback<std::vector<TextEdit>>); void onDocumentFormatting(const DocumentFormattingParams &, Callback<std::vector<TextEdit>>); // The results are serialized 'vector<DocumentSymbol>' if diff --git a/clang-tools-extra/clangd/ClangdServer.cpp b/clang-tools-extra/clangd/ClangdServer.cpp index 6fb2641e8793d..4c18f049c566e 100644 --- a/clang-tools-extra/clangd/ClangdServer.cpp +++ b/clang-tools-extra/clangd/ClangdServer.cpp @@ -500,29 +500,32 @@ void ClangdServer::signatureHelp(PathRef File, Position Pos, std::move(Action)); } -void ClangdServer::formatFile(PathRef File, std::optional<Range> Rng, +void ClangdServer::formatFile(PathRef File, const std::vector<Range> &Rngs, Callback<tooling::Replacements> CB) { auto Code = getDraft(File); if (!Code) return CB(llvm::make_error<LSPError>("trying to format non-added document", ErrorCode::InvalidParams)); - tooling::Range RequestedRange; - if (Rng) { - llvm::Expected<size_t> Begin = positionToOffset(*Code, Rng->start); - if (!Begin) - return CB(Begin.takeError()); - llvm::Expected<size_t> End = positionToOffset(*Code, Rng->end); - if (!End) - return CB(End.takeError()); - RequestedRange = tooling::Range(*Begin, *End - *Begin); + std::vector<tooling::Range> RequestedRanges; + if (!Rngs.empty()) { + RequestedRanges.reserve(Rngs.size()); + for (const auto &Rng : Rngs) { + llvm::Expected<size_t> Begin = positionToOffset(*Code, Rng.start); + if (!Begin) + return CB(Begin.takeError()); + llvm::Expected<size_t> End = positionToOffset(*Code, Rng.end); + if (!End) + return CB(End.takeError()); + RequestedRanges.emplace_back(*Begin, *End - *Begin); + } } else { - RequestedRange = tooling::Range(0, Code->size()); + RequestedRanges = {tooling::Range(0, Code->size())}; } // Call clang-format. auto Action = [File = File.str(), Code = std::move(*Code), - Ranges = std::vector<tooling::Range>{RequestedRange}, - CB = std::move(CB), this]() mutable { + Ranges = std::move(RequestedRanges), CB = std::move(CB), + this]() mutable { format::FormatStyle Style = getFormatStyleForFile(File, Code, TFS); tooling::Replacements IncludeReplaces = format::sortIncludes(Style, Code, Ranges, File); diff --git a/clang-tools-extra/clangd/ClangdServer.h b/clang-tools-extra/clangd/ClangdServer.h index a416602251428..c37857c55f931 100644 --- a/clang-tools-extra/clangd/ClangdServer.h +++ b/clang-tools-extra/clangd/ClangdServer.h @@ -316,8 +316,8 @@ class ClangdServer { bool AddContainer, Callback<ReferencesResult> CB); /// Run formatting for the \p File with content \p Code. - /// If \p Rng is non-null, formats only that region. - void formatFile(PathRef File, std::optional<Range> Rng, + /// If \p Rng is non-empty, formats only those regions. + void formatFile(PathRef File, const std::vector<Range> &Rngs, Callback<tooling::Replacements> CB); /// Run formatting after \p TriggerText was typed at \p Pos in \p File with diff --git a/clang-tools-extra/clangd/Protocol.cpp b/clang-tools-extra/clangd/Protocol.cpp index a6370649f5ad1..69bf1e5e54975 100644 --- a/clang-tools-extra/clangd/Protocol.cpp +++ b/clang-tools-extra/clangd/Protocol.cpp @@ -633,6 +633,15 @@ bool fromJSON(const llvm::json::Value &Params, DocumentRangeFormattingParams &R, llvm::json::Path P) { llvm::json::ObjectMapper O(Params, P); return O && O.map("textDocument", R.textDocument) && O.map("range", R.range); + ; +} + +bool fromJSON(const llvm::json::Value &Params, + DocumentRangesFormattingParams &R, llvm::json::Path P) { + llvm::json::ObjectMapper O(Params, P); + return O && O.map("textDocument", R.textDocument) && + O.map("ranges", R.ranges); + ; } bool fromJSON(const llvm::json::Value &Params, diff --git a/clang-tools-extra/clangd/Protocol.h b/clang-tools-extra/clangd/Protocol.h index e88c804692568..f04141a92d774 100644 --- a/clang-tools-extra/clangd/Protocol.h +++ b/clang-tools-extra/clangd/Protocol.h @@ -851,10 +851,23 @@ struct DocumentRangeFormattingParams { /// The range to format Range range; + + /// The list of ranges to format + std::optional<std::vector<Range>> ranges; }; bool fromJSON(const llvm::json::Value &, DocumentRangeFormattingParams &, llvm::json::Path); +struct DocumentRangesFormattingParams { + /// The document to format. + TextDocumentIdentifier textDocument; + + /// The list of ranges to format + std::vector<Range> ranges; +}; +bool fromJSON(const llvm::json::Value &, DocumentRangesFormattingParams &, + llvm::json::Path); + struct DocumentOnTypeFormattingParams { /// The document to format. TextDocumentIdentifier textDocument; diff --git a/clang-tools-extra/clangd/test/initialize-params.test b/clang-tools-extra/clangd/test/initialize-params.test index a1fdae9870ab6..379f5f92018df 100644 --- a/clang-tools-extra/clangd/test/initialize-params.test +++ b/clang-tools-extra/clangd/test/initialize-params.test @@ -35,7 +35,9 @@ # CHECK-NEXT: "firstTriggerCharacter": "\n", # CHECK-NEXT: "moreTriggerCharacter": [] # CHECK-NEXT: }, -# CHECK-NEXT: "documentRangeFormattingProvider": true, +# CHECK-NEXT: "documentRangeFormattingProvider": { +# CHECK-NEXT: "multiRange": true +# CHECK-NEXT: }, # CHECK-NEXT: "documentSymbolProvider": true, # CHECK-NEXT: "executeCommandProvider": { # CHECK-NEXT: "commands": [ diff --git a/clang-tools-extra/clangd/unittests/ClangdTests.cpp b/clang-tools-extra/clangd/unittests/ClangdTests.cpp index 864337b98f446..4c4b34e742eb8 100644 --- a/clang-tools-extra/clangd/unittests/ClangdTests.cpp +++ b/clang-tools-extra/clangd/unittests/ClangdTests.cpp @@ -943,7 +943,7 @@ void f() {} FS.Files[Path] = Code; runAddDocument(Server, Path, Code); - auto Replaces = runFormatFile(Server, Path, /*Rng=*/std::nullopt); + auto Replaces = runFormatFile(Server, Path, /*Rngs=*/{}); EXPECT_TRUE(static_cast<bool>(Replaces)); auto Changed = tooling::applyAllReplacements(Code, *Replaces); EXPECT_TRUE(static_cast<bool>(Changed)); diff --git a/clang-tools-extra/clangd/unittests/SyncAPI.cpp b/clang-tools-extra/clangd/unittests/SyncAPI.cpp index d48622eba5378..7e8c8e22acf95 100644 --- a/clang-tools-extra/clangd/unittests/SyncAPI.cpp +++ b/clang-tools-extra/clangd/unittests/SyncAPI.cpp @@ -116,9 +116,10 @@ runPrepareRename(ClangdServer &Server, PathRef File, Position Pos, } llvm::Expected<tooling::Replacements> -runFormatFile(ClangdServer &Server, PathRef File, std::optional<Range> Rng) { +runFormatFile(ClangdServer &Server, PathRef File, + const std::vector<Range> &Rngs) { std::optional<llvm::Expected<tooling::Replacements>> Result; - Server.formatFile(File, Rng, capture(Result)); + Server.formatFile(File, Rngs, capture(Result)); return std::move(*Result); } diff --git a/clang-tools-extra/clangd/unittests/SyncAPI.h b/clang-tools-extra/clangd/unittests/SyncAPI.h index cf3de4f742e84..35ebd2574dda3 100644 --- a/clang-tools-extra/clangd/unittests/SyncAPI.h +++ b/clang-tools-extra/clangd/unittests/SyncAPI.h @@ -53,7 +53,7 @@ runPrepareRename(ClangdServer &Server, PathRef File, Position Pos, const clangd::RenameOptions &RenameOpts); llvm::Expected<tooling::Replacements> -runFormatFile(ClangdServer &Server, PathRef File, std::optional<Range>); +runFormatFile(ClangdServer &Server, PathRef File, const std::vector<Range> &); SymbolSlab runFuzzyFind(const SymbolIndex &Index, StringRef Query); SymbolSlab runFuzzyFind(const SymbolIndex &Index, const FuzzyFindRequest &Req); _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits