[clang-tools-extra] [clangd] Add support for textDocument/rangesFormatting (LSP 3.18) (PR #80180)
Tom Praschan via cfe-commits
cfe-commits at lists.llvm.org
Thu Feb 1 11:04:33 PST 2024
https://github.com/tom-anders updated https://github.com/llvm/llvm-project/pull/80180
>From d7a498dea69a8e1efb9cc143635a1c32246756f0 Mon Sep 17 00:00:00 2001
From: tom-anders <13141438+tom-anders at 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..62df250fcb6bf 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: "rangesSupport": 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);
More information about the cfe-commits
mailing list