From 91b6c58518ad0c2379c0511e8a4a25f3fd79443f Mon Sep 17 00:00:00 2001 From: Christian Kandeler Date: Tue, 20 Apr 2021 15:46:35 +0200 Subject: [PATCH] LanguageClient: Add signal to inform about WorkDoneProgressEnd ... and make use of it in the clangd client to be able tell when background indexing has finished. Change-Id: I0f3c6f9646fd66ababd08c12b2f347da5f1a3729 Reviewed-by: David Schulz --- src/plugins/clangcodemodel/clangdclient.cpp | 10 +++++++++- src/plugins/clangcodemodel/clangdclient.h | 5 +++++ .../clangcodemodel/clanggloballocatorfilters.cpp | 1 + .../clangcodemodel/clangmodelmanagersupport.cpp | 8 ++++---- src/plugins/clangcodemodel/clangmodelmanagersupport.h | 8 +++----- src/plugins/clangcodemodel/clangrefactoringengine.cpp | 10 +++------- src/plugins/languageclient/client.cpp | 2 ++ src/plugins/languageclient/client.h | 1 + src/plugins/languageclient/progressmanager.cpp | 5 +++++ src/plugins/languageclient/progressmanager.h | 2 ++ 10 files changed, 35 insertions(+), 17 deletions(-) diff --git a/src/plugins/clangcodemodel/clangdclient.cpp b/src/plugins/clangcodemodel/clangdclient.cpp index 3ffa4466ea0..7ea9fd03d96 100644 --- a/src/plugins/clangcodemodel/clangdclient.cpp +++ b/src/plugins/clangcodemodel/clangdclient.cpp @@ -30,12 +30,15 @@ #include using namespace LanguageClient; +using namespace LanguageServerProtocol; namespace ClangCodeModel { namespace Internal { static Q_LOGGING_CATEGORY(clangdLog, "qtc.clangcodemodel.clangd", QtWarningMsg); +static QString indexingToken() { return "backgroundIndexProgress"; } + static BaseClientInterface *clientInterface(const Utils::FilePath &jsonDbDir) { QString clangdArgs = "--index --background-index --limit-results=0"; @@ -63,8 +66,13 @@ ClangdClient::ClangdClient(ProjectExplorer::Project *project, const Utils::FileP setClientCapabilities(caps); setLocatorsEnabled(false); setDocumentActionsEnabled(false); - setProgressTitleForToken("backgroundIndexProgress", tr("Parsing C/C++ Files (clangd)")); + setProgressTitleForToken(indexingToken(), tr("Parsing C/C++ Files (clangd)")); setCurrentProject(project); + connect(this, &Client::workDone, this, [this](const ProgressToken &token) { + const QString * const val = Utils::get_if(&token); + if (val && *val == indexingToken()) + m_isFullyIndexed = true; + }); start(); } diff --git a/src/plugins/clangcodemodel/clangdclient.h b/src/plugins/clangcodemodel/clangdclient.h index b1d3bfc24d4..f639419bbd9 100644 --- a/src/plugins/clangcodemodel/clangdclient.h +++ b/src/plugins/clangcodemodel/clangdclient.h @@ -37,6 +37,11 @@ class ClangdClient : public LanguageClient::Client Q_OBJECT public: ClangdClient(ProjectExplorer::Project *project, const Utils::FilePath &jsonDbDir); + + bool isFullyIndexed() const { return m_isFullyIndexed; } + +private: + bool m_isFullyIndexed = false; }; } // namespace Internal diff --git a/src/plugins/clangcodemodel/clanggloballocatorfilters.cpp b/src/plugins/clangcodemodel/clanggloballocatorfilters.cpp index 34ed11de098..38e45f8e355 100644 --- a/src/plugins/clangcodemodel/clanggloballocatorfilters.cpp +++ b/src/plugins/clangcodemodel/clanggloballocatorfilters.cpp @@ -25,6 +25,7 @@ #include "clanggloballocatorfilters.h" +#include "clangdclient.h" #include "clangmodelmanagersupport.h" #include diff --git a/src/plugins/clangcodemodel/clangmodelmanagersupport.cpp b/src/plugins/clangcodemodel/clangmodelmanagersupport.cpp index f934d0c54d8..62a66fe21ed 100644 --- a/src/plugins/clangcodemodel/clangmodelmanagersupport.cpp +++ b/src/plugins/clangcodemodel/clangmodelmanagersupport.cpp @@ -326,7 +326,7 @@ void ClangModelManagerSupport::updateLanguageClient(ProjectExplorer::Project *pr CompilationDbPurpose::CodeModel)); } -LanguageClient::Client *ClangModelManagerSupport::clientForProject( +ClangdClient *ClangModelManagerSupport::clientForProject( const ProjectExplorer::Project *project) { const QList clients = Utils::filtered( @@ -337,11 +337,11 @@ LanguageClient::Client *ClangModelManagerSupport::clientForProject( && c->state() != Client::Shutdown; }); QTC_CHECK(clients.size() <= 1); - return clients.empty() ? nullptr : clients.first(); + return clients.empty() ? nullptr : qobject_cast(clients.first()); } -Client *ClangModelManagerSupport::createClient(ProjectExplorer::Project *project, - const Utils::FilePath &jsonDbDir) +ClangdClient *ClangModelManagerSupport::createClient(ProjectExplorer::Project *project, + const Utils::FilePath &jsonDbDir) { return new ClangdClient(project, jsonDbDir); } diff --git a/src/plugins/clangcodemodel/clangmodelmanagersupport.h b/src/plugins/clangcodemodel/clangmodelmanagersupport.h index 4f0e5543572..bd3080e4c0e 100644 --- a/src/plugins/clangcodemodel/clangmodelmanagersupport.h +++ b/src/plugins/clangcodemodel/clangmodelmanagersupport.h @@ -47,11 +47,10 @@ class FollowSymbolInterface; class RefactoringEngineInterface; } // namespace CppTools -namespace LanguageClient { class Client; } - namespace ClangCodeModel { namespace Internal { +class ClangdClient; class ClangProjectSettings; class ClangModelManagerSupport: @@ -79,7 +78,7 @@ public: ClangProjectSettings &projectSettings(ProjectExplorer::Project *project) const; - LanguageClient::Client *clientForProject(const ProjectExplorer::Project *project); + ClangdClient *clientForProject(const ProjectExplorer::Project *project); static ClangModelManagerSupport *instance(); @@ -124,8 +123,7 @@ private: void updateLanguageClient(ProjectExplorer::Project *project, const CppTools::ProjectInfo &projectInfo); - LanguageClient::Client *createClient(ProjectExplorer::Project *project, - const Utils::FilePath &jsonDbDir); + ClangdClient *createClient(ProjectExplorer::Project *project, const Utils::FilePath &jsonDbDir); private: UiHeaderOnDiskManager m_uiHeaderOnDiskManager; diff --git a/src/plugins/clangcodemodel/clangrefactoringengine.cpp b/src/plugins/clangcodemodel/clangrefactoringengine.cpp index aad2e650ebc..0328bc89ba0 100644 --- a/src/plugins/clangcodemodel/clangrefactoringengine.cpp +++ b/src/plugins/clangcodemodel/clangrefactoringengine.cpp @@ -26,10 +26,10 @@ #include "clangrefactoringengine.h" #include "clangeditordocumentprocessor.h" +#include "clangdclient.h" #include "clangmodelmanagersupport.h" #include -#include #include #include #include @@ -91,12 +91,8 @@ void RefactoringEngine::findUsages(const CppTools::CursorInEditor &cursor, { ProjectExplorer::Project * const project = ProjectExplorer::SessionManager::projectForFile(cursor.filePath()); - LanguageClient::Client * const client - = ClangModelManagerSupport::instance()->clientForProject(project); - if (!client || client->state() != LanguageClient::Client::Initialized) { - // TODO: Also forward to built-in if index is not ready. - // This requires us to keep track of workDone status in the client. - // Related: Also allow to override the server string for progress info + ClangdClient * const client = ClangModelManagerSupport::instance()->clientForProject(project); + if (!client || !client->isFullyIndexed()) { CppTools::CppModelManager::builtinRefactoringEngine() ->findUsages(cursor, std::move(callback)); return; diff --git a/src/plugins/languageclient/client.cpp b/src/plugins/languageclient/client.cpp index dd2c6b2088b..aa66b0310d9 100644 --- a/src/plugins/languageclient/client.cpp +++ b/src/plugins/languageclient/client.cpp @@ -1250,6 +1250,8 @@ void Client::handleMethod(const QString &method, const MessageId &id, const ICon if (!params->isValid()) logError(*params); m_progressManager.handleProgress(*params); + if (ProgressManager::isProgressEndMessage(*params)) + emit workDone(params->token()); } } else if (id.isValid()) { Response response(id); diff --git a/src/plugins/languageclient/client.h b/src/plugins/languageclient/client.h index ed9ca52605e..e91c59151db 100644 --- a/src/plugins/languageclient/client.h +++ b/src/plugins/languageclient/client.h @@ -178,6 +178,7 @@ signals: void initialized(const LanguageServerProtocol::ServerCapabilities &capabilities); void capabilitiesChanged(const DynamicCapabilities &capabilities); void documentUpdated(TextEditor::TextDocument *document); + void workDone(const LanguageServerProtocol::ProgressToken &token); void finished(); protected: diff --git a/src/plugins/languageclient/progressmanager.cpp b/src/plugins/languageclient/progressmanager.cpp index e6f12e8729d..fe0e219376b 100644 --- a/src/plugins/languageclient/progressmanager.cpp +++ b/src/plugins/languageclient/progressmanager.cpp @@ -61,6 +61,11 @@ void ProgressManager::setTitleForToken(const LanguageServerProtocol::ProgressTok m_titles.insert(token, message); } +bool ProgressManager::isProgressEndMessage(const LanguageServerProtocol::ProgressParams ¶ms) +{ + return Utils::holds_alternative(params.value()); +} + Utils::Id languageClientProgressId(const ProgressToken &token) { constexpr char k_LanguageClientProgressId[] = "LanguageClient.ProgressId."; diff --git a/src/plugins/languageclient/progressmanager.h b/src/plugins/languageclient/progressmanager.h index 0c2056affce..6cc93f07bad 100644 --- a/src/plugins/languageclient/progressmanager.h +++ b/src/plugins/languageclient/progressmanager.h @@ -49,6 +49,8 @@ public: void setTitleForToken(const LanguageServerProtocol::ProgressToken &token, const QString &message); + static bool isProgressEndMessage(const LanguageServerProtocol::ProgressParams ¶ms); + private: void beginProgress(const LanguageServerProtocol::ProgressToken &token, const LanguageServerProtocol::WorkDoneProgressBegin &begin);