diff options
| author | David Schulz <david.schulz@qt.io> | 2019-09-23 12:10:09 +0200 |
|---|---|---|
| committer | David Schulz <david.schulz@qt.io> | 2019-09-30 07:26:12 +0000 |
| commit | 90963249a40536783f7f1b82fc714b6b0ca70b01 (patch) | |
| tree | c99a9942c02d24b05f717c4a4a19319938acaff1 /src/plugins/python/pythoneditor.cpp | |
| parent | 3e2e0c6edc3bde3538106b27eb270dff776b826f (diff) | |
Python: Add info bar to install python language server
If the detected python for the current document does not have an
installed language server, check whether pip is installed, try to
install the language server and if that was successful set it up.
Change-Id: Ib6cf3bacdcf3489728990cace5417862b7c78be5
Reviewed-by: Christian Stenger <christian.stenger@qt.io>
Diffstat (limited to 'src/plugins/python/pythoneditor.cpp')
| -rw-r--r-- | src/plugins/python/pythoneditor.cpp | 107 |
1 files changed, 104 insertions, 3 deletions
diff --git a/src/plugins/python/pythoneditor.cpp b/src/plugins/python/pythoneditor.cpp index 434ec9e1cc1..8b0c3b84542 100644 --- a/src/plugins/python/pythoneditor.cpp +++ b/src/plugins/python/pythoneditor.cpp @@ -45,11 +45,13 @@ #include <texteditor/texteditoractionhandler.h> #include <texteditor/texteditorconstants.h> +#include <utils/executeondestruction.h> #include <utils/qtcassert.h> #include <utils/synchronousprocess.h> #include <QCoreApplication> #include <QRegularExpression> +#include <QTimer> using namespace ProjectExplorer; using namespace Utils; @@ -58,6 +60,7 @@ namespace Python { namespace Internal { static constexpr char startPylsInfoBarId[] = "PythonEditor::StartPyls"; +static constexpr char installPylsInfoBarId[] = "PythonEditor::InstallPyls"; struct PythonForProject { @@ -193,6 +196,90 @@ static LanguageClient::Client *registerLanguageServer(const PythonForProject &py return LanguageClient::LanguageClientManager::clientForSetting(settings).value(0); } +class PythonLSInstallHelper : public QObject +{ + Q_OBJECT +public: + PythonLSInstallHelper(const PythonForProject &python, QPointer<TextEditor::TextDocument> document) + : m_python(python) + , m_document(document) + {} + + void run() + { + auto killTimer = new QTimer(&m_process); + + connect(&m_process, + QOverload<int, QProcess::ExitStatus>::of(&QProcess::finished), + this, + &PythonLSInstallHelper::installFinished); + connect(&m_process, + &QProcess::readyReadStandardError, + this, + &PythonLSInstallHelper::errorAvailable); + connect(&m_process, + &QProcess::readyReadStandardOutput, + this, + &PythonLSInstallHelper::outputAvailable); + connect(killTimer, &QTimer::timeout, [this]() { + SynchronousProcess::stopProcess(m_process); + Core::MessageManager::write(tr("The Python language server installation timed out.")); + }); + + // on windows the pyls 0.28.3 crashes with pylint so just install the pyflakes linter + const QString &pylsVersion = HostOsInfo::isWindowsHost() + ? QString{"python-language-server[pyflakes]"} + : QString{"python-language-server[all]"}; + + m_process.start(m_python.path.toString(), + {"-m", "pip", "install", pylsVersion}); + + Core::MessageManager::write(tr("Running '%1 %2' to install python language server") + .arg(m_process.program(), m_process.arguments().join(' '))); + + killTimer->start(5 /*minutes*/ * 60 * 1000); + } + +private: + void installFinished(int exitCode, QProcess::ExitStatus exitStatus) + { + if (exitStatus == QProcess::NormalExit && exitCode == 0) { + if (LanguageClient::Client *client = registerLanguageServer(m_python)) + LanguageClient::LanguageClientManager::reOpenDocumentWithClient(m_document, client); + } else { + Core::MessageManager::write( + tr("Installing the Python language server failed with exit code %1").arg(exitCode)); + } + deleteLater(); + } + void outputAvailable() + { + const QString &stdOut = QString::fromLocal8Bit(m_process.readAllStandardOutput().trimmed()); + if (!stdOut.isEmpty()) + Core::MessageManager::write(stdOut); + } + + void errorAvailable() + { + const QString &stdErr = QString::fromLocal8Bit(m_process.readAllStandardError().trimmed()); + if (!stdErr.isEmpty()) + Core::MessageManager::write(stdErr); + } + + QProcess m_process; + const PythonForProject m_python; + QPointer<TextEditor::TextDocument> m_document; +}; + +static void installPythonLanguageServer(const PythonForProject &python, + QPointer<TextEditor::TextDocument> document) +{ + document->infoBar()->removeInfo(installPylsInfoBarId); + + auto install = new PythonLSInstallHelper(python, document); + install->run(); +} + static void setupPythonLanguageServer(const PythonForProject &python, QPointer<TextEditor::TextDocument> document) { @@ -206,13 +293,25 @@ static void updateEditorInfoBar(const PythonForProject &python, TextEditor::Text const PythonLanguageServerState &lsState = checkPythonLanguageServer(python.path, document); if (lsState.state == PythonLanguageServerState::CanNotBeInstalled - || lsState.state == PythonLanguageServerState::AlreadyConfigured - || lsState.state == PythonLanguageServerState::CanBeInstalled /* TODO */) { + || lsState.state == PythonLanguageServerState::AlreadyConfigured) { return; } Core::InfoBar *infoBar = document->infoBar(); - if (lsState.state == PythonLanguageServerState::AlreadyInstalled + if (lsState.state == PythonLanguageServerState::CanBeInstalled + && infoBar->canInfoBeAdded(installPylsInfoBarId)) { + auto message + = PythonEditorFactory::tr( + "Install and set up Python language server for %1 (%2). " + "The language server provides Python specific completions and annotations.") + .arg(python.name(), python.path.toUserOutput()); + Core::InfoBarEntry info(installPylsInfoBarId, + message, + Core::InfoBarEntry::GlobalSuppression::Enabled); + info.setCustomButtonInfo(TextEditor::BaseTextEditor::tr("Install"), + [=]() { installPythonLanguageServer(python, document); }); + infoBar->addInfo(info); + } else if (lsState.state == PythonLanguageServerState::AlreadyInstalled && infoBar->canInfoBeAdded(startPylsInfoBarId)) { auto message = PythonEditorFactory::tr("Found a Python language server for %1 (%2). " "Should this one be set up for this document?") @@ -264,3 +363,5 @@ PythonEditorFactory::PythonEditorFactory() } // namespace Internal } // namespace Python + +#include "pythoneditor.moc" |
