diff --git a/clang-tools-extra/clangd/ClangdLSPServer.cpp b/clang-tools-extra/clangd/ClangdLSPServer.cpp --- a/clang-tools-extra/clangd/ClangdLSPServer.cpp +++ b/clang-tools-extra/clangd/ClangdLSPServer.cpp @@ -879,7 +879,8 @@ "onDocumentOnTypeFormatting called for non-added file", ErrorCode::InvalidParams)); - Reply(Server->formatOnType(Code->Contents, File, Params.position, Params.ch)); + Server->formatOnType(File, Code->Contents, Params.position, Params.ch, + std::move(Reply)); } void ClangdLSPServer::onDocumentRangeFormatting( @@ -892,12 +893,15 @@ "onDocumentRangeFormatting called for non-added file", ErrorCode::InvalidParams)); - auto ReplacementsOrError = - Server->formatRange(Code->Contents, File, Params.range); - if (ReplacementsOrError) - Reply(replacementsToEdits(Code->Contents, ReplacementsOrError.get())); - else - Reply(ReplacementsOrError.takeError()); + Server->formatRange( + File, Code->Contents, Params.range, + [Code = Code->Contents, Reply = std::move(Reply)]( + llvm::Expected Result) mutable { + if (Result) + Reply(replacementsToEdits(Code, Result.get())); + else + Reply(Result.takeError()); + }); } void ClangdLSPServer::onDocumentFormatting( @@ -910,11 +914,14 @@ "onDocumentFormatting called for non-added file", ErrorCode::InvalidParams)); - auto ReplacementsOrError = Server->formatFile(Code->Contents, File); - if (ReplacementsOrError) - Reply(replacementsToEdits(Code->Contents, ReplacementsOrError.get())); - else - Reply(ReplacementsOrError.takeError()); + Server->formatFile(File, Code->Contents, + [Code = Code->Contents, Reply = std::move(Reply)]( + llvm::Expected Result) mutable { + if (Result) + Reply(replacementsToEdits(Code, Result.get())); + else + Reply(Result.takeError()); + }); } /// The functions constructs a flattened view of the DocumentSymbol hierarchy. diff --git a/clang-tools-extra/clangd/ClangdServer.h b/clang-tools-extra/clangd/ClangdServer.h --- a/clang-tools-extra/clangd/ClangdServer.h +++ b/clang-tools-extra/clangd/ClangdServer.h @@ -247,18 +247,17 @@ Callback CB); /// Run formatting for \p Rng inside \p File with content \p Code. - llvm::Expected formatRange(StringRef Code, - PathRef File, Range Rng); + void formatRange(PathRef File, StringRef Code, Range Rng, + Callback CB); /// Run formatting for the whole \p File with content \p Code. - llvm::Expected formatFile(StringRef Code, - PathRef File); + void formatFile(PathRef File, StringRef Code, + Callback CB); /// Run formatting after \p TriggerText was typed at \p Pos in \p File with /// content \p Code. - llvm::Expected> formatOnType(StringRef Code, - PathRef File, Position Pos, - StringRef TriggerText); + void formatOnType(PathRef File, StringRef Code, Position Pos, + StringRef TriggerText, Callback> CB); /// Test the validity of a rename operation. void prepareRename(PathRef File, Position Pos, @@ -323,11 +322,9 @@ blockUntilIdleForTest(llvm::Optional TimeoutSeconds = 10); 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); + void formatCode(PathRef File, llvm::StringRef Code, + ArrayRef Ranges, + Callback CB); const ThreadsafeFS &TFS; diff --git a/clang-tools-extra/clangd/ClangdServer.cpp b/clang-tools-extra/clangd/ClangdServer.cpp --- a/clang-tools-extra/clangd/ClangdServer.cpp +++ b/clang-tools-extra/clangd/ClangdServer.cpp @@ -296,40 +296,46 @@ std::move(Action)); } -llvm::Expected -ClangdServer::formatRange(llvm::StringRef Code, PathRef File, Range Rng) { +void ClangdServer::formatRange(PathRef File, llvm::StringRef Code, Range Rng, + Callback CB) { llvm::Expected Begin = positionToOffset(Code, Rng.start); if (!Begin) - return Begin.takeError(); + return CB(Begin.takeError()); llvm::Expected End = positionToOffset(Code, Rng.end); if (!End) - return End.takeError(); - return formatCode(Code, File, {tooling::Range(*Begin, *End - *Begin)}); + return CB(End.takeError()); + formatCode(File, Code, {tooling::Range(*Begin, *End - *Begin)}, + std::move(CB)); } -llvm::Expected -ClangdServer::formatFile(llvm::StringRef Code, PathRef File) { +void ClangdServer::formatFile(PathRef File, llvm::StringRef Code, + Callback CB) { // Format everything. - return formatCode(Code, File, {tooling::Range(0, Code.size())}); + formatCode(File, Code, {tooling::Range(0, Code.size())}, std::move(CB)); } -llvm::Expected> -ClangdServer::formatOnType(llvm::StringRef Code, PathRef File, Position Pos, - StringRef TriggerText) { +void ClangdServer::formatOnType(PathRef File, llvm::StringRef Code, + Position Pos, StringRef TriggerText, + Callback> CB) { llvm::Expected CursorPos = positionToOffset(Code, Pos); if (!CursorPos) - return CursorPos.takeError(); - auto Style = format::getStyle(format::DefaultFormatStyle, File, - format::DefaultFallbackStyle, Code, - TFS.view(/*CWD=*/llvm::None).get()); - if (!Style) - return Style.takeError(); - - std::vector Result; - for (const tooling::Replacement &R : - formatIncremental(Code, *CursorPos, TriggerText, *Style)) - Result.push_back(replacementToEdit(Code, R)); - return Result; + return CB(CursorPos.takeError()); + auto Action = [File = File.str(), Code = Code.str(), + TriggerText = TriggerText.str(), CursorPos = *CursorPos, + CB = std::move(CB), this]() mutable { + auto Style = format::getStyle(format::DefaultFormatStyle, File, + format::DefaultFallbackStyle, Code, + TFS.view(/*CWD=*/llvm::None).get()); + if (!Style) + return CB(Style.takeError()); + + std::vector Result; + for (const tooling::Replacement &R : + formatIncremental(Code, CursorPos, TriggerText, *Style)) + Result.push_back(replacementToEdit(Code, R)); + return CB(Result); + }; + WorkScheduler.run("FormatOnType", std::move(Action)); } void ClangdServer::prepareRename(PathRef File, Position Pos, @@ -561,21 +567,25 @@ WorkScheduler.runWithAST("SwitchHeaderSource", Path, std::move(Action)); } -llvm::Expected -ClangdServer::formatCode(llvm::StringRef Code, PathRef File, - llvm::ArrayRef Ranges) { +void ClangdServer::formatCode(PathRef File, llvm::StringRef Code, + llvm::ArrayRef Ranges, + Callback CB) { // Call clang-format. - format::FormatStyle Style = getFormatStyleForFile(File, Code, TFS); - tooling::Replacements IncludeReplaces = - format::sortIncludes(Style, Code, Ranges, File); - auto Changed = tooling::applyAllReplacements(Code, IncludeReplaces); - if (!Changed) - return Changed.takeError(); - - return IncludeReplaces.merge(format::reformat( - Style, *Changed, - tooling::calculateRangesAfterReplacements(IncludeReplaces, Ranges), - File)); + auto Action = [File = File.str(), Code = Code.str(), Ranges = Ranges.vec(), + CB = std::move(CB), this]() mutable { + format::FormatStyle Style = getFormatStyleForFile(File, Code, TFS); + tooling::Replacements IncludeReplaces = + format::sortIncludes(Style, Code, Ranges, File); + auto Changed = tooling::applyAllReplacements(Code, IncludeReplaces); + if (!Changed) + return CB(Changed.takeError()); + + CB(IncludeReplaces.merge(format::reformat( + Style, *Changed, + tooling::calculateRangesAfterReplacements(IncludeReplaces, Ranges), + File))); + }; + WorkScheduler.run("Format", std::move(Action)); } void ClangdServer::findDocumentHighlights( diff --git a/clang-tools-extra/clangd/unittests/ClangdTests.cpp b/clang-tools-extra/clangd/unittests/ClangdTests.cpp --- a/clang-tools-extra/clangd/unittests/ClangdTests.cpp +++ b/clang-tools-extra/clangd/unittests/ClangdTests.cpp @@ -878,7 +878,7 @@ FS.Files[Path] = Code; runAddDocument(Server, Path, Code); - auto Replaces = Server.formatFile(Code, Path); + auto Replaces = runFormatFile(Server, Path, Code); EXPECT_TRUE(static_cast(Replaces)); auto Changed = tooling::applyAllReplacements(Code, *Replaces); EXPECT_TRUE(static_cast(Changed)); diff --git a/clang-tools-extra/clangd/unittests/SyncAPI.h b/clang-tools-extra/clangd/unittests/SyncAPI.h --- a/clang-tools-extra/clangd/unittests/SyncAPI.h +++ b/clang-tools-extra/clangd/unittests/SyncAPI.h @@ -44,6 +44,9 @@ Position Pos, StringRef NewName, const clangd::RenameOptions &RenameOpts); +llvm::Expected +runFormatFile(ClangdServer &Server, PathRef File, StringRef Code); + std::string runDumpAST(ClangdServer &Server, PathRef File); llvm::Expected> diff --git a/clang-tools-extra/clangd/unittests/SyncAPI.cpp b/clang-tools-extra/clangd/unittests/SyncAPI.cpp --- a/clang-tools-extra/clangd/unittests/SyncAPI.cpp +++ b/clang-tools-extra/clangd/unittests/SyncAPI.cpp @@ -105,6 +105,13 @@ return std::move(*Result); } +llvm::Expected +runFormatFile(ClangdServer &Server, PathRef File, StringRef Code) { + llvm::Optional> Result; + Server.formatFile(File, Code, capture(Result)); + return std::move(*Result); +} + std::string runDumpAST(ClangdServer &Server, PathRef File) { llvm::Optional Result; Server.dumpAST(File, capture(Result));