2022-08-19 15:59:36 +02:00
|
|
|
// Copyright (C) 2021 The Qt Company Ltd.
|
2022-12-21 10:12:09 +01:00
|
|
|
// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only WITH Qt-GPL-exception-1.0
|
2021-12-13 14:19:30 +01:00
|
|
|
|
|
|
|
|
#include "pythonlanguageclient.h"
|
|
|
|
|
|
2022-03-15 08:33:23 +01:00
|
|
|
#include "pipsupport.h"
|
2023-11-01 15:05:03 +01:00
|
|
|
#include "pythonbuildconfiguration.h"
|
2022-05-25 15:24:09 +02:00
|
|
|
#include "pysideuicextracompiler.h"
|
2021-12-13 14:19:30 +01:00
|
|
|
#include "pythonconstants.h"
|
2022-03-14 10:09:55 +01:00
|
|
|
#include "pythonproject.h"
|
2021-12-13 15:30:21 +01:00
|
|
|
#include "pythonsettings.h"
|
2022-07-15 11:49:34 +02:00
|
|
|
#include "pythontr.h"
|
2021-12-13 14:19:30 +01:00
|
|
|
#include "pythonutils.h"
|
|
|
|
|
|
|
|
|
|
#include <coreplugin/editormanager/editormanager.h>
|
2022-01-12 14:00:05 +01:00
|
|
|
#include <coreplugin/icore.h>
|
2021-12-13 14:19:30 +01:00
|
|
|
#include <coreplugin/progressmanager/progressmanager.h>
|
2022-07-15 11:49:34 +02:00
|
|
|
|
2022-05-25 15:24:09 +02:00
|
|
|
#include <languageclient/languageclientinterface.h>
|
2021-12-13 14:19:30 +01:00
|
|
|
#include <languageclient/languageclientmanager.h>
|
2022-05-25 15:24:09 +02:00
|
|
|
#include <languageserverprotocol/textsynchronization.h>
|
2022-03-14 10:09:55 +01:00
|
|
|
#include <languageserverprotocol/workspace.h>
|
2022-07-15 11:49:34 +02:00
|
|
|
|
2023-11-01 15:05:03 +01:00
|
|
|
#include <projectexplorer/buildconfiguration.h>
|
|
|
|
|
#include <projectexplorer/buildsteplist.h>
|
2022-05-25 15:24:09 +02:00
|
|
|
#include <projectexplorer/extracompiler.h>
|
2023-02-14 15:47:22 +01:00
|
|
|
#include <projectexplorer/projectmanager.h>
|
2022-05-25 15:24:09 +02:00
|
|
|
#include <projectexplorer/target.h>
|
2022-07-15 11:49:34 +02:00
|
|
|
|
2021-12-13 14:19:30 +01:00
|
|
|
#include <texteditor/textdocument.h>
|
2022-01-12 14:00:05 +01:00
|
|
|
#include <texteditor/texteditor.h>
|
2022-07-15 11:49:34 +02:00
|
|
|
|
2023-05-03 15:05:47 +02:00
|
|
|
#include <utils/async.h>
|
2021-12-13 14:19:30 +01:00
|
|
|
#include <utils/infobar.h>
|
2024-02-27 16:08:45 +01:00
|
|
|
#include <utils/qtcprocess.h>
|
2021-12-13 14:19:30 +01:00
|
|
|
|
|
|
|
|
#include <QFutureWatcher>
|
2022-05-19 14:55:15 +02:00
|
|
|
#include <QJsonDocument>
|
2021-12-13 14:19:30 +01:00
|
|
|
#include <QTimer>
|
|
|
|
|
|
|
|
|
|
using namespace LanguageClient;
|
2022-05-25 15:24:09 +02:00
|
|
|
using namespace LanguageServerProtocol;
|
2022-04-13 12:26:54 +02:00
|
|
|
using namespace ProjectExplorer;
|
2021-12-13 14:19:30 +01:00
|
|
|
using namespace Utils;
|
|
|
|
|
|
2022-07-15 11:49:34 +02:00
|
|
|
namespace Python::Internal {
|
2021-12-13 14:19:30 +01:00
|
|
|
|
|
|
|
|
static constexpr char installPylsInfoBarId[] = "Python::InstallPyls";
|
|
|
|
|
|
2022-05-25 15:24:09 +02:00
|
|
|
class PythonLanguageServerState
|
2021-12-13 14:19:30 +01:00
|
|
|
{
|
2022-05-25 15:24:09 +02:00
|
|
|
public:
|
2021-12-13 14:19:30 +01:00
|
|
|
enum {
|
|
|
|
|
CanNotBeInstalled,
|
|
|
|
|
CanBeInstalled,
|
2022-06-09 13:41:41 +02:00
|
|
|
AlreadyInstalled
|
2021-12-13 14:19:30 +01:00
|
|
|
} state;
|
|
|
|
|
FilePath pylsModulePath;
|
|
|
|
|
};
|
|
|
|
|
|
2022-06-09 13:41:41 +02:00
|
|
|
static QHash<FilePath, PyLSClient*> &pythonClients()
|
|
|
|
|
{
|
|
|
|
|
static QHash<FilePath, PyLSClient*> clients;
|
|
|
|
|
return clients;
|
|
|
|
|
}
|
|
|
|
|
|
2023-11-27 14:15:29 +01:00
|
|
|
static FilePath pyLspPath(const FilePath &python)
|
2021-12-13 14:19:30 +01:00
|
|
|
{
|
2023-11-27 14:15:29 +01:00
|
|
|
const QString version = pythonVersion(python);
|
2023-12-13 08:06:41 +01:00
|
|
|
if (!python.needsDevice())
|
|
|
|
|
return Core::ICore::userResourcePath() / "pylsp" / version;
|
|
|
|
|
if (const expected_str<FilePath> tmpDir = python.tmpDir())
|
|
|
|
|
return *tmpDir / "qc-pylsp" / version;
|
|
|
|
|
return {};
|
2021-12-13 14:19:30 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static PythonLanguageServerState checkPythonLanguageServer(const FilePath &python)
|
|
|
|
|
{
|
|
|
|
|
using namespace LanguageClient;
|
2023-11-27 14:15:29 +01:00
|
|
|
auto lspPath = pyLspPath(python);
|
|
|
|
|
if (lspPath.isEmpty())
|
|
|
|
|
return {PythonLanguageServerState::CanNotBeInstalled, FilePath()};
|
|
|
|
|
|
|
|
|
|
if (lspPath.pathAppended("bin").pathAppended("pylsp").withExecutableSuffix().exists())
|
|
|
|
|
return {PythonLanguageServerState::AlreadyInstalled, lspPath};
|
2021-12-13 14:19:30 +01:00
|
|
|
|
2023-05-03 16:00:22 +02:00
|
|
|
Process pythonProcess;
|
2021-12-13 14:19:30 +01:00
|
|
|
pythonProcess.setCommand({python, {"-m", "pip", "-V"}});
|
2024-01-23 08:52:23 +01:00
|
|
|
using namespace std::chrono_literals;
|
|
|
|
|
pythonProcess.runBlocking(2s);
|
2021-12-13 14:19:30 +01:00
|
|
|
if (pythonProcess.allOutput().startsWith("pip "))
|
2023-11-27 14:15:29 +01:00
|
|
|
return {PythonLanguageServerState::CanBeInstalled, lspPath};
|
|
|
|
|
return {PythonLanguageServerState::CanNotBeInstalled, FilePath()};
|
2021-12-13 14:19:30 +01:00
|
|
|
}
|
|
|
|
|
|
2021-12-13 15:30:21 +01:00
|
|
|
|
2022-05-25 15:24:09 +02:00
|
|
|
class PyLSInterface : public StdIOClientInterface
|
2022-03-14 10:09:55 +01:00
|
|
|
{
|
|
|
|
|
public:
|
2022-05-25 15:24:09 +02:00
|
|
|
PyLSInterface()
|
|
|
|
|
: m_extraPythonPath("QtCreator-pyls-XXXXXX")
|
2022-06-15 13:10:26 +02:00
|
|
|
{ }
|
|
|
|
|
|
|
|
|
|
TemporaryDirectory m_extraPythonPath;
|
|
|
|
|
protected:
|
|
|
|
|
void startImpl() override
|
2022-03-14 10:09:55 +01:00
|
|
|
{
|
2023-12-13 08:06:41 +01:00
|
|
|
const FilePath python = m_cmd.executable();
|
|
|
|
|
Environment env = python.deviceEnvironment();
|
|
|
|
|
const FilePath lspPath = pyLspPath(python);
|
|
|
|
|
if (!lspPath.isEmpty() && lspPath.exists() && QTC_GUARD(lspPath.isSameDevice(python))) {
|
2024-01-26 10:33:29 +01:00
|
|
|
env.appendOrSet("PYTHONPATH", lspPath.path());
|
2023-12-13 08:06:41 +01:00
|
|
|
}
|
|
|
|
|
if (!python.needsDevice()) {
|
2022-06-15 13:10:26 +02:00
|
|
|
// todo check where to put this tempdir in remote setups
|
2024-01-26 10:33:29 +01:00
|
|
|
env.appendOrSet("PYTHONPATH", m_extraPythonPath.path().toString());
|
2022-06-15 13:10:26 +02:00
|
|
|
}
|
2023-12-13 08:06:41 +01:00
|
|
|
if (env.hasChanges())
|
|
|
|
|
setEnvironment(env);
|
2022-06-15 13:10:26 +02:00
|
|
|
StdIOClientInterface::startImpl();
|
2022-05-25 15:24:09 +02:00
|
|
|
}
|
|
|
|
|
};
|
|
|
|
|
|
2022-06-09 13:41:41 +02:00
|
|
|
PyLSClient *clientForPython(const FilePath &python)
|
2022-05-25 15:24:09 +02:00
|
|
|
{
|
2022-06-09 13:41:41 +02:00
|
|
|
if (auto client = pythonClients()[python])
|
|
|
|
|
return client;
|
2022-05-25 15:24:09 +02:00
|
|
|
auto interface = new PyLSInterface;
|
2022-06-09 13:41:41 +02:00
|
|
|
interface->setCommandLine(CommandLine(python, {"-m", "pylsp"}));
|
|
|
|
|
auto client = new PyLSClient(interface);
|
2022-07-15 11:49:34 +02:00
|
|
|
client->setName(Tr::tr("Python Language Server (%1)").arg(python.toUserOutput()));
|
2022-06-09 13:41:41 +02:00
|
|
|
client->setActivateDocumentAutomatically(true);
|
|
|
|
|
client->updateConfiguration();
|
|
|
|
|
LanguageFilter filter;
|
|
|
|
|
filter.mimeTypes = QStringList() << Constants::C_PY_MIMETYPE << Constants::C_PY3_MIMETYPE;
|
|
|
|
|
client->setSupportedLanguage(filter);
|
|
|
|
|
client->start();
|
|
|
|
|
pythonClients()[python] = client;
|
|
|
|
|
return client;
|
2022-05-25 15:24:09 +02:00
|
|
|
}
|
|
|
|
|
|
2022-06-15 12:44:44 +02:00
|
|
|
PyLSClient::PyLSClient(PyLSInterface *interface)
|
2022-05-25 15:24:09 +02:00
|
|
|
: Client(interface)
|
2022-06-15 12:44:44 +02:00
|
|
|
, m_extraCompilerOutputDir(interface->m_extraPythonPath.path())
|
2022-05-25 15:24:09 +02:00
|
|
|
{
|
2022-06-07 17:36:24 +02:00
|
|
|
connect(this, &Client::initialized, this, &PyLSClient::updateConfiguration);
|
|
|
|
|
connect(PythonSettings::instance(), &PythonSettings::pylsConfigurationChanged,
|
|
|
|
|
this, &PyLSClient::updateConfiguration);
|
2022-06-09 13:41:41 +02:00
|
|
|
connect(PythonSettings::instance(), &PythonSettings::pylsEnabledChanged,
|
|
|
|
|
this, [this](const bool enabled){
|
|
|
|
|
if (!enabled)
|
|
|
|
|
LanguageClientManager::shutdownClient(this);
|
|
|
|
|
});
|
|
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
PyLSClient::~PyLSClient()
|
|
|
|
|
{
|
|
|
|
|
pythonClients().remove(pythonClients().key(this));
|
2022-06-07 17:36:24 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void PyLSClient::updateConfiguration()
|
|
|
|
|
{
|
2022-09-02 09:26:12 +02:00
|
|
|
const auto doc = QJsonDocument::fromJson(PythonSettings::pylsConfiguration().toUtf8());
|
2022-06-07 17:36:24 +02:00
|
|
|
if (doc.isArray())
|
|
|
|
|
Client::updateConfiguration(doc.array());
|
|
|
|
|
else if (doc.isObject())
|
|
|
|
|
Client::updateConfiguration(doc.object());
|
2022-05-25 15:24:09 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void PyLSClient::openDocument(TextEditor::TextDocument *document)
|
|
|
|
|
{
|
|
|
|
|
using namespace LanguageServerProtocol;
|
|
|
|
|
if (reachable()) {
|
|
|
|
|
const FilePath documentPath = document->filePath();
|
|
|
|
|
if (PythonProject *project = pythonProjectForFile(documentPath)) {
|
|
|
|
|
if (Target *target = project->activeTarget()) {
|
2023-11-01 15:05:03 +01:00
|
|
|
if (BuildConfiguration *buildConfig = target->activeBuildConfiguration()) {
|
|
|
|
|
if (BuildStepList *buildSteps = buildConfig->buildSteps()) {
|
|
|
|
|
BuildStep *buildStep = buildSteps->firstStepWithId(PySideBuildStep::id());
|
|
|
|
|
if (auto *pythonBuildStep = qobject_cast<PySideBuildStep *>(buildStep))
|
|
|
|
|
updateExtraCompilers(project, pythonBuildStep->extraCompilers());
|
2023-08-24 17:14:01 +02:00
|
|
|
}
|
2023-11-01 15:05:03 +01:00
|
|
|
}
|
2022-05-25 15:24:09 +02:00
|
|
|
}
|
|
|
|
|
} else if (isSupportedDocument(document)) {
|
|
|
|
|
const FilePath workspacePath = documentPath.parentDir();
|
|
|
|
|
if (!m_extraWorkspaceDirs.contains(workspacePath)) {
|
|
|
|
|
WorkspaceFoldersChangeEvent event;
|
2022-12-15 07:23:55 +01:00
|
|
|
event.setAdded({WorkSpaceFolder(hostPathToServerUri(workspacePath),
|
2022-05-25 15:24:09 +02:00
|
|
|
workspacePath.fileName())});
|
|
|
|
|
DidChangeWorkspaceFoldersParams params;
|
|
|
|
|
params.setEvent(event);
|
|
|
|
|
DidChangeWorkspaceFoldersNotification change(params);
|
|
|
|
|
sendMessage(change);
|
|
|
|
|
m_extraWorkspaceDirs.append(workspacePath);
|
2022-03-14 10:09:55 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
2022-05-25 15:24:09 +02:00
|
|
|
Client::openDocument(document);
|
|
|
|
|
}
|
2022-03-14 10:09:55 +01:00
|
|
|
|
2022-05-25 15:24:09 +02:00
|
|
|
void PyLSClient::projectClosed(ProjectExplorer::Project *project)
|
|
|
|
|
{
|
|
|
|
|
for (ProjectExplorer::ExtraCompiler *compiler : m_extraCompilers.value(project))
|
|
|
|
|
closeExtraCompiler(compiler);
|
|
|
|
|
Client::projectClosed(project);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void PyLSClient::updateExtraCompilers(ProjectExplorer::Project *project,
|
|
|
|
|
const QList<PySideUicExtraCompiler *> &extraCompilers)
|
|
|
|
|
{
|
|
|
|
|
auto oldCompilers = m_extraCompilers.take(project);
|
|
|
|
|
for (PySideUicExtraCompiler *extraCompiler : extraCompilers) {
|
|
|
|
|
QTC_ASSERT(extraCompiler->targets().size() == 1 , continue);
|
|
|
|
|
int index = oldCompilers.indexOf(extraCompiler);
|
|
|
|
|
if (index < 0) {
|
|
|
|
|
m_extraCompilers[project] << extraCompiler;
|
|
|
|
|
connect(extraCompiler,
|
|
|
|
|
&ExtraCompiler::contentsChanged,
|
|
|
|
|
this,
|
|
|
|
|
[this, extraCompiler](const FilePath &file) {
|
|
|
|
|
updateExtraCompilerContents(extraCompiler, file);
|
|
|
|
|
});
|
|
|
|
|
if (extraCompiler->isDirty())
|
2023-01-04 11:25:23 +01:00
|
|
|
extraCompiler->compileFile();
|
2022-05-25 15:24:09 +02:00
|
|
|
} else {
|
|
|
|
|
m_extraCompilers[project] << oldCompilers.takeAt(index);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
for (ProjectExplorer::ExtraCompiler *compiler : oldCompilers)
|
|
|
|
|
closeExtraCompiler(compiler);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void PyLSClient::updateExtraCompilerContents(ExtraCompiler *compiler, const FilePath &file)
|
|
|
|
|
{
|
|
|
|
|
const FilePath target = m_extraCompilerOutputDir.pathAppended(file.fileName());
|
|
|
|
|
|
|
|
|
|
target.writeFileContents(compiler->content(file));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void PyLSClient::closeExtraCompiler(ProjectExplorer::ExtraCompiler *compiler)
|
|
|
|
|
{
|
2022-12-07 19:31:39 +01:00
|
|
|
const FilePath file = compiler->targets().constFirst();
|
2022-05-25 15:24:09 +02:00
|
|
|
m_extraCompilerOutputDir.pathAppended(file.fileName()).removeFile();
|
|
|
|
|
compiler->disconnect(this);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
PyLSClient *PyLSClient::clientForPython(const FilePath &python)
|
|
|
|
|
{
|
2022-06-09 13:41:41 +02:00
|
|
|
return pythonClients()[python];
|
2021-12-13 15:30:21 +01:00
|
|
|
}
|
|
|
|
|
|
2024-01-15 17:26:18 +01:00
|
|
|
class PyLSConfigureAssistant : public QObject
|
2021-12-13 14:19:30 +01:00
|
|
|
{
|
2024-01-15 17:26:18 +01:00
|
|
|
public:
|
|
|
|
|
PyLSConfigureAssistant();
|
|
|
|
|
|
|
|
|
|
void handlePyLSState(const Utils::FilePath &python,
|
|
|
|
|
const PythonLanguageServerState &state,
|
|
|
|
|
TextEditor::TextDocument *document);
|
|
|
|
|
void resetEditorInfoBar(TextEditor::TextDocument *document);
|
|
|
|
|
void installPythonLanguageServer(const Utils::FilePath &python,
|
|
|
|
|
QPointer<TextEditor::TextDocument> document,
|
|
|
|
|
const Utils::FilePath &pylsPath);
|
|
|
|
|
void openDocument(const FilePath &python, TextEditor::TextDocument *document);
|
|
|
|
|
|
|
|
|
|
QHash<Utils::FilePath, QList<TextEditor::TextDocument *>> m_infoBarEntries;
|
|
|
|
|
QHash<TextEditor::TextDocument *, QPointer<QFutureWatcher<PythonLanguageServerState>>>
|
|
|
|
|
m_runningChecks;
|
|
|
|
|
};
|
2021-12-13 14:19:30 +01:00
|
|
|
|
|
|
|
|
void PyLSConfigureAssistant::installPythonLanguageServer(const FilePath &python,
|
2023-11-27 14:15:29 +01:00
|
|
|
QPointer<TextEditor::TextDocument> document,
|
|
|
|
|
const FilePath &pylsPath)
|
2021-12-13 14:19:30 +01:00
|
|
|
{
|
|
|
|
|
document->infoBar()->removeInfo(installPylsInfoBarId);
|
|
|
|
|
|
|
|
|
|
// Hide all install info bar entries for this python, but keep them in the list
|
|
|
|
|
// so the language server will be setup properly after the installation is done.
|
|
|
|
|
for (TextEditor::TextDocument *additionalDocument : m_infoBarEntries[python])
|
|
|
|
|
additionalDocument->infoBar()->removeInfo(installPylsInfoBarId);
|
|
|
|
|
|
2022-03-15 08:33:23 +01:00
|
|
|
auto install = new PipInstallTask(python);
|
|
|
|
|
|
2024-02-05 20:50:49 +01:00
|
|
|
connect(install, &PipInstallTask::finished, this,
|
|
|
|
|
[this, python, document, install](const bool success) {
|
2023-10-24 11:19:51 +02:00
|
|
|
const QList<TextEditor::TextDocument *> additionalDocuments = m_infoBarEntries.take(python);
|
2022-03-15 08:33:23 +01:00
|
|
|
if (success) {
|
2023-10-24 11:19:51 +02:00
|
|
|
if (PyLSClient *client = clientForPython(python)) {
|
|
|
|
|
if (document)
|
2022-03-15 08:33:23 +01:00
|
|
|
LanguageClientManager::openDocumentWithClient(document, client);
|
2023-10-24 11:19:51 +02:00
|
|
|
for (TextEditor::TextDocument *additionalDocument : additionalDocuments)
|
|
|
|
|
LanguageClientManager::openDocumentWithClient(additionalDocument, client);
|
2022-03-15 08:33:23 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
install->deleteLater();
|
|
|
|
|
});
|
|
|
|
|
|
2023-11-27 14:15:29 +01:00
|
|
|
install->setTargetPath(pylsPath);
|
2023-01-24 11:28:28 +01:00
|
|
|
install->setPackages({PipPackage{"python-lsp-server[all]", "Python Language Server"}});
|
2021-12-13 14:19:30 +01:00
|
|
|
install->run();
|
|
|
|
|
}
|
|
|
|
|
|
2024-01-15 17:26:18 +01:00
|
|
|
void PyLSConfigureAssistant::openDocument(const FilePath &python, TextEditor::TextDocument *document)
|
2021-12-13 14:19:30 +01:00
|
|
|
{
|
2024-01-15 17:26:18 +01:00
|
|
|
resetEditorInfoBar(document);
|
2023-11-01 15:05:03 +01:00
|
|
|
if (!PythonSettings::pylsEnabled() || !python.exists())
|
2022-06-09 13:41:41 +02:00
|
|
|
return;
|
2021-12-13 14:19:30 +01:00
|
|
|
|
2022-06-09 13:41:41 +02:00
|
|
|
if (auto client = pythonClients().value(python)) {
|
|
|
|
|
LanguageClientManager::openDocumentWithClient(document, client);
|
|
|
|
|
return;
|
2021-12-13 14:19:30 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
using CheckPylsWatcher = QFutureWatcher<PythonLanguageServerState>;
|
|
|
|
|
QPointer<CheckPylsWatcher> watcher = new CheckPylsWatcher();
|
|
|
|
|
|
|
|
|
|
// cancel and delete watcher after a 10 second timeout
|
2024-01-15 17:26:18 +01:00
|
|
|
QTimer::singleShot(10000, this, [watcher]() {
|
2021-12-13 14:19:30 +01:00
|
|
|
if (watcher) {
|
|
|
|
|
watcher->cancel();
|
|
|
|
|
watcher->deleteLater();
|
|
|
|
|
}
|
|
|
|
|
});
|
|
|
|
|
|
2024-02-05 20:50:49 +01:00
|
|
|
connect(watcher, &CheckPylsWatcher::resultReadyAt, this,
|
|
|
|
|
[this, watcher, python, document = QPointer<TextEditor::TextDocument>(document)] {
|
2021-12-13 14:19:30 +01:00
|
|
|
if (!document || !watcher)
|
|
|
|
|
return;
|
2024-01-15 17:26:18 +01:00
|
|
|
handlePyLSState(python, watcher->result(), document);
|
2021-12-13 14:19:30 +01:00
|
|
|
});
|
2023-11-01 15:05:03 +01:00
|
|
|
connect(watcher, &CheckPylsWatcher::finished, watcher, &CheckPylsWatcher::deleteLater);
|
2024-01-15 17:26:18 +01:00
|
|
|
connect(watcher, &CheckPylsWatcher::finished, this, [this, document] {
|
|
|
|
|
m_runningChecks.remove(document);
|
2023-11-01 15:05:03 +01:00
|
|
|
});
|
2023-03-09 17:11:29 +01:00
|
|
|
watcher->setFuture(Utils::asyncRun(&checkPythonLanguageServer, python));
|
2024-01-15 17:26:18 +01:00
|
|
|
m_runningChecks[document] = watcher;
|
2021-12-13 14:19:30 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void PyLSConfigureAssistant::handlePyLSState(const FilePath &python,
|
|
|
|
|
const PythonLanguageServerState &state,
|
|
|
|
|
TextEditor::TextDocument *document)
|
|
|
|
|
{
|
|
|
|
|
if (state.state == PythonLanguageServerState::CanNotBeInstalled)
|
|
|
|
|
return;
|
|
|
|
|
|
|
|
|
|
Utils::InfoBar *infoBar = document->infoBar();
|
|
|
|
|
if (state.state == PythonLanguageServerState::CanBeInstalled
|
|
|
|
|
&& infoBar->canInfoBeAdded(installPylsInfoBarId)) {
|
2022-07-15 11:49:34 +02:00
|
|
|
auto message = Tr::tr("Install Python language server (PyLS) for %1 (%2). "
|
|
|
|
|
"The language server provides Python specific completion and annotation.")
|
2021-12-13 14:19:30 +01:00
|
|
|
.arg(pythonName(python), python.toUserOutput());
|
|
|
|
|
Utils::InfoBarEntry info(installPylsInfoBarId,
|
|
|
|
|
message,
|
|
|
|
|
Utils::InfoBarEntry::GlobalSuppression::Enabled);
|
2024-02-05 20:50:49 +01:00
|
|
|
info.addCustomButton(Tr::tr("Install"), [this, python, document, state] {
|
|
|
|
|
installPythonLanguageServer(python, document, state.pylsModulePath);
|
2023-11-27 14:15:29 +01:00
|
|
|
});
|
2021-12-13 14:19:30 +01:00
|
|
|
infoBar->addInfo(info);
|
|
|
|
|
m_infoBarEntries[python] << document;
|
2022-06-09 13:41:41 +02:00
|
|
|
} else if (state.state == PythonLanguageServerState::AlreadyInstalled) {
|
|
|
|
|
if (auto client = clientForPython(python))
|
|
|
|
|
LanguageClientManager::openDocumentWithClient(document, client);
|
2021-12-13 14:19:30 +01:00
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void PyLSConfigureAssistant::resetEditorInfoBar(TextEditor::TextDocument *document)
|
|
|
|
|
{
|
|
|
|
|
for (QList<TextEditor::TextDocument *> &documents : m_infoBarEntries)
|
|
|
|
|
documents.removeAll(document);
|
2022-06-09 13:41:41 +02:00
|
|
|
document->infoBar()->removeInfo(installPylsInfoBarId);
|
2023-11-01 15:05:03 +01:00
|
|
|
if (auto watcher = m_runningChecks.value(document))
|
|
|
|
|
watcher->cancel();
|
2021-12-13 14:19:30 +01:00
|
|
|
}
|
|
|
|
|
|
2024-01-15 17:26:18 +01:00
|
|
|
PyLSConfigureAssistant::PyLSConfigureAssistant()
|
2021-12-13 14:19:30 +01:00
|
|
|
{
|
|
|
|
|
Core::EditorManager::instance();
|
|
|
|
|
|
|
|
|
|
connect(Core::EditorManager::instance(),
|
|
|
|
|
&Core::EditorManager::documentClosed,
|
|
|
|
|
this,
|
|
|
|
|
[this](Core::IDocument *document) {
|
|
|
|
|
if (auto textDocument = qobject_cast<TextEditor::TextDocument *>(document))
|
|
|
|
|
resetEditorInfoBar(textDocument);
|
|
|
|
|
});
|
|
|
|
|
}
|
|
|
|
|
|
2024-01-15 17:26:18 +01:00
|
|
|
static PyLSConfigureAssistant &pyLSConfigureAssistant()
|
|
|
|
|
{
|
|
|
|
|
static PyLSConfigureAssistant thePyLSConfigureAssistant;
|
|
|
|
|
return thePyLSConfigureAssistant;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void openDocumentWithPython(const FilePath &python, TextEditor::TextDocument *document)
|
|
|
|
|
{
|
|
|
|
|
pyLSConfigureAssistant().openDocument(python, document);
|
|
|
|
|
}
|
|
|
|
|
|
2022-07-15 11:49:34 +02:00
|
|
|
} // Python::Internal
|