forked from qt-creator/qt-creator
Python: add python specific language client settings
Change-Id: I1b9a194f32f3f13381954539229b02e03e3af058 Reviewed-by: <github-actions-qt-creator@cristianadam.eu> Reviewed-by: Christian Stenger <christian.stenger@qt.io>
This commit is contained in:
@@ -41,6 +41,8 @@ const char PYTHON_OPEN_REPL[] = "Python.OpenRepl";
|
|||||||
const char PYTHON_OPEN_REPL_IMPORT[] = "Python.OpenReplImport";
|
const char PYTHON_OPEN_REPL_IMPORT[] = "Python.OpenReplImport";
|
||||||
const char PYTHON_OPEN_REPL_IMPORT_TOPLEVEL[] = "Python.OpenReplImportToplevel";
|
const char PYTHON_OPEN_REPL_IMPORT_TOPLEVEL[] = "Python.OpenReplImportToplevel";
|
||||||
|
|
||||||
|
const char PYLS_SETTINGS_ID[] = "Python.PyLSSettingsID";
|
||||||
|
|
||||||
/*******************************************************************************
|
/*******************************************************************************
|
||||||
* MIME type
|
* MIME type
|
||||||
******************************************************************************/
|
******************************************************************************/
|
||||||
|
@@ -27,6 +27,7 @@
|
|||||||
|
|
||||||
#include "pythonconstants.h"
|
#include "pythonconstants.h"
|
||||||
#include "pythonplugin.h"
|
#include "pythonplugin.h"
|
||||||
|
#include "pythonsettings.h"
|
||||||
#include "pythonutils.h"
|
#include "pythonutils.h"
|
||||||
|
|
||||||
#include <coreplugin/editormanager/editormanager.h>
|
#include <coreplugin/editormanager/editormanager.h>
|
||||||
@@ -39,8 +40,11 @@
|
|||||||
#include <utils/infobar.h>
|
#include <utils/infobar.h>
|
||||||
#include <utils/qtcprocess.h>
|
#include <utils/qtcprocess.h>
|
||||||
#include <utils/runextensions.h>
|
#include <utils/runextensions.h>
|
||||||
|
#include <utils/variablechooser.h>
|
||||||
|
|
||||||
|
#include <QComboBox>
|
||||||
#include <QFutureWatcher>
|
#include <QFutureWatcher>
|
||||||
|
#include <QGridLayout>
|
||||||
#include <QRegularExpression>
|
#include <QRegularExpression>
|
||||||
#include <QTimer>
|
#include <QTimer>
|
||||||
|
|
||||||
@@ -163,6 +167,129 @@ static PythonLanguageServerState checkPythonLanguageServer(const FilePath &pytho
|
|||||||
return {PythonLanguageServerState::CanNotBeInstalled, FilePath()};
|
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))
|
||||||
|
{
|
||||||
|
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);
|
||||||
|
|
||||||
|
connect(PythonSettings::instance(),
|
||||||
|
&PythonSettings::interpretersChanged,
|
||||||
|
this,
|
||||||
|
&PyLSSettingsWidget::updateInterpreters);
|
||||||
|
}
|
||||||
|
|
||||||
|
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:
|
||||||
|
QLineEdit *m_name = nullptr;
|
||||||
|
QComboBox *m_interpreter = 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);
|
||||||
|
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);
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
Client *PyLSSettings::createClient(BaseClientInterface *interface) const
|
||||||
|
{
|
||||||
|
return new Client(interface);
|
||||||
|
}
|
||||||
|
|
||||||
PyLSConfigureAssistant *PyLSConfigureAssistant::instance()
|
PyLSConfigureAssistant *PyLSConfigureAssistant::instance()
|
||||||
{
|
{
|
||||||
static auto *instance = new PyLSConfigureAssistant(PythonPlugin::instance());
|
static auto *instance = new PyLSConfigureAssistant(PythonPlugin::instance());
|
||||||
@@ -180,12 +307,22 @@ const StdIOSettings *PyLSConfigureAssistant::languageServerForPython(const FileP
|
|||||||
|
|
||||||
static Client *registerLanguageServer(const FilePath &python)
|
static Client *registerLanguageServer(const FilePath &python)
|
||||||
{
|
{
|
||||||
auto *settings = new StdIOSettings();
|
Interpreter interpreter = Utils::findOrDefault(PythonSettings::interpreters(),
|
||||||
settings->m_executable = python;
|
Utils::equal(&Interpreter::command, python));
|
||||||
settings->m_arguments = "-m pylsp";
|
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);
|
||||||
|
}
|
||||||
settings->m_name = PyLSConfigureAssistant::tr("Python Language Server (%1)")
|
settings->m_name = PyLSConfigureAssistant::tr("Python Language Server (%1)")
|
||||||
.arg(pythonName(python));
|
.arg(pythonName(python));
|
||||||
settings->m_languageFilter.mimeTypes = QStringList(Constants::C_PY_MIMETYPE);
|
|
||||||
LanguageClientManager::registerClientSettings(settings);
|
LanguageClientManager::registerClientSettings(settings);
|
||||||
Client *client = LanguageClientManager::clientForSetting(settings).value(0);
|
Client *client = LanguageClientManager::clientForSetting(settings).value(0);
|
||||||
PyLSConfigureAssistant::updateEditorInfoBars(python, client);
|
PyLSConfigureAssistant::updateEditorInfoBars(python, client);
|
||||||
|
@@ -27,18 +27,41 @@
|
|||||||
|
|
||||||
#include <utils/fileutils.h>
|
#include <utils/fileutils.h>
|
||||||
|
|
||||||
|
#include <languageclient/client.h>
|
||||||
|
#include <languageclient/languageclientsettings.h>
|
||||||
|
|
||||||
namespace Core { class IDocument; }
|
namespace Core { class IDocument; }
|
||||||
namespace LanguageClient {
|
namespace LanguageClient { class Client; }
|
||||||
class Client;
|
|
||||||
class StdIOSettings;
|
|
||||||
}
|
|
||||||
namespace TextEditor { class TextDocument; }
|
namespace TextEditor { class TextDocument; }
|
||||||
|
|
||||||
namespace Python {
|
namespace Python {
|
||||||
namespace Internal {
|
namespace Internal {
|
||||||
|
|
||||||
|
class Interpreter;
|
||||||
struct PythonLanguageServerState;
|
struct PythonLanguageServerState;
|
||||||
|
|
||||||
|
class PyLSSettings : public LanguageClient::StdIOSettings
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
PyLSSettings();
|
||||||
|
|
||||||
|
QString interpreterId() const { return m_interpreterId; }
|
||||||
|
void setInterpreter(const QString &interpreterId);
|
||||||
|
|
||||||
|
bool isValid() const final;
|
||||||
|
QVariantMap toMap() const final;
|
||||||
|
void fromMap(const QVariantMap &map) final;
|
||||||
|
bool applyFromSettingsWidget(QWidget *widget) final;
|
||||||
|
QWidget *createSettingsWidget(QWidget *parent) const final;
|
||||||
|
LanguageClient::BaseSettings *copy() const final;
|
||||||
|
LanguageClient::Client *createClient(LanguageClient::BaseClientInterface *interface) const final;
|
||||||
|
|
||||||
|
private:
|
||||||
|
QString m_interpreterId;
|
||||||
|
|
||||||
|
PyLSSettings(const PyLSSettings &other) = default;
|
||||||
|
};
|
||||||
|
|
||||||
class PyLSConfigureAssistant : public QObject
|
class PyLSConfigureAssistant : public QObject
|
||||||
{
|
{
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
@@ -25,6 +25,7 @@
|
|||||||
|
|
||||||
#include "pythonplugin.h"
|
#include "pythonplugin.h"
|
||||||
|
|
||||||
|
#include "pythonconstants.h"
|
||||||
#include "pythoneditor.h"
|
#include "pythoneditor.h"
|
||||||
#include "pythonlanguageclient.h"
|
#include "pythonlanguageclient.h"
|
||||||
#include "pythonproject.h"
|
#include "pythonproject.h"
|
||||||
@@ -71,6 +72,10 @@ public:
|
|||||||
PythonPlugin::PythonPlugin()
|
PythonPlugin::PythonPlugin()
|
||||||
{
|
{
|
||||||
m_instance = this;
|
m_instance = this;
|
||||||
|
|
||||||
|
LanguageClient::LanguageClientSettings::registerClientType({Constants::PYLS_SETTINGS_ID,
|
||||||
|
tr("Python Language Server"),
|
||||||
|
[]() { return new PyLSSettings; }});
|
||||||
}
|
}
|
||||||
|
|
||||||
PythonPlugin::~PythonPlugin()
|
PythonPlugin::~PythonPlugin()
|
||||||
@@ -102,7 +107,7 @@ void PythonPlugin::extensionsInitialized()
|
|||||||
{
|
{
|
||||||
// Add MIME overlay icons (these icons displayed at Project dock panel)
|
// Add MIME overlay icons (these icons displayed at Project dock panel)
|
||||||
QString imageFile = Utils::creatorTheme()->imageFile(Utils::Theme::IconOverlayPro,
|
QString imageFile = Utils::creatorTheme()->imageFile(Utils::Theme::IconOverlayPro,
|
||||||
Constants::FILEOVERLAY_PY);
|
::Constants::FILEOVERLAY_PY);
|
||||||
Core::FileIconProvider::registerIconOverlayForSuffix(imageFile, "py");
|
Core::FileIconProvider::registerIconOverlayForSuffix(imageFile, "py");
|
||||||
|
|
||||||
TaskHub::addCategory(PythonErrorTaskCategory, "Python", true);
|
TaskHub::addCategory(PythonErrorTaskCategory, "Python", true);
|
||||||
|
Reference in New Issue
Block a user