Skip to content

[clangd] Add support for textDocument/rangesFormatting #141052

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: main
Choose a base branch
from

Conversation

tom-anders
Copy link
Contributor

@llvmbot
Copy link
Member

llvmbot commented May 22, 2025

@llvm/pr-subscribers-clang-tools-extra

Author: Tom Praschan (tom-anders)

Changes

Uses the protocol changes proposed in microsoft/language-server-protocol#1556 and microsoft/vscode#163190

Related issue: clangd/clangd#1635

Old Phabricator review: https://reviews.llvm.org/D150852

Relevant LSP 3.18 spec: https://microsoft.github.io/language-server-protocol/specifications/lsp/3.18/specification/#documentRangesFormattingParams

Old PR: #80180


Full diff: https://github.com/llvm/llvm-project/pull/141052.diff

10 Files Affected:

  • (modified) clang-tools-extra/clangd/ClangdLSPServer.cpp (+15-3)
  • (modified) clang-tools-extra/clangd/ClangdLSPServer.h (+2)
  • (modified) clang-tools-extra/clangd/ClangdServer.cpp (+16-13)
  • (modified) clang-tools-extra/clangd/ClangdServer.h (+2-2)
  • (modified) clang-tools-extra/clangd/Protocol.cpp (+9)
  • (modified) clang-tools-extra/clangd/Protocol.h (+10)
  • (modified) clang-tools-extra/clangd/test/initialize-params.test (+3-1)
  • (modified) clang-tools-extra/clangd/unittests/ClangdTests.cpp (+1-1)
  • (modified) clang-tools-extra/clangd/unittests/SyncAPI.cpp (+3-2)
  • (modified) clang-tools-extra/clangd/unittests/SyncAPI.h (+1-1)
diff --git a/clang-tools-extra/clangd/ClangdLSPServer.cpp b/clang-tools-extra/clangd/ClangdLSPServer.cpp
index 1e981825c7c15..29321f7cd3fa2 100644
--- a/clang-tools-extra/clangd/ClangdLSPServer.cpp
+++ b/clang-tools-extra/clangd/ClangdLSPServer.cpp
@@ -591,7 +591,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"},
@@ -952,9 +955,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)
@@ -970,7 +981,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)
@@ -1666,6 +1677,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 f43734ec1ede3..6ada3fd9e6e47 100644
--- a/clang-tools-extra/clangd/ClangdLSPServer.h
+++ b/clang-tools-extra/clangd/ClangdLSPServer.h
@@ -110,6 +110,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 b499683621f53..ac1e9aa5f0ff1 100644
--- a/clang-tools-extra/clangd/ClangdServer.cpp
+++ b/clang-tools-extra/clangd/ClangdServer.cpp
@@ -521,29 +521,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, true);
     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 1e612e2ba618e..4a1eae188f7eb 100644
--- a/clang-tools-extra/clangd/ClangdServer.h
+++ b/clang-tools-extra/clangd/ClangdServer.h
@@ -329,8 +329,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 05c8041df7de7..c9e8a175b5d76 100644
--- a/clang-tools-extra/clangd/Protocol.cpp
+++ b/clang-tools-extra/clangd/Protocol.cpp
@@ -672,6 +672,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 c7ef1a13e6e39..8a7809d6677ee 100644
--- a/clang-tools-extra/clangd/Protocol.h
+++ b/clang-tools-extra/clangd/Protocol.h
@@ -858,6 +858,16 @@ struct DocumentRangeFormattingParams {
 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 7c96eb9835b71..d976b7d19fd0e 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 643b8e9f12d75..9ea7c3e02411d 100644
--- a/clang-tools-extra/clangd/unittests/ClangdTests.cpp
+++ b/clang-tools-extra/clangd/unittests/ClangdTests.cpp
@@ -944,7 +944,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);

@llvmbot
Copy link
Member

llvmbot commented May 22, 2025

@llvm/pr-subscribers-clangd

Author: Tom Praschan (tom-anders)

Changes

Uses the protocol changes proposed in microsoft/language-server-protocol#1556 and microsoft/vscode#163190

Related issue: clangd/clangd#1635

Old Phabricator review: https://reviews.llvm.org/D150852

Relevant LSP 3.18 spec: https://microsoft.github.io/language-server-protocol/specifications/lsp/3.18/specification/#documentRangesFormattingParams

Old PR: #80180


Full diff: https://github.com/llvm/llvm-project/pull/141052.diff

10 Files Affected:

  • (modified) clang-tools-extra/clangd/ClangdLSPServer.cpp (+15-3)
  • (modified) clang-tools-extra/clangd/ClangdLSPServer.h (+2)
  • (modified) clang-tools-extra/clangd/ClangdServer.cpp (+16-13)
  • (modified) clang-tools-extra/clangd/ClangdServer.h (+2-2)
  • (modified) clang-tools-extra/clangd/Protocol.cpp (+9)
  • (modified) clang-tools-extra/clangd/Protocol.h (+10)
  • (modified) clang-tools-extra/clangd/test/initialize-params.test (+3-1)
  • (modified) clang-tools-extra/clangd/unittests/ClangdTests.cpp (+1-1)
  • (modified) clang-tools-extra/clangd/unittests/SyncAPI.cpp (+3-2)
  • (modified) clang-tools-extra/clangd/unittests/SyncAPI.h (+1-1)
diff --git a/clang-tools-extra/clangd/ClangdLSPServer.cpp b/clang-tools-extra/clangd/ClangdLSPServer.cpp
index 1e981825c7c15..29321f7cd3fa2 100644
--- a/clang-tools-extra/clangd/ClangdLSPServer.cpp
+++ b/clang-tools-extra/clangd/ClangdLSPServer.cpp
@@ -591,7 +591,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"},
@@ -952,9 +955,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)
@@ -970,7 +981,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)
@@ -1666,6 +1677,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 f43734ec1ede3..6ada3fd9e6e47 100644
--- a/clang-tools-extra/clangd/ClangdLSPServer.h
+++ b/clang-tools-extra/clangd/ClangdLSPServer.h
@@ -110,6 +110,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 b499683621f53..ac1e9aa5f0ff1 100644
--- a/clang-tools-extra/clangd/ClangdServer.cpp
+++ b/clang-tools-extra/clangd/ClangdServer.cpp
@@ -521,29 +521,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, true);
     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 1e612e2ba618e..4a1eae188f7eb 100644
--- a/clang-tools-extra/clangd/ClangdServer.h
+++ b/clang-tools-extra/clangd/ClangdServer.h
@@ -329,8 +329,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 05c8041df7de7..c9e8a175b5d76 100644
--- a/clang-tools-extra/clangd/Protocol.cpp
+++ b/clang-tools-extra/clangd/Protocol.cpp
@@ -672,6 +672,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 c7ef1a13e6e39..8a7809d6677ee 100644
--- a/clang-tools-extra/clangd/Protocol.h
+++ b/clang-tools-extra/clangd/Protocol.h
@@ -858,6 +858,16 @@ struct DocumentRangeFormattingParams {
 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 7c96eb9835b71..d976b7d19fd0e 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 643b8e9f12d75..9ea7c3e02411d 100644
--- a/clang-tools-extra/clangd/unittests/ClangdTests.cpp
+++ b/clang-tools-extra/clangd/unittests/ClangdTests.cpp
@@ -944,7 +944,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);

Copy link

⚠️ We detected that you are using a GitHub private e-mail address to contribute to the repo.
Please turn off Keep my email addresses private setting in your account.
See LLVM Discourse for more information.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants