From 68a5cd65751ebbdfeb747916099a28e33b884b6e Mon Sep 17 00:00:00 2001 From: David Schulz Date: Wed, 31 May 2023 12:12:22 +0200 Subject: [PATCH] LanguageClient: postpone creating progressbars Some language servers are spawning progress reports for many small tasks. This can get distracting in the case where those progress bars are spawned while typing, like in the case of the python language server that creates a report for every lint that gets triggered after receiving a document change notification. So in order to reduce the amount of progress bars created from progress reports we postpone the creation of the bars. Fixes: QTCREATORBUG-29224 Change-Id: I2e658be0a26b21e41c80b444184648ba70682522 Reviewed-by: Reviewed-by: Qt CI Patch Build Bot Reviewed-by: Christian Stenger --- .../languageclient/progressmanager.cpp | 52 ++++++++++++++----- src/plugins/languageclient/progressmanager.h | 15 ++++-- 2 files changed, 50 insertions(+), 17 deletions(-) diff --git a/src/plugins/languageclient/progressmanager.cpp b/src/plugins/languageclient/progressmanager.cpp index 285080e4980..6b82d289dfc 100644 --- a/src/plugins/languageclient/progressmanager.cpp +++ b/src/plugins/languageclient/progressmanager.cpp @@ -8,6 +8,7 @@ #include #include +#include using namespace LanguageServerProtocol; @@ -81,9 +82,28 @@ void ProgressManager::beginProgress(const ProgressToken &token, const WorkDonePr auto interface = new QFutureInterface(); interface->reportStarted(); interface->setProgressRange(0, 100); // LSP always reports percentage of the task - const QString title = m_titles.value(token, begin.title()); - Core::FutureProgress *progress = Core::ProgressManager::addTask( - interface->future(), title, languageClientProgressId(token)); + ProgressItem progressItem; + progressItem.futureInterface = interface; + progressItem.title = m_titles.value(token, begin.title()); + if (LOGPROGRESS().isDebugEnabled()) + progressItem.timer.start(); + progressItem.showBarTimer = new QTimer(); + progressItem.showBarTimer->setSingleShot(true); + progressItem.showBarTimer->setInterval(750); + progressItem.showBarTimer->callOnTimeout([this, token]() { spawnProgressBar(token); }); + progressItem.showBarTimer->start(); + m_progress[token] = progressItem; + reportProgress(token, begin); +} + +void ProgressManager::spawnProgressBar(const LanguageServerProtocol::ProgressToken &token) +{ + ProgressItem &progressItem = m_progress[token]; + QTC_ASSERT(progressItem.futureInterface, return); + Core::FutureProgress *progress + = Core::ProgressManager::addTask(progressItem.futureInterface->future(), + progressItem.title, + languageClientProgressId(token)); const std::function clickHandler = m_clickHandlers.value(token); if (clickHandler) QObject::connect(progress, &Core::FutureProgress::clicked, clickHandler); @@ -92,23 +112,26 @@ void ProgressManager::beginProgress(const ProgressToken &token, const WorkDonePr QObject::connect(progress, &Core::FutureProgress::canceled, cancelHandler); else progress->setCancelEnabled(false); - m_progress[token] = {progress, interface}; - if (LOGPROGRESS().isDebugEnabled()) - m_timer[token].start(); - reportProgress(token, begin); + if (!progressItem.message.isEmpty()) { + progress->setSubtitle(progressItem.message); + progress->setSubtitleVisibleInStatusBar(true); + } + progressItem.progressInterface = progress; } void ProgressManager::reportProgress(const ProgressToken &token, const WorkDoneProgressReport &report) { - const LanguageClientProgress &progress = m_progress.value(token); + ProgressItem &progress = m_progress[token]; + const std::optional &message = report.message(); if (progress.progressInterface) { - const std::optional &message = report.message(); if (message.has_value()) { progress.progressInterface->setSubtitle(*message); const bool showSubtitle = !message->isEmpty(); progress.progressInterface->setSubtitleVisibleInStatusBar(showSubtitle); } + } else if (message.has_value()) { + progress.message = *message; } if (progress.futureInterface) { if (const std::optional &percentage = report.percentage(); percentage.has_value()) @@ -118,7 +141,7 @@ void ProgressManager::reportProgress(const ProgressToken &token, void ProgressManager::endProgress(const ProgressToken &token, const WorkDoneProgressEnd &end) { - const LanguageClientProgress &progress = m_progress.value(token); + const ProgressItem &progress = m_progress.value(token); const QString &message = end.message().value_or(QString()); if (progress.progressInterface) { if (!message.isEmpty()) { @@ -127,11 +150,11 @@ void ProgressManager::endProgress(const ProgressToken &token, const WorkDoneProg } progress.progressInterface->setSubtitle(message); progress.progressInterface->setSubtitleVisibleInStatusBar(!message.isEmpty()); - auto timer = m_timer.take(token); - if (timer.isValid()) { + if (progress.timer.isValid()) { qCDebug(LOGPROGRESS) << QString("%1 took %2") .arg(progress.progressInterface->title()) - .arg(QTime::fromMSecsSinceStartOfDay(timer.elapsed()) + .arg(QTime::fromMSecsSinceStartOfDay( + progress.timer.elapsed()) .toString(Qt::ISODateWithMs)); } } @@ -140,7 +163,8 @@ void ProgressManager::endProgress(const ProgressToken &token, const WorkDoneProg void ProgressManager::endProgressReport(const ProgressToken &token) { - const LanguageClientProgress &progress = m_progress.take(token); + ProgressItem progress = m_progress.take(token); + delete progress.showBarTimer; if (progress.futureInterface) progress.futureInterface->reportFinished(); delete progress.futureInterface; diff --git a/src/plugins/languageclient/progressmanager.h b/src/plugins/languageclient/progressmanager.h index 1e0ad781806..05b9640745d 100644 --- a/src/plugins/languageclient/progressmanager.h +++ b/src/plugins/languageclient/progressmanager.h @@ -11,6 +11,10 @@ #include #include +QT_BEGIN_NAMESPACE +class QTimer; +QT_END_NAMESPACE + namespace LanguageServerProtocol { class ProgressParams; class ProgressToken; @@ -46,15 +50,20 @@ private: const LanguageServerProtocol::WorkDoneProgressReport &report); void endProgress(const LanguageServerProtocol::ProgressToken &token, const LanguageServerProtocol::WorkDoneProgressEnd &end); + void spawnProgressBar(const LanguageServerProtocol::ProgressToken &token); - struct LanguageClientProgress { + struct ProgressItem + { QPointer progressInterface = nullptr; QFutureInterface *futureInterface = nullptr; + QElapsedTimer timer; + QTimer *showBarTimer = nullptr; + QString message; + QString title; }; - QMap m_progress; + QMap m_progress; QMap m_titles; - QMap m_timer; QMap> m_clickHandlers; QMap> m_cancelHandlers; };