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 <david.schulz@qt.io>
This commit is contained in:
Christian Kandeler
2021-04-20 15:46:35 +02:00
parent 8e352af0ec
commit 91b6c58518
10 changed files with 35 additions and 17 deletions

View File

@@ -30,12 +30,15 @@
#include <languageclient/languageclientinterface.h> #include <languageclient/languageclientinterface.h>
using namespace LanguageClient; using namespace LanguageClient;
using namespace LanguageServerProtocol;
namespace ClangCodeModel { namespace ClangCodeModel {
namespace Internal { namespace Internal {
static Q_LOGGING_CATEGORY(clangdLog, "qtc.clangcodemodel.clangd", QtWarningMsg); static Q_LOGGING_CATEGORY(clangdLog, "qtc.clangcodemodel.clangd", QtWarningMsg);
static QString indexingToken() { return "backgroundIndexProgress"; }
static BaseClientInterface *clientInterface(const Utils::FilePath &jsonDbDir) static BaseClientInterface *clientInterface(const Utils::FilePath &jsonDbDir)
{ {
QString clangdArgs = "--index --background-index --limit-results=0"; QString clangdArgs = "--index --background-index --limit-results=0";
@@ -63,8 +66,13 @@ ClangdClient::ClangdClient(ProjectExplorer::Project *project, const Utils::FileP
setClientCapabilities(caps); setClientCapabilities(caps);
setLocatorsEnabled(false); setLocatorsEnabled(false);
setDocumentActionsEnabled(false); setDocumentActionsEnabled(false);
setProgressTitleForToken("backgroundIndexProgress", tr("Parsing C/C++ Files (clangd)")); setProgressTitleForToken(indexingToken(), tr("Parsing C/C++ Files (clangd)"));
setCurrentProject(project); setCurrentProject(project);
connect(this, &Client::workDone, this, [this](const ProgressToken &token) {
const QString * const val = Utils::get_if<QString>(&token);
if (val && *val == indexingToken())
m_isFullyIndexed = true;
});
start(); start();
} }

View File

@@ -37,6 +37,11 @@ class ClangdClient : public LanguageClient::Client
Q_OBJECT Q_OBJECT
public: public:
ClangdClient(ProjectExplorer::Project *project, const Utils::FilePath &jsonDbDir); ClangdClient(ProjectExplorer::Project *project, const Utils::FilePath &jsonDbDir);
bool isFullyIndexed() const { return m_isFullyIndexed; }
private:
bool m_isFullyIndexed = false;
}; };
} // namespace Internal } // namespace Internal

View File

@@ -25,6 +25,7 @@
#include "clanggloballocatorfilters.h" #include "clanggloballocatorfilters.h"
#include "clangdclient.h"
#include "clangmodelmanagersupport.h" #include "clangmodelmanagersupport.h"
#include <cpptools/cppclassesfilter.h> #include <cpptools/cppclassesfilter.h>

View File

@@ -326,7 +326,7 @@ void ClangModelManagerSupport::updateLanguageClient(ProjectExplorer::Project *pr
CompilationDbPurpose::CodeModel)); CompilationDbPurpose::CodeModel));
} }
LanguageClient::Client *ClangModelManagerSupport::clientForProject( ClangdClient *ClangModelManagerSupport::clientForProject(
const ProjectExplorer::Project *project) const ProjectExplorer::Project *project)
{ {
const QList<Client *> clients = Utils::filtered( const QList<Client *> clients = Utils::filtered(
@@ -337,10 +337,10 @@ LanguageClient::Client *ClangModelManagerSupport::clientForProject(
&& c->state() != Client::Shutdown; && c->state() != Client::Shutdown;
}); });
QTC_CHECK(clients.size() <= 1); QTC_CHECK(clients.size() <= 1);
return clients.empty() ? nullptr : clients.first(); return clients.empty() ? nullptr : qobject_cast<ClangdClient *>(clients.first());
} }
Client *ClangModelManagerSupport::createClient(ProjectExplorer::Project *project, ClangdClient *ClangModelManagerSupport::createClient(ProjectExplorer::Project *project,
const Utils::FilePath &jsonDbDir) const Utils::FilePath &jsonDbDir)
{ {
return new ClangdClient(project, jsonDbDir); return new ClangdClient(project, jsonDbDir);

View File

@@ -47,11 +47,10 @@ class FollowSymbolInterface;
class RefactoringEngineInterface; class RefactoringEngineInterface;
} // namespace CppTools } // namespace CppTools
namespace LanguageClient { class Client; }
namespace ClangCodeModel { namespace ClangCodeModel {
namespace Internal { namespace Internal {
class ClangdClient;
class ClangProjectSettings; class ClangProjectSettings;
class ClangModelManagerSupport: class ClangModelManagerSupport:
@@ -79,7 +78,7 @@ public:
ClangProjectSettings &projectSettings(ProjectExplorer::Project *project) const; ClangProjectSettings &projectSettings(ProjectExplorer::Project *project) const;
LanguageClient::Client *clientForProject(const ProjectExplorer::Project *project); ClangdClient *clientForProject(const ProjectExplorer::Project *project);
static ClangModelManagerSupport *instance(); static ClangModelManagerSupport *instance();
@@ -124,8 +123,7 @@ private:
void updateLanguageClient(ProjectExplorer::Project *project, void updateLanguageClient(ProjectExplorer::Project *project,
const CppTools::ProjectInfo &projectInfo); const CppTools::ProjectInfo &projectInfo);
LanguageClient::Client *createClient(ProjectExplorer::Project *project, ClangdClient *createClient(ProjectExplorer::Project *project, const Utils::FilePath &jsonDbDir);
const Utils::FilePath &jsonDbDir);
private: private:
UiHeaderOnDiskManager m_uiHeaderOnDiskManager; UiHeaderOnDiskManager m_uiHeaderOnDiskManager;

View File

@@ -26,10 +26,10 @@
#include "clangrefactoringengine.h" #include "clangrefactoringengine.h"
#include "clangeditordocumentprocessor.h" #include "clangeditordocumentprocessor.h"
#include "clangdclient.h"
#include "clangmodelmanagersupport.h" #include "clangmodelmanagersupport.h"
#include <cpptools/cppmodelmanager.h> #include <cpptools/cppmodelmanager.h>
#include <languageclient/client.h>
#include <languageclient/languageclientsymbolsupport.h> #include <languageclient/languageclientsymbolsupport.h>
#include <projectexplorer/session.h> #include <projectexplorer/session.h>
#include <utils/textutils.h> #include <utils/textutils.h>
@@ -91,12 +91,8 @@ void RefactoringEngine::findUsages(const CppTools::CursorInEditor &cursor,
{ {
ProjectExplorer::Project * const project ProjectExplorer::Project * const project
= ProjectExplorer::SessionManager::projectForFile(cursor.filePath()); = ProjectExplorer::SessionManager::projectForFile(cursor.filePath());
LanguageClient::Client * const client ClangdClient * const client = ClangModelManagerSupport::instance()->clientForProject(project);
= ClangModelManagerSupport::instance()->clientForProject(project); if (!client || !client->isFullyIndexed()) {
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
CppTools::CppModelManager::builtinRefactoringEngine() CppTools::CppModelManager::builtinRefactoringEngine()
->findUsages(cursor, std::move(callback)); ->findUsages(cursor, std::move(callback));
return; return;

View File

@@ -1250,6 +1250,8 @@ void Client::handleMethod(const QString &method, const MessageId &id, const ICon
if (!params->isValid()) if (!params->isValid())
logError(*params); logError(*params);
m_progressManager.handleProgress(*params); m_progressManager.handleProgress(*params);
if (ProgressManager::isProgressEndMessage(*params))
emit workDone(params->token());
} }
} else if (id.isValid()) { } else if (id.isValid()) {
Response<JsonObject, JsonObject> response(id); Response<JsonObject, JsonObject> response(id);

View File

@@ -178,6 +178,7 @@ signals:
void initialized(const LanguageServerProtocol::ServerCapabilities &capabilities); void initialized(const LanguageServerProtocol::ServerCapabilities &capabilities);
void capabilitiesChanged(const DynamicCapabilities &capabilities); void capabilitiesChanged(const DynamicCapabilities &capabilities);
void documentUpdated(TextEditor::TextDocument *document); void documentUpdated(TextEditor::TextDocument *document);
void workDone(const LanguageServerProtocol::ProgressToken &token);
void finished(); void finished();
protected: protected:

View File

@@ -61,6 +61,11 @@ void ProgressManager::setTitleForToken(const LanguageServerProtocol::ProgressTok
m_titles.insert(token, message); m_titles.insert(token, message);
} }
bool ProgressManager::isProgressEndMessage(const LanguageServerProtocol::ProgressParams &params)
{
return Utils::holds_alternative<WorkDoneProgressEnd>(params.value());
}
Utils::Id languageClientProgressId(const ProgressToken &token) Utils::Id languageClientProgressId(const ProgressToken &token)
{ {
constexpr char k_LanguageClientProgressId[] = "LanguageClient.ProgressId."; constexpr char k_LanguageClientProgressId[] = "LanguageClient.ProgressId.";

View File

@@ -49,6 +49,8 @@ public:
void setTitleForToken(const LanguageServerProtocol::ProgressToken &token, void setTitleForToken(const LanguageServerProtocol::ProgressToken &token,
const QString &message); const QString &message);
static bool isProgressEndMessage(const LanguageServerProtocol::ProgressParams &params);
private: private:
void beginProgress(const LanguageServerProtocol::ProgressToken &token, void beginProgress(const LanguageServerProtocol::ProgressToken &token,
const LanguageServerProtocol::WorkDoneProgressBegin &begin); const LanguageServerProtocol::WorkDoneProgressBegin &begin);