Tom Praschan 2025-05-26 10:08:18 +02:00 committed by GitHub
parent 3f29acb517
commit 926c201323
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
11 changed files with 119 additions and 25 deletions

View File

@ -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);

View File

@ -110,6 +110,8 @@ private:
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

View File

@ -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);
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);
llvm::Expected<size_t> End = positionToOffset(*Code, Rng.end);
if (!End)
return CB(End.takeError());
RequestedRange = tooling::Range(*Begin, *End - *Begin);
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);

View File

@ -329,8 +329,8 @@ public:
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

View File

@ -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,

View File

@ -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;

View File

@ -135,10 +135,65 @@
# CHECK-NEXT: "jsonrpc": "2.0",
# CHECK-NEXT: "result": []
---
{"jsonrpc":"2.0","method":"textDocument/didChange","params":{"textDocument":{"uri":"test:///foo.c","version":9},"contentChanges":[{"text":"int foo( int x){\n x=x+1;\nreturn x;\n}"}]}}
---
{"jsonrpc":"2.0","id":5,"method":"textDocument/rangesFormatting","params":{"textDocument":{"uri":"test:///foo.c"},"ranges":[{"start":{"line":0,"character":0},"end":{"line":0,"character":15}}, {"start":{"line":2,"character":0},"end":{"line":2,"character":5}}]}}
---
# CHECK: "id": 5,
# CHECK-NEXT: "jsonrpc": "2.0",
# CHECK-NEXT: "result": [
# CHECK-NEXT: {
# CHECK-NEXT: "newText": "",
# CHECK-NEXT: "range": {
# CHECK-NEXT: "end": {
# CHECK-NEXT: "character": 10,
# CHECK-NEXT: "line": 0
# CHECK-NEXT: },
# CHECK-NEXT: "start": {
# CHECK-NEXT: "character": 8,
# CHECK-NEXT: "line": 0
# CHECK-NEXT: }
# CHECK-NEXT: }
# CHECK-NEXT: },
# CHECK-NEXT: {
# CHECK-NEXT: "newText": " ",
# CHECK-NEXT: "range": {
# CHECK-NEXT: "end": {
# CHECK-NEXT: "character": 16,
# CHECK-NEXT: "line": 0
# CHECK-NEXT: },
# CHECK-NEXT: "start": {
# CHECK-NEXT: "character": 16,
# CHECK-NEXT: "line": 0
# CHECK-NEXT: }
# CHECK-NEXT: }
# CHECK-NEXT: },
# CHECK-NEXT: {
# CHECK-NEXT: "newText": "\n ",
# CHECK-NEXT: "range": {
# CHECK-NEXT: "end": {
# CHECK-NEXT: "character": 0,
# CHECK-NEXT: "line": 2
# CHECK-NEXT: },
# CHECK-NEXT: "start": {
# CHECK-NEXT: "character": 8,
# CHECK-NEXT: "line": 1
# CHECK-NEXT: }
# CHECK-NEXT: }
# CHECK-NEXT: }
# CHECK-NEXT: ]
---
{"jsonrpc":"2.0","method":"textDocument/didChange","params":{"textDocument":{"uri":"test:///foo.c","version":9},"contentChanges":[{"text":"int foo(int x) {\n x=x+1;\n return x;\n}"}]}}
---
{"jsonrpc":"2.0","id":6,"method":"textDocument/rangesFormatting","params":{"textDocument":{"uri":"test:///foo.c"},"ranges":[{"start":{"line":0,"character":0},"end":{"line":0,"character":15}}, {"start":{"line":2,"character":0},"end":{"line":2,"character":5}}]}}
# CHECK: "id": 6,
# CHECK-NEXT: "jsonrpc": "2.0",
# CHECK-NEXT: "result": []
---
{"jsonrpc":"2.0","method":"textDocument/didChange","params":{"textDocument":{"uri":"test:///foo.c","version":5},"contentChanges":[{"text":"int x=\n"}]}}
---
{"jsonrpc":"2.0","id":5,"method":"textDocument/onTypeFormatting","params":{"textDocument":{"uri":"test:///foo.c"},"position":{"line":1,"character":0},"ch":"\n"}}
# CHECK: "id": 5,
{"jsonrpc":"2.0","id":7,"method":"textDocument/onTypeFormatting","params":{"textDocument":{"uri":"test:///foo.c"},"position":{"line":1,"character":0},"ch":"\n"}}
# CHECK: "id": 7,
# CHECK-NEXT: "jsonrpc": "2.0",
# CHECK-NEXT: "result": [
# CHECK-NEXT: {

View File

@ -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": [

View File

@ -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));

View File

@ -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);
}

View File

@ -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);