From 5a2de2609e797143fe830f55a838ab73c8584cd8 Mon Sep 17 00:00:00 2001 From: David Schulz Date: Mon, 17 Feb 2020 13:06:08 +0100 Subject: [PATCH] Python: detect language server for python asynchron Change-Id: I775e4cc21dc443b9ec6af81fabef9cf2bfd4e7d2 Fixes: QTCREATORBUG-23599 Reviewed-by: Christian Stenger --- src/plugins/python/pythonutils.cpp | 68 +++++++++++++++++++++--------- src/plugins/python/pythonutils.h | 5 +++ 2 files changed, 52 insertions(+), 21 deletions(-) diff --git a/src/plugins/python/pythonutils.cpp b/src/plugins/python/pythonutils.cpp index bc0309a3028..e584a90e4d3 100644 --- a/src/plugins/python/pythonutils.cpp +++ b/src/plugins/python/pythonutils.cpp @@ -44,6 +44,7 @@ #include #include +#include #include #include @@ -144,20 +145,19 @@ static PythonLanguageServerState checkPythonLanguageServer(const FilePath &pytho using namespace LanguageClient; SynchronousProcess pythonProcess; const CommandLine pythonLShelpCommand(python, {"-m", "pyls", "-h"}); - SynchronousProcessResponse response = pythonProcess.runBlocking(pythonLShelpCommand); - if (response.allOutput().contains("Python Language Server")) { - const FilePath &modulePath = getPylsModulePath(pythonLShelpCommand); - for (const StdIOSettings *serverSetting : configuredPythonLanguageServer()) { - if (modulePath == getPylsModulePath(serverSetting->command())) { - return {serverSetting->m_enabled ? PythonLanguageServerState::AlreadyConfigured - : PythonLanguageServerState::ConfiguredButDisabled, - FilePath()}; - } + const FilePath &modulePath = getPylsModulePath(pythonLShelpCommand); + for (const StdIOSettings *serverSetting : configuredPythonLanguageServer()) { + if (modulePath == getPylsModulePath(serverSetting->command())) { + return {serverSetting->m_enabled ? PythonLanguageServerState::AlreadyConfigured + : PythonLanguageServerState::ConfiguredButDisabled, + FilePath()}; } - - return {PythonLanguageServerState::AlreadyInstalled, modulePath}; } + SynchronousProcessResponse response = pythonProcess.runBlocking(pythonLShelpCommand); + if (response.allOutput().contains("Python Language Server")) + return {PythonLanguageServerState::AlreadyInstalled, modulePath}; + const CommandLine pythonPipVersionCommand(python, {"-m", "pip", "-V"}); response = pythonProcess.runBlocking(pythonPipVersionCommand); if (response.allOutput().startsWith("pip ")) @@ -368,11 +368,38 @@ void PyLSConfigureAssistant::documentOpened(Core::IDocument *document) void PyLSConfigureAssistant::openDocumentWithPython(const FilePath &python, TextEditor::TextDocument *document) { - const PythonLanguageServerState &lsState = checkPythonLanguageServer(python); + using CheckPylsWatcher = QFutureWatcher; - if (lsState.state == PythonLanguageServerState::CanNotBeInstalled) + QPointer watcher = new CheckPylsWatcher(); + watcher->setFuture(Utils::runAsync(&checkPythonLanguageServer, python)); + + // cancel and delete watcher after a 10 second timeout + QTimer::singleShot(10000, this, [watcher]() { + if (watcher) { + watcher->cancel(); + watcher->deleteLater(); + } + }); + + connect( + watcher, + &CheckPylsWatcher::resultReadyAt, + this, + [=, document = QPointer(document)]() { + if (!document || !watcher) + return; + handlePyLSState(python, watcher->result(), document); + watcher->deleteLater(); + }); +} + +void PyLSConfigureAssistant::handlePyLSState(const FilePath &python, + const PythonLanguageServerState &state, + TextEditor::TextDocument *document) +{ + if (state.state == PythonLanguageServerState::CanNotBeInstalled) return; - if (lsState.state == PythonLanguageServerState::AlreadyConfigured) { + if (state.state == PythonLanguageServerState::AlreadyConfigured) { if (const StdIOSettings *setting = languageServerForPython(python)) { if (Client *client = LanguageClientManager::clientForSetting(setting).value(0)) LanguageClientManager::reOpenDocumentWithClient(document, client); @@ -382,12 +409,11 @@ void PyLSConfigureAssistant::openDocumentWithPython(const FilePath &python, resetEditorInfoBar(document); Core::InfoBar *infoBar = document->infoBar(); - if (lsState.state == PythonLanguageServerState::CanBeInstalled + if (state.state == PythonLanguageServerState::CanBeInstalled && infoBar->canInfoBeAdded(installPylsInfoBarId)) { - auto message - = tr("Install and set up Python language server (PyLS) for %1 (%2). " - "The language server provides Python specific completion and annotation.") - .arg(pythonName(python), python.toUserOutput()); + auto message = tr("Install and set up Python language server (PyLS) for %1 (%2). " + "The language server provides Python specific completion and annotation.") + .arg(pythonName(python), python.toUserOutput()); Core::InfoBarEntry info(installPylsInfoBarId, message, Core::InfoBarEntry::GlobalSuppression::Enabled); @@ -395,7 +421,7 @@ void PyLSConfigureAssistant::openDocumentWithPython(const FilePath &python, [=]() { installPythonLanguageServer(python, document); }); infoBar->addInfo(info); m_infoBarEntries[python] << document; - } else if (lsState.state == PythonLanguageServerState::AlreadyInstalled + } else if (state.state == PythonLanguageServerState::AlreadyInstalled && infoBar->canInfoBeAdded(startPylsInfoBarId)) { auto message = tr("Found a Python language server for %1 (%2). " "Set it up for this document?") @@ -407,7 +433,7 @@ void PyLSConfigureAssistant::openDocumentWithPython(const FilePath &python, [=]() { setupPythonLanguageServer(python, document); }); infoBar->addInfo(info); m_infoBarEntries[python] << document; - } else if (lsState.state == PythonLanguageServerState::ConfiguredButDisabled + } else if (state.state == PythonLanguageServerState::ConfiguredButDisabled && infoBar->canInfoBeAdded(enablePylsInfoBarId)) { auto message = tr("Enable Python language server for %1 (%2)?") .arg(pythonName(python), python.toUserOutput()); diff --git a/src/plugins/python/pythonutils.h b/src/plugins/python/pythonutils.h index 20cb674ddb9..e7e7b225008 100644 --- a/src/plugins/python/pythonutils.h +++ b/src/plugins/python/pythonutils.h @@ -40,6 +40,8 @@ namespace TextEditor { class TextDocument; } namespace Python { namespace Internal { +class PythonLanguageServerState; + class PyLSConfigureAssistant : public QObject { Q_OBJECT @@ -56,6 +58,9 @@ public: private: explicit PyLSConfigureAssistant(QObject *parent); + void handlePyLSState(const Utils::FilePath &python, + const PythonLanguageServerState &state, + TextEditor::TextDocument *document); void resetEditorInfoBar(TextEditor::TextDocument *document); void installPythonLanguageServer(const Utils::FilePath &python, QPointer document);