Python: detect language server for python asynchron

Change-Id: I775e4cc21dc443b9ec6af81fabef9cf2bfd4e7d2
Fixes: QTCREATORBUG-23599
Reviewed-by: Christian Stenger <christian.stenger@qt.io>
This commit is contained in:
David Schulz
2020-02-17 13:06:08 +01:00
parent dec8113377
commit 5a2de2609e
2 changed files with 52 additions and 21 deletions

View File

@@ -44,6 +44,7 @@
#include <texteditor/textdocument.h> #include <texteditor/textdocument.h>
#include <utils/qtcassert.h> #include <utils/qtcassert.h>
#include <utils/runextensions.h>
#include <utils/synchronousprocess.h> #include <utils/synchronousprocess.h>
#include <QDir> #include <QDir>
@@ -144,20 +145,19 @@ static PythonLanguageServerState checkPythonLanguageServer(const FilePath &pytho
using namespace LanguageClient; using namespace LanguageClient;
SynchronousProcess pythonProcess; SynchronousProcess pythonProcess;
const CommandLine pythonLShelpCommand(python, {"-m", "pyls", "-h"}); const CommandLine pythonLShelpCommand(python, {"-m", "pyls", "-h"});
SynchronousProcessResponse response = pythonProcess.runBlocking(pythonLShelpCommand); const FilePath &modulePath = getPylsModulePath(pythonLShelpCommand);
if (response.allOutput().contains("Python Language Server")) { for (const StdIOSettings *serverSetting : configuredPythonLanguageServer()) {
const FilePath &modulePath = getPylsModulePath(pythonLShelpCommand); if (modulePath == getPylsModulePath(serverSetting->command())) {
for (const StdIOSettings *serverSetting : configuredPythonLanguageServer()) { return {serverSetting->m_enabled ? PythonLanguageServerState::AlreadyConfigured
if (modulePath == getPylsModulePath(serverSetting->command())) { : PythonLanguageServerState::ConfiguredButDisabled,
return {serverSetting->m_enabled ? PythonLanguageServerState::AlreadyConfigured FilePath()};
: 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"}); const CommandLine pythonPipVersionCommand(python, {"-m", "pip", "-V"});
response = pythonProcess.runBlocking(pythonPipVersionCommand); response = pythonProcess.runBlocking(pythonPipVersionCommand);
if (response.allOutput().startsWith("pip ")) if (response.allOutput().startsWith("pip "))
@@ -368,11 +368,38 @@ void PyLSConfigureAssistant::documentOpened(Core::IDocument *document)
void PyLSConfigureAssistant::openDocumentWithPython(const FilePath &python, void PyLSConfigureAssistant::openDocumentWithPython(const FilePath &python,
TextEditor::TextDocument *document) TextEditor::TextDocument *document)
{ {
const PythonLanguageServerState &lsState = checkPythonLanguageServer(python); using CheckPylsWatcher = QFutureWatcher<PythonLanguageServerState>;
if (lsState.state == PythonLanguageServerState::CanNotBeInstalled) QPointer<CheckPylsWatcher> 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<TextEditor::TextDocument>(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; return;
if (lsState.state == PythonLanguageServerState::AlreadyConfigured) { if (state.state == PythonLanguageServerState::AlreadyConfigured) {
if (const StdIOSettings *setting = languageServerForPython(python)) { if (const StdIOSettings *setting = languageServerForPython(python)) {
if (Client *client = LanguageClientManager::clientForSetting(setting).value(0)) if (Client *client = LanguageClientManager::clientForSetting(setting).value(0))
LanguageClientManager::reOpenDocumentWithClient(document, client); LanguageClientManager::reOpenDocumentWithClient(document, client);
@@ -382,12 +409,11 @@ void PyLSConfigureAssistant::openDocumentWithPython(const FilePath &python,
resetEditorInfoBar(document); resetEditorInfoBar(document);
Core::InfoBar *infoBar = document->infoBar(); Core::InfoBar *infoBar = document->infoBar();
if (lsState.state == PythonLanguageServerState::CanBeInstalled if (state.state == PythonLanguageServerState::CanBeInstalled
&& infoBar->canInfoBeAdded(installPylsInfoBarId)) { && infoBar->canInfoBeAdded(installPylsInfoBarId)) {
auto message auto message = tr("Install and set up Python language server (PyLS) for %1 (%2). "
= tr("Install and set up Python language server (PyLS) for %1 (%2). " "The language server provides Python specific completion and annotation.")
"The language server provides Python specific completion and annotation.") .arg(pythonName(python), python.toUserOutput());
.arg(pythonName(python), python.toUserOutput());
Core::InfoBarEntry info(installPylsInfoBarId, Core::InfoBarEntry info(installPylsInfoBarId,
message, message,
Core::InfoBarEntry::GlobalSuppression::Enabled); Core::InfoBarEntry::GlobalSuppression::Enabled);
@@ -395,7 +421,7 @@ void PyLSConfigureAssistant::openDocumentWithPython(const FilePath &python,
[=]() { installPythonLanguageServer(python, document); }); [=]() { installPythonLanguageServer(python, document); });
infoBar->addInfo(info); infoBar->addInfo(info);
m_infoBarEntries[python] << document; m_infoBarEntries[python] << document;
} else if (lsState.state == PythonLanguageServerState::AlreadyInstalled } else if (state.state == PythonLanguageServerState::AlreadyInstalled
&& infoBar->canInfoBeAdded(startPylsInfoBarId)) { && infoBar->canInfoBeAdded(startPylsInfoBarId)) {
auto message = tr("Found a Python language server for %1 (%2). " auto message = tr("Found a Python language server for %1 (%2). "
"Set it up for this document?") "Set it up for this document?")
@@ -407,7 +433,7 @@ void PyLSConfigureAssistant::openDocumentWithPython(const FilePath &python,
[=]() { setupPythonLanguageServer(python, document); }); [=]() { setupPythonLanguageServer(python, document); });
infoBar->addInfo(info); infoBar->addInfo(info);
m_infoBarEntries[python] << document; m_infoBarEntries[python] << document;
} else if (lsState.state == PythonLanguageServerState::ConfiguredButDisabled } else if (state.state == PythonLanguageServerState::ConfiguredButDisabled
&& infoBar->canInfoBeAdded(enablePylsInfoBarId)) { && infoBar->canInfoBeAdded(enablePylsInfoBarId)) {
auto message = tr("Enable Python language server for %1 (%2)?") auto message = tr("Enable Python language server for %1 (%2)?")
.arg(pythonName(python), python.toUserOutput()); .arg(pythonName(python), python.toUserOutput());

View File

@@ -40,6 +40,8 @@ namespace TextEditor { class TextDocument; }
namespace Python { namespace Python {
namespace Internal { namespace Internal {
class PythonLanguageServerState;
class PyLSConfigureAssistant : public QObject class PyLSConfigureAssistant : public QObject
{ {
Q_OBJECT Q_OBJECT
@@ -56,6 +58,9 @@ public:
private: private:
explicit PyLSConfigureAssistant(QObject *parent); explicit PyLSConfigureAssistant(QObject *parent);
void handlePyLSState(const Utils::FilePath &python,
const PythonLanguageServerState &state,
TextEditor::TextDocument *document);
void resetEditorInfoBar(TextEditor::TextDocument *document); void resetEditorInfoBar(TextEditor::TextDocument *document);
void installPythonLanguageServer(const Utils::FilePath &python, void installPythonLanguageServer(const Utils::FilePath &python,
QPointer<TextEditor::TextDocument> document); QPointer<TextEditor::TextDocument> document);