diff --git a/src/plugins/languageclient/languageclientmanager.cpp b/src/plugins/languageclient/languageclientmanager.cpp index 275e9ed9e49..4de4a0de46e 100644 --- a/src/plugins/languageclient/languageclientmanager.cpp +++ b/src/plugins/languageclient/languageclientmanager.cpp @@ -30,7 +30,6 @@ #include #include -#include #include using namespace LanguageServerProtocol; @@ -44,10 +43,10 @@ static bool g_shuttingDown = false; class LanguageClientManagerPrivate { - DocumentLocatorFilter m_currentDocumentLocatorFilter; - WorkspaceLocatorFilter m_workspaceLocatorFilter; - WorkspaceClassLocatorFilter m_workspaceClassLocatorFilter; - WorkspaceMethodLocatorFilter m_workspaceMethodLocatorFilter; + LanguageCurrentDocumentFilter m_currentDocumentFilter; + LanguageAllSymbolsFilter m_allSymbolsFilter; + LanguageClassesFilter m_classFilter; + LanguageFunctionsFilter m_functionFilter; }; LanguageClientManager::LanguageClientManager(QObject *parent) diff --git a/src/plugins/languageclient/locatorfilter.cpp b/src/plugins/languageclient/locatorfilter.cpp index 5d52f28f232..04caf2d1723 100644 --- a/src/plugins/languageclient/locatorfilter.cpp +++ b/src/plugins/languageclient/locatorfilter.cpp @@ -5,23 +5,14 @@ #include "clientrequesttask.h" #include "currentdocumentsymbolsrequest.h" -#include "documentsymbolcache.h" -#include "languageclient_global.h" #include "languageclientmanager.h" #include "languageclienttr.h" -#include - #include -#include - -#include - #include #include -#include #include using namespace Core; @@ -60,7 +51,7 @@ LocatorMatcherTask locatorMatcher(Client *client, int maxResultCount, TreeStorage storage; TreeStorage> resultStorage; - const auto onQuerySetup = [=](WorkspaceSymbolRequestTask &request) { + const auto onQuerySetup = [storage, client, maxResultCount](WorkspaceSymbolRequestTask &request) { request.setClient(client); WorkspaceSymbolParams params; params.setQuery(storage->input()); @@ -75,7 +66,7 @@ LocatorMatcherTask locatorMatcher(Client *client, int maxResultCount, *resultStorage = result->toList(); }; - const auto onFilterSetup = [=](Async &async) { + const auto onFilterSetup = [storage, resultStorage, client, filter](Async &async) { const QList results = *resultStorage; if (results.isEmpty()) return TaskAction::StopWithDone; @@ -131,14 +122,14 @@ LocatorMatcherTask currentDocumentMatcher() TreeStorage storage; TreeStorage resultStorage; - const auto onQuerySetup = [=](CurrentDocumentSymbolsRequest &request) { + const auto onQuerySetup = [](CurrentDocumentSymbolsRequest &request) { Q_UNUSED(request) }; const auto onQueryDone = [resultStorage](const CurrentDocumentSymbolsRequest &request) { *resultStorage = request.currentDocumentSymbolsData(); }; - const auto onFilterSetup = [=](Async &async) { + const auto onFilterSetup = [storage, resultStorage](Async &async) { async.setFutureSynchronizer(ExtensionSystem::PluginManager::futureSynchronizer()); async.setConcurrentCallData(filterCurrentResults, *storage, *resultStorage); }; @@ -178,7 +169,7 @@ LocatorMatcherTasks languageClientMatchers(MatcherType type, const QListlocatorsEnabled() || m_forced)) { - - setEnabled(!m_forced); - if (m_symbolCache != client->documentSymbolCache()) { - disconnect(m_updateSymbolsConnection); - m_symbolCache = client->documentSymbolCache(); - m_updateSymbolsConnection = connect(m_symbolCache, &DocumentSymbolCache::gotSymbols, - this, &DocumentLocatorFilter::updateSymbols); - } - m_resetSymbolsConnection = connect(document, &IDocument::contentsChanged, - this, &DocumentLocatorFilter::resetSymbols); - m_currentUri = client->hostPathToServerUri(document->filePath()); - m_pathMapper = client->hostPathMapper(); - } else { - disconnect(m_updateSymbolsConnection); - m_symbolCache.clear(); - m_currentUri.clear(); - setEnabled(false); - m_pathMapper = DocumentUri::PathMapper(); - } -} - -void DocumentLocatorFilter::updateSymbols(const DocumentUri &uri, - const DocumentSymbolsResult &symbols) -{ - if (uri != m_currentUri) - return; - QMutexLocker locker(&m_mutex); - m_currentSymbols = symbols; - emit symbolsUpToDate(QPrivateSignal()); -} - -void DocumentLocatorFilter::resetSymbols() -{ - QMutexLocker locker(&m_mutex); - m_currentSymbols.reset(); -} - static LocatorFilterEntry entryForSymbolInfo(const SymbolInformation &info, - DocumentUri::PathMapper pathMapper) + const DocumentUri::PathMapper &pathMapper) { LocatorFilterEntry entry; entry.displayName = info.name(); @@ -305,78 +247,7 @@ Core::LocatorFilterEntries currentDocumentSymbols(const QString &input, return {}; } -void DocumentLocatorFilter::prepareSearch(const QString &/*entry*/) -{ - QMutexLocker locker(&m_mutex); - m_currentFilePath = m_pathMapper ? m_currentUri.toFilePath(m_pathMapper) : FilePath(); - if (m_symbolCache && !m_currentSymbols.has_value()) { - locker.unlock(); - m_symbolCache->requestSymbols(m_currentUri, Schedule::Now); - } -} - -QList DocumentLocatorFilter::matchesFor( - QFutureInterface &future, const QString &entry) -{ - const auto docSymbolModifier = [](LocatorFilterEntry &entry, const DocumentSymbol &info, - const LocatorFilterEntry &parent) { - Q_UNUSED(parent) - entry.displayName = info.name(); - if (std::optional detail = info.detail()) - entry.extraInfo = *detail; - }; - return matchesForImpl(future, entry, docSymbolModifier); -} - -QList DocumentLocatorFilter::matchesForImpl( - QFutureInterface &future, const QString &entry, - const DocSymbolModifier &docSymbolModifier) -{ - const FuzzyMatcher::CaseSensitivity caseSensitivity - = ILocatorFilter::caseSensitivity(entry) == Qt::CaseSensitive - ? FuzzyMatcher::CaseSensitivity::CaseSensitive - : FuzzyMatcher::CaseSensitivity::CaseInsensitive; - const QRegularExpression regExp = FuzzyMatcher::createRegExp(entry, caseSensitivity); - if (!regExp.isValid()) - return {}; - - QMutexLocker locker(&m_mutex); - if (!m_symbolCache) - return {}; - if (!m_currentSymbols.has_value()) { - QEventLoop loop; - connect(this, &DocumentLocatorFilter::symbolsUpToDate, &loop, [&] { loop.exit(1); }); - QFutureWatcher watcher; - connect(&watcher, &QFutureWatcher::canceled, &loop, &QEventLoop::quit); - watcher.setFuture(future.future()); - locker.unlock(); - if (!loop.exec()) - return {}; - locker.relock(); - } - - QTC_ASSERT(m_currentSymbols.has_value(), return {}); - - if (auto list = std::get_if>(&*m_currentSymbols)) - return entriesForDocSymbols(*list, regExp, m_currentFilePath, docSymbolModifier); - else if (auto list = std::get_if>(&*m_currentSymbols)) - return entriesForSymbolsInfo(*list, regExp, m_pathMapper); - - return {}; -} - -WorkspaceLocatorFilter::WorkspaceLocatorFilter() - : WorkspaceLocatorFilter(QVector()) -{} - -LocatorMatcherTasks WorkspaceLocatorFilter::matchers() -{ - return languageClientMatchers(MatcherType::AllSymbols, - Utils::filtered(LanguageClientManager::clients(), &Client::locatorsEnabled)); -} - -WorkspaceLocatorFilter::WorkspaceLocatorFilter(const QVector &filter) - : m_filterKinds(filter) +LanguageAllSymbolsFilter::LanguageAllSymbolsFilter() { setId(Constants::LANGUAGECLIENT_WORKSPACE_FILTER_ID); setDisplayName(Tr::tr(Constants::LANGUAGECLIENT_WORKSPACE_FILTER_DISPLAY_NAME)); @@ -386,94 +257,13 @@ WorkspaceLocatorFilter::WorkspaceLocatorFilter(const QVector &filter setPriority(ILocatorFilter::Low); } -void WorkspaceLocatorFilter::prepareSearch(const QString &entry) +LocatorMatcherTasks LanguageAllSymbolsFilter::matchers() { - prepareSearchForClients(entry, Utils::filtered(LanguageClientManager::clients(), - &Client::locatorsEnabled)); + return languageClientMatchers(MatcherType::AllSymbols, + Utils::filtered(LanguageClientManager::clients(), &Client::locatorsEnabled)); } -void WorkspaceLocatorFilter::prepareSearchForClients(const QString &entry, - const QList &clients) -{ - m_pendingRequests.clear(); - m_results.clear(); - - if (clients.isEmpty()) - return; - - WorkspaceSymbolParams params; - params.setQuery(entry); - if (m_maxResultCount > 0) - params.setLimit(m_maxResultCount); - - QMutexLocker locker(&m_mutex); - for (auto client : std::as_const(clients)) { - if (!client->reachable()) - continue; - std::optional> capability - = client->capabilities().workspaceSymbolProvider(); - if (!capability.has_value()) - continue; - if (std::holds_alternative(*capability) && !std::get(*capability)) - continue; - WorkspaceSymbolRequest request(params); - request.setResponseCallback( - [this, client](const WorkspaceSymbolRequest::Response &response) { - handleResponse(client, response); - }); - m_pendingRequests[client] = request.id(); - client->sendMessage(request); - } -} - -QList WorkspaceLocatorFilter::matchesFor( - QFutureInterface &future, const QString & /*entry*/) -{ - QMutexLocker locker(&m_mutex); - if (!m_pendingRequests.isEmpty()) { - QEventLoop loop; - connect(this, &WorkspaceLocatorFilter::allRequestsFinished, &loop, [&] { loop.exit(1); }); - QFutureWatcher watcher; - connect(&watcher, - &QFutureWatcher::canceled, - &loop, - &QEventLoop::quit); - watcher.setFuture(future.future()); - locker.unlock(); - if (!loop.exec()) - return {}; - - locker.relock(); - } - - if (!m_filterKinds.isEmpty()) { - m_results = Utils::filtered(m_results, [&](const SymbolInfoWithPathMapper &info) { - return m_filterKinds.contains(SymbolKind(info.symbol.kind())); - }); - } - auto generateEntry = [](const SymbolInfoWithPathMapper &info) { - return entryForSymbolInfo(info.symbol, info.mapper); - }; - return Utils::transform(m_results, generateEntry).toList(); -} - -void WorkspaceLocatorFilter::handleResponse(Client *client, - const WorkspaceSymbolRequest::Response &response) -{ - QMutexLocker locker(&m_mutex); - m_pendingRequests.remove(client); - auto result = response.result().value_or(LanguageClientArray()); - if (!result.isNull()) - m_results.append( - Utils::transform(result.toList(), [client](const SymbolInformation &info) { - return SymbolInfoWithPathMapper{info, client->hostPathMapper()}; - })); - if (m_pendingRequests.isEmpty()) - emit allRequestsFinished(QPrivateSignal()); -} - -WorkspaceClassLocatorFilter::WorkspaceClassLocatorFilter() - : WorkspaceLocatorFilter({SymbolKind::Class, SymbolKind::Struct}) +LanguageClassesFilter::LanguageClassesFilter() { setId(Constants::LANGUAGECLIENT_WORKSPACE_CLASS_FILTER_ID); setDisplayName(Tr::tr(Constants::LANGUAGECLIENT_WORKSPACE_CLASS_FILTER_DISPLAY_NAME)); @@ -481,14 +271,13 @@ WorkspaceClassLocatorFilter::WorkspaceClassLocatorFilter() setDefaultShortcutString("c"); } -LocatorMatcherTasks WorkspaceClassLocatorFilter::matchers() +LocatorMatcherTasks LanguageClassesFilter::matchers() { return languageClientMatchers(MatcherType::Classes, Utils::filtered(LanguageClientManager::clients(), &Client::locatorsEnabled)); } -WorkspaceMethodLocatorFilter::WorkspaceMethodLocatorFilter() - : WorkspaceLocatorFilter({SymbolKind::Method, SymbolKind::Function, SymbolKind::Constructor}) +LanguageFunctionsFilter::LanguageFunctionsFilter() { setId(Constants::LANGUAGECLIENT_WORKSPACE_METHOD_FILTER_ID); setDisplayName(Tr::tr(Constants::LANGUAGECLIENT_WORKSPACE_METHOD_FILTER_DISPLAY_NAME)); @@ -496,7 +285,7 @@ WorkspaceMethodLocatorFilter::WorkspaceMethodLocatorFilter() setDefaultShortcutString("m"); } -LocatorMatcherTasks WorkspaceMethodLocatorFilter::matchers() +LocatorMatcherTasks LanguageFunctionsFilter::matchers() { return languageClientMatchers(MatcherType::Functions, Utils::filtered(LanguageClientManager::clients(), &Client::locatorsEnabled)); diff --git a/src/plugins/languageclient/locatorfilter.h b/src/plugins/languageclient/locatorfilter.h index 286e064c509..39d135723ce 100644 --- a/src/plugins/languageclient/locatorfilter.h +++ b/src/plugins/languageclient/locatorfilter.h @@ -3,22 +3,15 @@ #pragma once -#include "client.h" #include "languageclient_global.h" #include -#include -#include -#include - -#include -#include - -namespace Core { class IEditor; } +namespace LanguageServerProtocol { class DocumentSymbol; }; namespace LanguageClient { +class Client; class CurrentDocumentSymbolsData; using DocSymbolModifier = std::function &clients = {}, int maxResultCount = 0); -class LanguageClientManager; - -class LANGUAGECLIENT_EXPORT DocumentLocatorFilter : public Core::ILocatorFilter -{ - Q_OBJECT -public: - DocumentLocatorFilter(); - - void prepareSearch(const QString &entry) override; - QList matchesFor(QFutureInterface &future, - const QString &entry) override; -signals: - void symbolsUpToDate(QPrivateSignal); - -protected: - void forceUse() { m_forced = true; } - - Utils::FilePath m_currentFilePath; - - QList matchesForImpl( - QFutureInterface &future, const QString &entry, - const DocSymbolModifier &docSymbolModifier); - -private: - Core::LocatorMatcherTasks matchers() final; - void updateCurrentClient(); - void updateSymbols(const LanguageServerProtocol::DocumentUri &uri, - const LanguageServerProtocol::DocumentSymbolsResult &symbols); - void resetSymbols(); - - QMutex m_mutex; - QMetaObject::Connection m_updateSymbolsConnection; - QMetaObject::Connection m_resetSymbolsConnection; - std::optional m_currentSymbols; - LanguageServerProtocol::DocumentUri::PathMapper m_pathMapper; - bool m_forced = false; - QPointer m_symbolCache; - LanguageServerProtocol::DocumentUri m_currentUri; -}; - -class LANGUAGECLIENT_EXPORT WorkspaceLocatorFilter : public Core::ILocatorFilter -{ - Q_OBJECT -public: - WorkspaceLocatorFilter(); - - /// request workspace symbols for all clients with enabled locator - void prepareSearch(const QString &entry) override; - QList matchesFor(QFutureInterface &future, - const QString &entry) override; -signals: - void allRequestsFinished(QPrivateSignal); - -protected: - explicit WorkspaceLocatorFilter(const QVector &filter); - - /// force request workspace symbols for all given clients - void prepareSearchForClients(const QString &entry, const QList &clients); - void setMaxResultCount(qint64 limit) { m_maxResultCount = limit; } - -private: - Core::LocatorMatcherTasks matchers() override; - void handleResponse(Client *client, - const LanguageServerProtocol::WorkspaceSymbolRequest::Response &response); - - QMutex m_mutex; - - struct SymbolInfoWithPathMapper - { - LanguageServerProtocol::SymbolInformation symbol; - LanguageServerProtocol::DocumentUri::PathMapper mapper; - }; - - QMap m_pendingRequests; - QVector m_results; - QVector m_filterKinds; - qint64 m_maxResultCount = 0; -}; - -// TODO: Don't derive, flatten the hierarchy -class LANGUAGECLIENT_EXPORT WorkspaceClassLocatorFilter : public WorkspaceLocatorFilter +class LanguageAllSymbolsFilter : public Core::ILocatorFilter { public: - WorkspaceClassLocatorFilter(); + LanguageAllSymbolsFilter(); private: Core::LocatorMatcherTasks matchers() final; }; -// TODO: Don't derive, flatten the hierarchy -class LANGUAGECLIENT_EXPORT WorkspaceMethodLocatorFilter : public WorkspaceLocatorFilter +class LanguageClassesFilter : public Core::ILocatorFilter { public: - WorkspaceMethodLocatorFilter(); + LanguageClassesFilter(); + +private: + Core::LocatorMatcherTasks matchers() final; +}; + +class LanguageFunctionsFilter : public Core::ILocatorFilter +{ +public: + LanguageFunctionsFilter(); + +private: + Core::LocatorMatcherTasks matchers() final; +}; + +class LanguageCurrentDocumentFilter : public Core::ILocatorFilter +{ +public: + LanguageCurrentDocumentFilter(); private: Core::LocatorMatcherTasks matchers() final;