forked from qt-creator/qt-creator
Python: remove python specific language client settings
Change-Id: Ic993d525f29c1925f7e64dfc6f5e053234fb4904 Reviewed-by: Christian Stenger <christian.stenger@qt.io>
This commit is contained in:
@@ -69,9 +69,7 @@ using namespace Utils;
|
||||
namespace Python {
|
||||
namespace Internal {
|
||||
|
||||
static constexpr char startPylsInfoBarId[] = "Python::StartPyls";
|
||||
static constexpr char installPylsInfoBarId[] = "Python::InstallPyls";
|
||||
static constexpr char enablePylsInfoBarId[] = "Python::EnablePyls";
|
||||
|
||||
class PythonLanguageServerState
|
||||
{
|
||||
@@ -79,13 +77,17 @@ public:
|
||||
enum {
|
||||
CanNotBeInstalled,
|
||||
CanBeInstalled,
|
||||
AlreadyInstalled,
|
||||
AlreadyConfigured,
|
||||
ConfiguredButDisabled
|
||||
AlreadyInstalled
|
||||
} state;
|
||||
FilePath pylsModulePath;
|
||||
};
|
||||
|
||||
static QHash<FilePath, PyLSClient*> &pythonClients()
|
||||
{
|
||||
static QHash<FilePath, PyLSClient*> clients;
|
||||
return clients;
|
||||
}
|
||||
|
||||
FilePath getPylsModulePath(CommandLine pylsCommand)
|
||||
{
|
||||
static QMutex mutex; // protect the access to the cache
|
||||
@@ -125,29 +127,11 @@ FilePath getPylsModulePath(CommandLine pylsCommand)
|
||||
return {};
|
||||
}
|
||||
|
||||
QList<const StdIOSettings *> configuredPythonLanguageServer()
|
||||
{
|
||||
using namespace LanguageClient;
|
||||
QList<const StdIOSettings *> result;
|
||||
for (const BaseSettings *setting : LanguageClientManager::currentSettings()) {
|
||||
if (setting->m_languageFilter.isSupported("foo.py", Constants::C_PY_MIMETYPE))
|
||||
result << dynamic_cast<const StdIOSettings *>(setting);
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
static PythonLanguageServerState checkPythonLanguageServer(const FilePath &python)
|
||||
{
|
||||
using namespace LanguageClient;
|
||||
const CommandLine pythonLShelpCommand(python, {"-m", "pylsp", "-h"});
|
||||
const FilePath &modulePath = getPylsModulePath(pythonLShelpCommand);
|
||||
for (const StdIOSettings *serverSetting : configuredPythonLanguageServer()) {
|
||||
if (modulePath == getPylsModulePath(serverSetting->command())) {
|
||||
return {serverSetting->m_enabled ? PythonLanguageServerState::AlreadyConfigured
|
||||
: PythonLanguageServerState::ConfiguredButDisabled,
|
||||
FilePath()};
|
||||
}
|
||||
}
|
||||
|
||||
QtcProcess pythonProcess;
|
||||
pythonProcess.setCommand(pythonLShelpCommand);
|
||||
@@ -163,137 +147,6 @@ static PythonLanguageServerState checkPythonLanguageServer(const FilePath &pytho
|
||||
return {PythonLanguageServerState::CanNotBeInstalled, FilePath()};
|
||||
}
|
||||
|
||||
class PyLSSettingsWidget : public QWidget
|
||||
{
|
||||
Q_DECLARE_TR_FUNCTIONS(PyLSSettingsWidget)
|
||||
public:
|
||||
PyLSSettingsWidget(const PyLSSettings *settings, QWidget *parent)
|
||||
: QWidget(parent)
|
||||
, m_name(new QLineEdit(settings->m_name, this))
|
||||
, m_interpreter(new QComboBox(this))
|
||||
, m_configure(new QPushButton(tr("Configure..."), this))
|
||||
{
|
||||
int row = 0;
|
||||
auto *mainLayout = new QGridLayout;
|
||||
mainLayout->addWidget(new QLabel(tr("Name:")), row, 0);
|
||||
mainLayout->addWidget(m_name, row, 1);
|
||||
auto chooser = new VariableChooser(this);
|
||||
chooser->addSupportedWidget(m_name);
|
||||
|
||||
mainLayout->addWidget(new QLabel(tr("Python:")), ++row, 0);
|
||||
QString settingsId = settings->interpreterId();
|
||||
if (settingsId.isEmpty())
|
||||
settingsId = PythonSettings::defaultInterpreter().id;
|
||||
updateInterpreters(PythonSettings::interpreters(), settingsId);
|
||||
mainLayout->addWidget(m_interpreter, row, 1);
|
||||
setLayout(mainLayout);
|
||||
|
||||
mainLayout->addWidget(m_configure, ++row, 0);
|
||||
|
||||
connect(PythonSettings::instance(),
|
||||
&PythonSettings::interpretersChanged,
|
||||
this,
|
||||
&PyLSSettingsWidget::updateInterpreters);
|
||||
|
||||
connect(m_configure, &QPushButton::clicked, this, &PyLSSettingsWidget::switchToPylsConfigurePage);
|
||||
}
|
||||
|
||||
void updateInterpreters(const QList<Interpreter> &interpreters, const QString &defaultId)
|
||||
{
|
||||
QString currentId = interpreterId();
|
||||
if (currentId.isEmpty())
|
||||
currentId = defaultId;
|
||||
m_interpreter->clear();
|
||||
for (const Interpreter &interpreter : interpreters) {
|
||||
if (!interpreter.command.exists())
|
||||
continue;
|
||||
const QString name = QString(interpreter.name + " (%1)")
|
||||
.arg(interpreter.command.toUserOutput());
|
||||
m_interpreter->addItem(name, interpreter.id);
|
||||
if (!currentId.isEmpty() && currentId == interpreter.id)
|
||||
m_interpreter->setCurrentIndex(m_interpreter->count() - 1);
|
||||
}
|
||||
}
|
||||
|
||||
QString name() const { return m_name->text(); }
|
||||
QString interpreterId() const { return m_interpreter->currentData().toString(); }
|
||||
|
||||
private:
|
||||
void switchToPylsConfigurePage()
|
||||
{
|
||||
Core::ICore::showOptionsDialog(Constants::C_PYLSCONFIGURATION_PAGE_ID);
|
||||
}
|
||||
|
||||
QLineEdit *m_name = nullptr;
|
||||
QComboBox *m_interpreter = nullptr;
|
||||
QPushButton *m_configure = nullptr;
|
||||
};
|
||||
|
||||
PyLSSettings::PyLSSettings()
|
||||
{
|
||||
m_settingsTypeId = Constants::PYLS_SETTINGS_ID;
|
||||
m_name = "Python Language Server";
|
||||
m_startBehavior = RequiresFile;
|
||||
m_languageFilter.mimeTypes = QStringList()
|
||||
<< Constants::C_PY_MIMETYPE << Constants::C_PY3_MIMETYPE;
|
||||
m_arguments = "-m pylsp";
|
||||
}
|
||||
|
||||
bool PyLSSettings::isValid() const
|
||||
{
|
||||
return !m_interpreterId.isEmpty() && StdIOSettings::isValid();
|
||||
}
|
||||
|
||||
static const char interpreterKey[] = "interpreter";
|
||||
|
||||
QVariantMap PyLSSettings::toMap() const
|
||||
{
|
||||
QVariantMap map = StdIOSettings::toMap();
|
||||
map.insert(interpreterKey, m_interpreterId);
|
||||
return map;
|
||||
}
|
||||
|
||||
void PyLSSettings::fromMap(const QVariantMap &map)
|
||||
{
|
||||
StdIOSettings::fromMap(map);
|
||||
m_languageFilter.mimeTypes = QStringList()
|
||||
<< Constants::C_PY_MIMETYPE << Constants::C_PY3_MIMETYPE;
|
||||
setInterpreter(map[interpreterKey].toString());
|
||||
}
|
||||
|
||||
bool PyLSSettings::applyFromSettingsWidget(QWidget *widget)
|
||||
{
|
||||
bool changed = false;
|
||||
auto pylswidget = static_cast<PyLSSettingsWidget *>(widget);
|
||||
|
||||
changed |= m_name != pylswidget->name();
|
||||
m_name = pylswidget->name();
|
||||
|
||||
changed |= m_interpreterId != pylswidget->interpreterId();
|
||||
setInterpreter(pylswidget->interpreterId());
|
||||
|
||||
return changed;
|
||||
}
|
||||
|
||||
QWidget *PyLSSettings::createSettingsWidget(QWidget *parent) const
|
||||
{
|
||||
return new PyLSSettingsWidget(this, parent);
|
||||
}
|
||||
|
||||
BaseSettings *PyLSSettings::copy() const
|
||||
{
|
||||
return new PyLSSettings(*this);
|
||||
}
|
||||
|
||||
void PyLSSettings::setInterpreter(const QString &interpreterId)
|
||||
{
|
||||
m_interpreterId = interpreterId;
|
||||
if (m_interpreterId.isEmpty())
|
||||
return;
|
||||
Interpreter interpreter = Utils::findOrDefault(PythonSettings::interpreters(),
|
||||
Utils::equal(&Interpreter::id, interpreterId));
|
||||
m_executable = interpreter.command;
|
||||
}
|
||||
|
||||
class PyLSInterface : public StdIOClientInterface
|
||||
{
|
||||
@@ -310,13 +163,22 @@ public:
|
||||
TemporaryDirectory m_extraPythonPath;
|
||||
};
|
||||
|
||||
BaseClientInterface *PyLSSettings::createInterface(ProjectExplorer::Project *project) const
|
||||
PyLSClient *clientForPython(const FilePath &python)
|
||||
{
|
||||
if (auto client = pythonClients()[python])
|
||||
return client;
|
||||
auto interface = new PyLSInterface;
|
||||
interface->setCommandLine(command());
|
||||
if (project)
|
||||
interface->setWorkingDirectory(project->projectDirectory());
|
||||
return interface;
|
||||
interface->setCommandLine(CommandLine(python, {"-m", "pylsp"}));
|
||||
auto client = new PyLSClient(interface);
|
||||
client->setName(PyLSClient::tr("Python Language Server (%1)").arg(python.toUserOutput()));
|
||||
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;
|
||||
}
|
||||
|
||||
PyLSClient::PyLSClient(BaseClientInterface *interface)
|
||||
@@ -326,6 +188,17 @@ PyLSClient::PyLSClient(BaseClientInterface *interface)
|
||||
connect(this, &Client::initialized, this, &PyLSClient::updateConfiguration);
|
||||
connect(PythonSettings::instance(), &PythonSettings::pylsConfigurationChanged,
|
||||
this, &PyLSClient::updateConfiguration);
|
||||
connect(PythonSettings::instance(), &PythonSettings::pylsEnabledChanged,
|
||||
this, [this](const bool enabled){
|
||||
if (!enabled)
|
||||
LanguageClientManager::shutdownClient(this);
|
||||
});
|
||||
|
||||
}
|
||||
|
||||
PyLSClient::~PyLSClient()
|
||||
{
|
||||
pythonClients().remove(pythonClients().key(this));
|
||||
}
|
||||
|
||||
void PyLSClient::updateConfiguration()
|
||||
@@ -413,16 +286,7 @@ void PyLSClient::closeExtraCompiler(ProjectExplorer::ExtraCompiler *compiler)
|
||||
|
||||
PyLSClient *PyLSClient::clientForPython(const FilePath &python)
|
||||
{
|
||||
if (auto setting = PyLSConfigureAssistant::languageServerForPython(python)) {
|
||||
if (auto client = LanguageClientManager::clientsForSetting(setting).value(0))
|
||||
return qobject_cast<PyLSClient *>(client);
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
Client *PyLSSettings::createClient(BaseClientInterface *interface) const
|
||||
{
|
||||
return new PyLSClient(interface);
|
||||
return pythonClients()[python];
|
||||
}
|
||||
|
||||
PyLSConfigureAssistant *PyLSConfigureAssistant::instance()
|
||||
@@ -431,40 +295,6 @@ PyLSConfigureAssistant *PyLSConfigureAssistant::instance()
|
||||
return instance;
|
||||
}
|
||||
|
||||
const StdIOSettings *PyLSConfigureAssistant::languageServerForPython(const FilePath &python)
|
||||
{
|
||||
const FilePath pythonModulePath = getPylsModulePath({python, {"-m", "pylsp"}});
|
||||
return findOrDefault(configuredPythonLanguageServer(),
|
||||
[pythonModulePath](const StdIOSettings *setting) {
|
||||
return getPylsModulePath(setting->command()) == pythonModulePath;
|
||||
});
|
||||
}
|
||||
|
||||
static Client *registerLanguageServer(const FilePath &python)
|
||||
{
|
||||
Interpreter interpreter = Utils::findOrDefault(PythonSettings::interpreters(),
|
||||
Utils::equal(&Interpreter::command, python));
|
||||
StdIOSettings *settings = nullptr;
|
||||
if (!interpreter.id.isEmpty()) {
|
||||
auto *pylsSettings = new PyLSSettings();
|
||||
pylsSettings->setInterpreter(interpreter.id);
|
||||
settings = pylsSettings;
|
||||
} else {
|
||||
// cannot find a matching interpreter in settings for the python path add a generic server
|
||||
auto *settings = new StdIOSettings();
|
||||
settings->m_executable = python;
|
||||
settings->m_arguments = "-m pylsp";
|
||||
settings->m_languageFilter.mimeTypes = QStringList() << Constants::C_PY_MIMETYPE
|
||||
<< Constants::C_PY3_MIMETYPE;
|
||||
}
|
||||
settings->m_name = PyLSConfigureAssistant::tr("Python Language Server (%1)")
|
||||
.arg(pythonName(python));
|
||||
LanguageClientManager::registerClientSettings(settings);
|
||||
Client *client = LanguageClientManager::clientsForSetting(settings).value(0);
|
||||
PyLSConfigureAssistant::updateEditorInfoBars(python, client);
|
||||
return client;
|
||||
}
|
||||
|
||||
void PyLSConfigureAssistant::installPythonLanguageServer(const FilePath &python,
|
||||
QPointer<TextEditor::TextDocument> document)
|
||||
{
|
||||
@@ -479,8 +309,8 @@ void PyLSConfigureAssistant::installPythonLanguageServer(const FilePath &python,
|
||||
|
||||
connect(install, &PipInstallTask::finished, this, [=](const bool success) {
|
||||
if (success) {
|
||||
if (Client *client = registerLanguageServer(python)) {
|
||||
if (document)
|
||||
if (document) {
|
||||
if (PyLSClient *client = clientForPython(python))
|
||||
LanguageClientManager::openDocumentWithClient(document, client);
|
||||
}
|
||||
}
|
||||
@@ -491,34 +321,18 @@ void PyLSConfigureAssistant::installPythonLanguageServer(const FilePath &python,
|
||||
install->run();
|
||||
}
|
||||
|
||||
static void setupPythonLanguageServer(const FilePath &python,
|
||||
QPointer<TextEditor::TextDocument> document)
|
||||
{
|
||||
document->infoBar()->removeInfo(startPylsInfoBarId);
|
||||
if (Client *client = registerLanguageServer(python))
|
||||
LanguageClientManager::openDocumentWithClient(document, client);
|
||||
}
|
||||
|
||||
static void enablePythonLanguageServer(const FilePath &python,
|
||||
QPointer<TextEditor::TextDocument> document)
|
||||
{
|
||||
document->infoBar()->removeInfo(enablePylsInfoBarId);
|
||||
if (const StdIOSettings *setting = PyLSConfigureAssistant::languageServerForPython(python)) {
|
||||
LanguageClientManager::enableClientSettings(setting->m_id);
|
||||
if (const StdIOSettings *setting = PyLSConfigureAssistant::languageServerForPython(python)) {
|
||||
if (Client *client = LanguageClientManager::clientsForSetting(setting).value(0)) {
|
||||
LanguageClientManager::openDocumentWithClient(document, client);
|
||||
PyLSConfigureAssistant::updateEditorInfoBars(python, client);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void PyLSConfigureAssistant::openDocumentWithPython(const FilePath &python,
|
||||
TextEditor::TextDocument *document)
|
||||
{
|
||||
using CheckPylsWatcher = QFutureWatcher<PythonLanguageServerState>;
|
||||
if (!PythonSettings::pylsEnabled())
|
||||
return;
|
||||
|
||||
if (auto client = pythonClients().value(python)) {
|
||||
LanguageClientManager::openDocumentWithClient(document, client);
|
||||
return;
|
||||
}
|
||||
|
||||
using CheckPylsWatcher = QFutureWatcher<PythonLanguageServerState>;
|
||||
QPointer<CheckPylsWatcher> watcher = new CheckPylsWatcher();
|
||||
|
||||
// cancel and delete watcher after a 10 second timeout
|
||||
@@ -547,19 +361,12 @@ void PyLSConfigureAssistant::handlePyLSState(const FilePath &python,
|
||||
{
|
||||
if (state.state == PythonLanguageServerState::CanNotBeInstalled)
|
||||
return;
|
||||
if (state.state == PythonLanguageServerState::AlreadyConfigured) {
|
||||
if (const StdIOSettings *setting = languageServerForPython(python)) {
|
||||
if (Client *client = LanguageClientManager::clientsForSetting(setting).value(0))
|
||||
LanguageClientManager::openDocumentWithClient(document, client);
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
resetEditorInfoBar(document);
|
||||
Utils::InfoBar *infoBar = document->infoBar();
|
||||
if (state.state == PythonLanguageServerState::CanBeInstalled
|
||||
&& infoBar->canInfoBeAdded(installPylsInfoBarId)) {
|
||||
auto message = tr("Install and set up Python language server (PyLS) for %1 (%2). "
|
||||
auto message = tr("Install Python language server (PyLS) for %1 (%2). "
|
||||
"The language server provides Python specific completion and annotation.")
|
||||
.arg(pythonName(python), python.toUserOutput());
|
||||
Utils::InfoBarEntry info(installPylsInfoBarId,
|
||||
@@ -569,27 +376,9 @@ void PyLSConfigureAssistant::handlePyLSState(const FilePath &python,
|
||||
[=]() { installPythonLanguageServer(python, document); });
|
||||
infoBar->addInfo(info);
|
||||
m_infoBarEntries[python] << document;
|
||||
} 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?")
|
||||
.arg(pythonName(python), python.toUserOutput());
|
||||
Utils::InfoBarEntry info(startPylsInfoBarId,
|
||||
message,
|
||||
Utils::InfoBarEntry::GlobalSuppression::Enabled);
|
||||
info.addCustomButton(tr("Set Up"), [=]() { setupPythonLanguageServer(python, document); });
|
||||
infoBar->addInfo(info);
|
||||
m_infoBarEntries[python] << document;
|
||||
} else if (state.state == PythonLanguageServerState::ConfiguredButDisabled
|
||||
&& infoBar->canInfoBeAdded(enablePylsInfoBarId)) {
|
||||
auto message = tr("Enable Python language server for %1 (%2)?")
|
||||
.arg(pythonName(python), python.toUserOutput());
|
||||
Utils::InfoBarEntry info(enablePylsInfoBarId,
|
||||
message,
|
||||
Utils::InfoBarEntry::GlobalSuppression::Enabled);
|
||||
info.addCustomButton(tr("Enable"), [=]() { enablePythonLanguageServer(python, document); });
|
||||
infoBar->addInfo(info);
|
||||
m_infoBarEntries[python] << document;
|
||||
} else if (state.state == PythonLanguageServerState::AlreadyInstalled) {
|
||||
if (auto client = clientForPython(python))
|
||||
LanguageClientManager::openDocumentWithClient(document, client);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -606,10 +395,7 @@ void PyLSConfigureAssistant::resetEditorInfoBar(TextEditor::TextDocument *docume
|
||||
{
|
||||
for (QList<TextEditor::TextDocument *> &documents : m_infoBarEntries)
|
||||
documents.removeAll(document);
|
||||
Utils::InfoBar *infoBar = document->infoBar();
|
||||
infoBar->removeInfo(installPylsInfoBarId);
|
||||
infoBar->removeInfo(startPylsInfoBarId);
|
||||
infoBar->removeInfo(enablePylsInfoBarId);
|
||||
document->infoBar()->removeInfo(installPylsInfoBarId);
|
||||
}
|
||||
|
||||
PyLSConfigureAssistant::PyLSConfigureAssistant(QObject *parent)
|
||||
|
||||
Reference in New Issue
Block a user