aboutsummaryrefslogtreecommitdiffstats
path: root/src/plugins/languageclient/languageclientmanager.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'src/plugins/languageclient/languageclientmanager.cpp')
-rw-r--r--src/plugins/languageclient/languageclientmanager.cpp270
1 files changed, 226 insertions, 44 deletions
diff --git a/src/plugins/languageclient/languageclientmanager.cpp b/src/plugins/languageclient/languageclientmanager.cpp
index 637a0efa28..4c5ec02a59 100644
--- a/src/plugins/languageclient/languageclientmanager.cpp
+++ b/src/plugins/languageclient/languageclientmanager.cpp
@@ -26,10 +26,12 @@
#include "languageclientmanager.h"
#include "languageclientutils.h"
+#include "languageclientplugin.h"
#include <coreplugin/editormanager/editormanager.h>
#include <coreplugin/editormanager/ieditor.h>
#include <coreplugin/find/searchresultwindow.h>
+#include <coreplugin/icore.h>
#include <languageserverprotocol/messages.h>
#include <projectexplorer/session.h>
#include <projectexplorer/project.h>
@@ -49,42 +51,51 @@ namespace LanguageClient {
static LanguageClientManager *managerInstance = nullptr;
-LanguageClientManager::LanguageClientManager()
+LanguageClientManager::LanguageClientManager(QObject *parent)
+ : QObject (parent)
{
+ using namespace Core;
+ using namespace ProjectExplorer;
JsonRpcMessageHandler::registerMessageProvider<PublishDiagnosticsNotification>();
JsonRpcMessageHandler::registerMessageProvider<ApplyWorkspaceEditRequest>();
JsonRpcMessageHandler::registerMessageProvider<LogMessageNotification>();
JsonRpcMessageHandler::registerMessageProvider<ShowMessageRequest>();
JsonRpcMessageHandler::registerMessageProvider<ShowMessageNotification>();
- managerInstance = this;
+ JsonRpcMessageHandler::registerMessageProvider<WorkSpaceFolderRequest>();
+ connect(EditorManager::instance(), &EditorManager::editorOpened,
+ this, &LanguageClientManager::editorOpened);
+ connect(EditorManager::instance(), &EditorManager::documentOpened,
+ this, &LanguageClientManager::documentOpened);
+ connect(EditorManager::instance(), &EditorManager::documentClosed,
+ this, &LanguageClientManager::documentClosed);
+ connect(EditorManager::instance(), &EditorManager::saved,
+ this, &LanguageClientManager::documentContentsSaved);
+ connect(EditorManager::instance(), &EditorManager::aboutToSave,
+ this, &LanguageClientManager::documentWillSave);
+ connect(SessionManager::instance(), &SessionManager::projectAdded,
+ this, &LanguageClientManager::projectAdded);
+ connect(SessionManager::instance(), &SessionManager::projectRemoved,
+ this, &LanguageClientManager::projectRemoved);
}
LanguageClientManager::~LanguageClientManager()
{
QTC_ASSERT(m_clients.isEmpty(), qDeleteAll(m_clients));
+ qDeleteAll(m_currentSettings);
+ managerInstance = nullptr;
}
void LanguageClientManager::init()
{
- using namespace Core;
- using namespace ProjectExplorer;
- QTC_ASSERT(managerInstance, return);
- connect(EditorManager::instance(), &EditorManager::editorOpened,
- managerInstance, &LanguageClientManager::editorOpened);
- connect(EditorManager::instance(), &EditorManager::editorsClosed,
- managerInstance, &LanguageClientManager::editorsClosed);
- connect(EditorManager::instance(), &EditorManager::saved,
- managerInstance, &LanguageClientManager::documentContentsSaved);
- connect(EditorManager::instance(), &EditorManager::aboutToSave,
- managerInstance, &LanguageClientManager::documentWillSave);
- connect(SessionManager::instance(), &SessionManager::projectAdded,
- managerInstance, &LanguageClientManager::projectAdded);
- connect(SessionManager::instance(), &SessionManager::projectRemoved,
- managerInstance, &LanguageClientManager::projectRemoved);
+ if (managerInstance)
+ return;
+ QTC_ASSERT(LanguageClientPlugin::instance(), return);
+ managerInstance = new LanguageClientManager(LanguageClientPlugin::instance());
}
void LanguageClientManager::startClient(Client *client)
{
+ QTC_ASSERT(managerInstance, return);
QTC_ASSERT(client, return);
if (managerInstance->m_shuttingDown) {
managerInstance->clientFinished(client);
@@ -99,20 +110,40 @@ void LanguageClientManager::startClient(Client *client)
client->initialize();
else
managerInstance->clientFinished(client);
+
+ connect(client,
+ &Client::initialized,
+ &managerInstance->m_currentDocumentLocatorFilter,
+ &DocumentLocatorFilter::updateCurrentClient);
+}
+
+void LanguageClientManager::startClient(BaseSettings *setting, ProjectExplorer::Project *project)
+{
+ QTC_ASSERT(managerInstance, return);
+ QTC_ASSERT(setting, return);
+ QTC_ASSERT(setting->isValid(), return);
+ Client *client = setting->createClient();
+ QTC_ASSERT(client, return);
+ client->setCurrentProject(project);
+ startClient(client);
+ managerInstance->m_clientsForSetting[setting->m_id].append(client);
}
QVector<Client *> LanguageClientManager::clients()
{
+ QTC_ASSERT(managerInstance, return {});
return managerInstance->m_clients;
}
void LanguageClientManager::addExclusiveRequest(const MessageId &id, Client *client)
{
+ QTC_ASSERT(managerInstance, return);
managerInstance->m_exclusiveRequests[id] << client;
}
void LanguageClientManager::reportFinished(const MessageId &id, Client *byClient)
{
+ QTC_ASSERT(managerInstance, return);
for (Client *client : managerInstance->m_exclusiveRequests[id]) {
if (client != byClient)
client->cancelRequest(id);
@@ -120,11 +151,24 @@ void LanguageClientManager::reportFinished(const MessageId &id, Client *byClient
managerInstance->m_exclusiveRequests.remove(id);
}
+void LanguageClientManager::shutdownClient(Client *client)
+{
+ if (!client)
+ return;
+ if (client->reachable())
+ client->shutdown();
+ else if (client->state() != Client::Shutdown && client->state() != Client::ShutdownRequested)
+ deleteClient(client);
+}
+
void LanguageClientManager::deleteClient(Client *client)
{
+ QTC_ASSERT(managerInstance, return);
QTC_ASSERT(client, return);
client->disconnect();
managerInstance->m_clients.removeAll(client);
+ for (QVector<Client *> &clients : managerInstance->m_clientsForSetting)
+ clients.removeAll(client);
if (managerInstance->m_shuttingDown)
delete client;
else
@@ -133,15 +177,12 @@ void LanguageClientManager::deleteClient(Client *client)
void LanguageClientManager::shutdown()
{
+ QTC_ASSERT(managerInstance, return);
if (managerInstance->m_shuttingDown)
return;
managerInstance->m_shuttingDown = true;
- for (auto interface : managerInstance->m_clients) {
- if (interface->reachable())
- interface->shutdown();
- else
- deleteClient(interface);
- }
+ for (Client *client : managerInstance->m_clients)
+ shutdownClient(client);
QTimer::singleShot(3000, managerInstance, [](){
for (auto interface : managerInstance->m_clients)
deleteClient(interface);
@@ -157,12 +198,107 @@ LanguageClientManager *LanguageClientManager::instance()
QList<Client *> LanguageClientManager::clientsSupportingDocument(
const TextEditor::TextDocument *doc)
{
+ QTC_ASSERT(managerInstance, return {});
QTC_ASSERT(doc, return {};);
return Utils::filtered(managerInstance->reachableClients(), [doc](Client *client) {
return client->isSupportedDocument(doc);
}).toList();
}
+void LanguageClientManager::applySettings()
+{
+ QTC_ASSERT(managerInstance, return);
+ qDeleteAll(managerInstance->m_currentSettings);
+ managerInstance->m_currentSettings = Utils::transform(LanguageClientSettings::currentPageSettings(),
+ [](BaseSettings *settings) {
+ return settings->copy();
+ });
+ LanguageClientSettings::toSettings(Core::ICore::settings(), managerInstance->m_currentSettings);
+
+ const QList<BaseSettings *> restarts = Utils::filtered(managerInstance->m_currentSettings,
+ [](BaseSettings *settings) {
+ return settings->needsRestart();
+ });
+
+ for (BaseSettings *setting : restarts) {
+ for (Client *client : clientForSetting(setting))
+ shutdownClient(client);
+ if (!setting->isValid() || !setting->m_enabled)
+ continue;
+ switch (setting->m_startBehavior) {
+ case BaseSettings::AlwaysOn:
+ startClient(setting);
+ break;
+ case BaseSettings::RequiresFile:
+ if (Utils::anyOf(Core::DocumentModel::openedDocuments(),
+ [filter = setting->m_languageFilter](Core::IDocument *doc) {
+ return filter.isSupported(doc);
+ })) {
+ startClient(setting);
+ }
+ break;
+ case BaseSettings::RequiresProject: {
+ for (Core::IDocument *doc : Core::DocumentModel::openedDocuments()) {
+ if (setting->m_languageFilter.isSupported(doc)) {
+ const Utils::FilePath filePath = doc->filePath();
+ for (ProjectExplorer::Project *project :
+ ProjectExplorer::SessionManager::projects()) {
+ if (project->isKnownFile(filePath))
+ startClient(setting, project);
+ }
+ }
+ }
+ break;
+ }
+ default:
+ break;
+ }
+ }
+}
+
+QList<BaseSettings *> LanguageClientManager::currentSettings()
+{
+ QTC_ASSERT(managerInstance, return {});
+ return managerInstance->m_currentSettings;
+}
+
+QVector<Client *> LanguageClientManager::clientForSetting(const BaseSettings *setting)
+{
+ QTC_ASSERT(managerInstance, return {});
+ auto instance = managerInstance;
+ return instance->m_clientsForSetting.value(setting->m_id);
+}
+
+const BaseSettings *LanguageClientManager::settingForClient(Client *client)
+{
+ QTC_ASSERT(managerInstance, return nullptr);
+ for (const QString &id : managerInstance->m_clientsForSetting.keys()) {
+ for (const Client *settingClient : managerInstance->m_clientsForSetting[id]) {
+ if (settingClient == client) {
+ return Utils::findOrDefault(managerInstance->m_currentSettings,
+ [id](BaseSettings *setting) {
+ return setting->m_id == id;
+ });
+ }
+ }
+ }
+ return nullptr;
+}
+
+Client *LanguageClientManager::clientForEditor(Core::IEditor *iEditor)
+{
+ QTC_ASSERT(managerInstance, return nullptr);
+
+ auto editor = qobject_cast<TextEditor::BaseTextEditor *>(iEditor);
+ if (!editor)
+ return nullptr;
+
+ return Utils::findOrDefault(managerInstance->reachableClients(),
+ [doc = editor->textDocument()](Client *client) {
+ return client->documentOpen(doc);
+ });
+}
+
QVector<Client *> LanguageClientManager::reachableClients()
{
return Utils::filtered(m_clients, &Client::reachable);
@@ -188,7 +324,7 @@ void LanguageClientManager::clientFinished(Client *client)
client->disconnect(this);
client->log(tr("Unexpectedly finished. Restarting in %1 seconds.").arg(restartTimeoutS),
Core::MessageManager::Flash);
- QTimer::singleShot(restartTimeoutS * 1000, client, [client](){ startClient(client); });
+ QTimer::singleShot(restartTimeoutS * 1000, client, [client]() { startClient(client); });
} else {
if (unexpectedFinish && !m_shuttingDown)
client->log(tr("Unexpectedly finished."), Core::MessageManager::Flash);
@@ -198,23 +334,19 @@ void LanguageClientManager::clientFinished(Client *client)
}
}
-void LanguageClientManager::editorOpened(Core::IEditor *iEditor)
+void LanguageClientManager::editorOpened(Core::IEditor *editor)
{
using namespace TextEditor;
- Core::IDocument *document = iEditor->document();
- for (Client *interface : reachableClients())
- interface->openDocument(document);
-
- if (BaseTextEditor *editor = qobject_cast<BaseTextEditor *>(iEditor)) {
- if (TextEditorWidget *widget = editor->editorWidget()) {
+ if (auto *textEditor = qobject_cast<BaseTextEditor *>(editor)) {
+ if (TextEditorWidget *widget = textEditor->editorWidget()) {
connect(widget, &TextEditorWidget::requestLinkAt, this,
- [this, filePath = document->filePath()]
+ [this, filePath = editor->document()->filePath()]
(const QTextCursor &cursor, Utils::ProcessLinkCallback &callback) {
findLinkAt(filePath, cursor, callback);
});
connect(widget, &TextEditorWidget::requestUsages, this,
- [this, filePath = document->filePath()]
- (const QTextCursor &cursor) {
+ [this, filePath = editor->document()->filePath()]
+ (const QTextCursor &cursor){
findUsages(filePath, cursor);
});
connect(widget, &TextEditorWidget::cursorPositionChanged, this, [this, widget](){
@@ -229,20 +361,52 @@ void LanguageClientManager::editorOpened(Core::IEditor *iEditor)
}
});
});
+ updateEditorToolBar(editor);
+ for (auto client : reachableClients())
+ widget->addHoverHandler(client->hoverHandler());
}
}
}
-void LanguageClientManager::editorsClosed(const QList<Core::IEditor *> &editors)
+void LanguageClientManager::documentOpened(Core::IDocument *document)
{
- for (auto iEditor : editors) {
- if (auto editor = qobject_cast<TextEditor::BaseTextEditor *>(iEditor)) {
- const DidCloseTextDocumentParams params(TextDocumentIdentifier(
- DocumentUri::fromFileName(editor->document()->filePath())));
- for (Client *interface : reachableClients())
- interface->closeDocument(params);
+ // check whether we have to start servers for this document
+ for (BaseSettings *setting : LanguageClientSettings::currentPageSettings()) {
+ const QVector<Client *> clients = clientForSetting(setting);
+ if (setting->isValid() && setting->m_enabled
+ && setting->m_languageFilter.isSupported(document)) {
+ if (setting->m_startBehavior == BaseSettings::RequiresProject) {
+ const Utils::FilePath filePath = document->filePath();
+ for (ProjectExplorer::Project *project :
+ ProjectExplorer::SessionManager::projects()) {
+ // check whether file is part of this project
+ if (!project->isKnownFile(filePath))
+ continue;
+
+ // check whether we already have a client running for this project
+ if (Utils::findOrDefault(clients,
+ [project](QPointer<Client> client) {
+ return client->project() == project;
+ })) {
+ continue;
+ }
+ startClient(setting, project);
+ }
+ } else if (setting->m_startBehavior == BaseSettings::RequiresFile && clients.isEmpty()) {
+ startClient(setting);
+ }
}
}
+ for (Client *interface : reachableClients())
+ interface->openDocument(document);
+}
+
+void LanguageClientManager::documentClosed(Core::IDocument *document)
+{
+ const DidCloseTextDocumentParams params(
+ TextDocumentIdentifier(DocumentUri::fromFileName(document->filePath())));
+ for (Client *interface : reachableClients())
+ interface->closeDocument(params);
}
void LanguageClientManager::documentContentsSaved(Core::IDocument *document)
@@ -257,7 +421,7 @@ void LanguageClientManager::documentWillSave(Core::IDocument *document)
interface->documentContentsSaved(document);
}
-void LanguageClientManager::findLinkAt(const Utils::FileName &filePath,
+void LanguageClientManager::findLinkAt(const Utils::FilePath &filePath,
const QTextCursor &cursor,
Utils::ProcessLinkCallback callback)
{
@@ -321,7 +485,7 @@ QList<Core::SearchResultItem> generateSearchResultItems(const LanguageClientArra
return result;
}
-void LanguageClientManager::findUsages(const Utils::FileName &filePath, const QTextCursor &cursor)
+void LanguageClientManager::findUsages(const Utils::FilePath &filePath, const QTextCursor &cursor)
{
const DocumentUri uri = DocumentUri::fromFileName(filePath);
const TextDocumentIdentifier document(uri);
@@ -357,13 +521,31 @@ void LanguageClientManager::findUsages(const Utils::FileName &filePath, const QT
void LanguageClientManager::projectAdded(ProjectExplorer::Project *project)
{
+ for (BaseSettings *setting : m_currentSettings) {
+ if (setting->isValid()
+ && setting->m_enabled
+ && setting->m_startBehavior == BaseSettings::RequiresProject) {
+ if (Utils::findOrDefault(clientForSetting(setting),
+ [project](QPointer<Client> client) {
+ return client->project() == project;
+ })
+ == nullptr) {
+ for (Core::IDocument *doc : Core::DocumentModel::openedDocuments()) {
+ if (setting->m_languageFilter.isSupported(doc)) {
+ if (project->isKnownFile(doc->filePath()))
+ startClient(setting, project);
+ }
+ }
+ }
+ }
+ }
for (Client *interface : reachableClients())
interface->projectOpened(project);
}
void LanguageClientManager::projectRemoved(ProjectExplorer::Project *project)
{
- for (Client *interface : reachableClients())
+ for (Client *interface : m_clients)
interface->projectClosed(project);
}