Python: restructure settings

Change-Id: I32b3bed5581e06e981863b561b9b2f2bb125b82e
Reviewed-by: hjk <hjk@qt.io>
This commit is contained in:
David Schulz
2022-09-02 10:19:45 +02:00
parent 6f0f982356
commit 407082bcb2
2 changed files with 137 additions and 230 deletions

View File

@@ -118,13 +118,12 @@ signals:
};
class InterpreterOptionsWidget : public QWidget
class InterpreterOptionsWidget : public Core::IOptionsPageWidget
{
public:
InterpreterOptionsWidget(const QList<Interpreter> &interpreters,
const QString &defaultInterpreter);
InterpreterOptionsWidget();
void apply();
void apply() override;
private:
QTreeView m_view;
@@ -144,9 +143,9 @@ private:
void cleanUp();
};
InterpreterOptionsWidget::InterpreterOptionsWidget(const QList<Interpreter> &interpreters, const QString &defaultInterpreter)
InterpreterOptionsWidget::InterpreterOptionsWidget()
: m_detailsWidget(new InterpreterDetailsWidget())
, m_defaultId(defaultInterpreter)
, m_defaultId(PythonSettings::defaultInterpreter().id)
{
m_model.setDataAccessor([this](const Interpreter &interpreter, int column, int role) -> QVariant {
switch (role) {
@@ -174,7 +173,7 @@ InterpreterOptionsWidget::InterpreterOptionsWidget(const QList<Interpreter> &int
}
return {};
});
m_model.setAllData(interpreters);
m_model.setAllData(PythonSettings::interpreters());
m_view.setModel(&m_model);
m_view.setHeaderHidden(true);
@@ -278,65 +277,18 @@ void InterpreterOptionsWidget::deleteItem()
class InterpreterOptionsPage : public Core::IOptionsPage
{
Q_OBJECT
public:
InterpreterOptionsPage();
void setInterpreter(const QList<Interpreter> &interpreters) { m_interpreters = interpreters; }
void addInterpreter(const Interpreter &interpreter) { m_interpreters << interpreter; }
QList<Interpreter> interpreters() const { return m_interpreters; }
void setDefaultInterpreter(const QString &defaultId)
{ m_defaultInterpreterId = defaultId; }
Interpreter defaultInterpreter() const;
QWidget *widget() override;
void apply() override;
void finish() override;
private:
QPointer<InterpreterOptionsWidget> m_widget;
QList<Interpreter> m_interpreters;
QString m_defaultInterpreterId;
InterpreterOptionsPage()
{
setId(Constants::C_PYTHONOPTIONS_PAGE_ID);
setDisplayName(Tr::tr("Interpreters"));
setCategory(Constants::C_PYTHON_SETTINGS_CATEGORY);
setDisplayCategory(Tr::tr("Python"));
setCategoryIconPath(":/python/images/settingscategory_python.png");
setWidgetCreator([]() { return new InterpreterOptionsWidget(); });
}
};
InterpreterOptionsPage::InterpreterOptionsPage()
{
setId(Constants::C_PYTHONOPTIONS_PAGE_ID);
setDisplayName(Tr::tr("Interpreters"));
setCategory(Constants::C_PYTHON_SETTINGS_CATEGORY);
setDisplayCategory(Tr::tr("Python"));
setCategoryIconPath(":/python/images/settingscategory_python.png");
}
Interpreter InterpreterOptionsPage::defaultInterpreter() const
{
if (m_defaultInterpreterId.isEmpty())
return {};
return Utils::findOrDefault(m_interpreters, [this](const Interpreter &interpreter) {
return interpreter.id == m_defaultInterpreterId;
});
}
QWidget *InterpreterOptionsPage::widget()
{
if (!m_widget)
m_widget = new InterpreterOptionsWidget(m_interpreters, m_defaultInterpreterId);
return m_widget;
}
void InterpreterOptionsPage::apply()
{
if (m_widget)
m_widget->apply();
}
void InterpreterOptionsPage::finish()
{
delete m_widget;
m_widget = nullptr;
}
static bool alreadyRegistered(const QList<Interpreter> &pythons, const FilePath &pythonExecutable)
{
return Utils::anyOf(pythons, [pythonExecutable](const Interpreter &interpreter) {
@@ -370,7 +322,7 @@ static const QStringList &plugins()
return plugins;
}
class PyLSConfigureWidget : public QWidget
class PyLSConfigureWidget : public Core::IOptionsPageWidget
{
public:
PyLSConfigureWidget()
@@ -427,16 +379,13 @@ public:
QVBoxLayout *mainLayout = new QVBoxLayout;
mainLayout->addWidget(m_mainGroup);
setLayout(mainLayout);
}
void initialize(bool enabled, const QString &configuration)
{
m_editor->textDocument()->setPlainText(configuration);
m_mainGroup->setChecked(enabled);
m_editor->textDocument()->setPlainText(PythonSettings::pylsConfiguration());
m_mainGroup->setChecked(PythonSettings::pylsEnabled());
updateCheckboxes();
}
void apply()
void apply() override
{
PythonSettings::setPylsEnabled(m_mainGroup->isChecked());
PythonSettings::setPyLSConfiguration(m_editor->textDocument()->plainText());
@@ -501,56 +450,14 @@ private:
class PyLSOptionsPage : public Core::IOptionsPage
{
public:
PyLSOptionsPage();
bool enabled() const { return m_enabled; }
void setEnabled(bool enabled);
void setConfiguration(const QString &configuration) { m_configuration = configuration; }
QString configuration() const { return m_configuration; }
QWidget *widget() override;
void apply() override;
void finish() override;
private:
QPointer<PyLSConfigureWidget> m_widget;
bool m_enabled = true;
QString m_configuration;
};
PyLSOptionsPage::PyLSOptionsPage()
{
setId(Constants::C_PYLSCONFIGURATION_PAGE_ID);
setDisplayName(Tr::tr("Language Server Configuration"));
setCategory(Constants::C_PYTHON_SETTINGS_CATEGORY);
}
QWidget *PyLSOptionsPage::widget()
{
if (!m_widget) {
m_widget = new PyLSConfigureWidget();
m_widget->initialize(m_enabled, m_configuration);
PyLSOptionsPage()
{
setId(Constants::C_PYLSCONFIGURATION_PAGE_ID);
setDisplayName(Tr::tr("Language Server Configuration"));
setCategory(Constants::C_PYTHON_SETTINGS_CATEGORY);
setWidgetCreator([]() {return new PyLSConfigureWidget();});
}
return m_widget;
}
void PyLSOptionsPage::apply()
{
if (m_widget)
m_widget->apply();
}
void PyLSOptionsPage::finish()
{
delete m_widget;
m_widget = nullptr;
}
void PyLSOptionsPage::setEnabled(bool enabled)
{
m_enabled = enabled;
}
};
static PyLSOptionsPage &pylspOptionsPage()
{
@@ -585,14 +492,6 @@ constexpr char defaultKey[] = "DefaultInterpeter";
constexpr char pylsEnabledKey[] = "PylsEnabled";
constexpr char pylsConfigurationKey[] = "PylsConfiguration";
struct SavedSettings
{
QList<Interpreter> pythons;
QString defaultId;
QString pylsConfiguration;
bool pylsEnabled = true;
};
static QString defaultPylsConfiguration()
{
static QJsonObject configuration;
@@ -650,69 +549,6 @@ static void disableOutdatedPyls()
}
}
static SavedSettings fromSettings(QSettings *settings)
{
SavedSettings result;
settings->beginGroup(settingsGroupKey);
const QVariantList interpreters = settings->value(interpreterKey).toList();
QList<Interpreter> oldSettings;
for (const QVariant &interpreterVar : interpreters) {
auto interpreterList = interpreterVar.toList();
const Interpreter interpreter{interpreterList.value(0).toString(),
interpreterList.value(1).toString(),
FilePath::fromVariant(interpreterList.value(2)),
interpreterList.value(3, true).toBool()};
if (interpreterList.size() == 3)
oldSettings << interpreter;
else if (interpreterList.size() == 4)
result.pythons << interpreter;
}
for (const Interpreter &interpreter : qAsConst(oldSettings)) {
if (Utils::anyOf(result.pythons, Utils::equal(&Interpreter::id, interpreter.id)))
continue;
result.pythons << interpreter;
}
result.pythons = Utils::filtered(result.pythons, [](const Interpreter &interpreter){
return !interpreter.autoDetected || interpreter.command.isExecutableFile();
});
result.defaultId = settings->value(defaultKey).toString();
QVariant pylsEnabled = settings->value(pylsEnabledKey);
if (pylsEnabled.isNull())
disableOutdatedPyls();
else
result.pylsEnabled = pylsEnabled.toBool();
const QVariant pylsConfiguration = settings->value(pylsConfigurationKey);
if (!pylsConfiguration.isNull())
result.pylsConfiguration = pylsConfiguration.toString();
else
result.pylsConfiguration = defaultPylsConfiguration();
settings->endGroup();
return result;
}
static void toSettings(QSettings *settings, const SavedSettings &savedSettings)
{
settings->beginGroup(settingsGroupKey);
QVariantList interpretersVar;
for (const Interpreter &interpreter : savedSettings.pythons) {
QVariantList interpreterVar{interpreter.id,
interpreter.name,
interpreter.command.toVariant()};
interpretersVar.append(QVariant(interpreterVar)); // old settings
interpreterVar.append(interpreter.autoDetected);
interpretersVar.append(QVariant(interpreterVar)); // new settings
}
settings->setValue(interpreterKey, interpretersVar);
settings->setValue(defaultKey, savedSettings.defaultId);
settings->setValue(pylsConfigurationKey, savedSettings.pylsConfiguration);
settings->setValue(pylsEnabledKey, savedSettings.pylsEnabled);
settings->endGroup();
}
static void addPythonsFromRegistry(QList<Interpreter> &pythons)
{
QSettings pythonRegistry("HKEY_LOCAL_MACHINE\\SOFTWARE\\Python\\PythonCore",
@@ -784,7 +620,7 @@ static void addPythonsFromPath(QList<Interpreter> &pythons)
}
}
static QString idForPythonFromPath(QList<Interpreter> pythons)
static QString idForPythonFromPath(const QList<Interpreter> &pythons)
{
FilePath pythonFromPath = Environment::systemEnvironment().searchInPath("python3");
if (pythonFromPath.isEmpty())
@@ -799,72 +635,77 @@ static QString idForPythonFromPath(QList<Interpreter> pythons)
}
static PythonSettings *settingsInstance = nullptr;
PythonSettings::PythonSettings() = default;
PythonSettings::PythonSettings()
: QObject(PythonPlugin::instance())
{
initFromSettings(Core::ICore::settings());
if (HostOsInfo::isWindowsHost())
addPythonsFromRegistry(m_interpreters);
addPythonsFromPath(m_interpreters);
if (m_defaultInterpreterId.isEmpty())
m_defaultInterpreterId = idForPythonFromPath(m_interpreters);
writeToSettings(Core::ICore::settings());
interpreterOptionsPage();
pylspOptionsPage();
}
void PythonSettings::init()
{
QTC_ASSERT(!settingsInstance, return );
settingsInstance = new PythonSettings();
const SavedSettings &settings = fromSettings(Core::ICore::settings());
pylspOptionsPage().setConfiguration(settings.pylsConfiguration);
pylspOptionsPage().setEnabled(settings.pylsEnabled);
QList<Interpreter> pythons = settings.pythons;
if (HostOsInfo::isWindowsHost())
addPythonsFromRegistry(pythons);
addPythonsFromPath(pythons);
const QString &defaultId = !settings.defaultId.isEmpty() ? settings.defaultId
: idForPythonFromPath(pythons);
setInterpreter(pythons, defaultId);
}
void PythonSettings::setInterpreter(const QList<Interpreter> &interpreters, const QString &defaultId)
{
if (defaultId == interpreterOptionsPage().defaultInterpreter().id
&& interpreters == interpreterOptionsPage().interpreters()) {
if (defaultId == settingsInstance->m_defaultInterpreterId
&& interpreters == settingsInstance->m_interpreters) {
return;
}
interpreterOptionsPage().setInterpreter(interpreters);
interpreterOptionsPage().setDefaultInterpreter(defaultId);
settingsInstance->m_interpreters = interpreters;
settingsInstance->m_defaultInterpreterId = defaultId;
saveSettings();
}
void PythonSettings::setPyLSConfiguration(const QString &configuration)
{
if (configuration == pylspOptionsPage().configuration())
if (configuration == settingsInstance->m_pylsConfiguration)
return;
pylspOptionsPage().setConfiguration(configuration);
settingsInstance->m_pylsConfiguration = configuration;
saveSettings();
emit instance()->pylsConfigurationChanged(configuration);
}
void PythonSettings::setPylsEnabled(const bool &enabled)
{
if (enabled == pylspOptionsPage().enabled())
if (enabled == settingsInstance->m_pylsEnabled)
return;
pylspOptionsPage().setEnabled(enabled);
settingsInstance->m_pylsEnabled = enabled;
saveSettings();
emit instance()->pylsEnabledChanged(enabled);
}
bool PythonSettings::pylsEnabled()
{
return pylspOptionsPage().enabled();
return settingsInstance->m_pylsEnabled;
}
QString PythonSettings::pylsConfiguration()
{
return pylspOptionsPage().configuration();
return settingsInstance->m_pylsConfiguration;
}
void PythonSettings::addInterpreter(const Interpreter &interpreter, bool isDefault)
{
interpreterOptionsPage().addInterpreter(interpreter);
if (Utils::anyOf(settingsInstance->m_interpreters, Utils::equal(&Interpreter::id, interpreter.id)))
return;
settingsInstance->m_interpreters.append(interpreter);
if (isDefault)
interpreterOptionsPage().setDefaultInterpreter(interpreter.id);
settingsInstance->m_defaultInterpreterId = interpreter.id;
saveSettings();
}
@@ -911,31 +752,89 @@ QList<Interpreter> PythonSettings::detectPythonVenvs(const FilePath &path)
return result;
}
void PythonSettings::initFromSettings(QSettings *settings)
{
settings->beginGroup(settingsGroupKey);
const QVariantList interpreters = settings->value(interpreterKey).toList();
QList<Interpreter> oldSettings;
for (const QVariant &interpreterVar : interpreters) {
auto interpreterList = interpreterVar.toList();
const Interpreter interpreter{interpreterList.value(0).toString(),
interpreterList.value(1).toString(),
FilePath::fromVariant(interpreterList.value(2)),
interpreterList.value(3, true).toBool()};
if (interpreterList.size() == 3)
oldSettings << interpreter;
else if (interpreterList.size() == 4)
m_interpreters << interpreter;
}
for (const Interpreter &interpreter : qAsConst(oldSettings)) {
if (Utils::anyOf(m_interpreters, Utils::equal(&Interpreter::id, interpreter.id)))
continue;
m_interpreters << interpreter;
}
m_interpreters = Utils::filtered(m_interpreters, [](const Interpreter &interpreter){
return !interpreter.autoDetected || interpreter.command.isExecutableFile();
});
m_defaultInterpreterId = settings->value(defaultKey).toString();
QVariant pylsEnabled = settings->value(pylsEnabledKey);
if (pylsEnabled.isNull())
disableOutdatedPyls();
else
m_pylsEnabled = pylsEnabled.toBool();
const QVariant pylsConfiguration = settings->value(pylsConfigurationKey);
if (!pylsConfiguration.isNull())
m_pylsConfiguration = pylsConfiguration.toString();
else
m_pylsConfiguration = defaultPylsConfiguration();
settings->endGroup();
}
void PythonSettings::writeToSettings(QSettings *settings)
{
settings->beginGroup(settingsGroupKey);
QVariantList interpretersVar;
for (const Interpreter &interpreter : m_interpreters) {
QVariantList interpreterVar{interpreter.id,
interpreter.name,
interpreter.command.toVariant()};
interpretersVar.append(QVariant(interpreterVar)); // old settings
interpreterVar.append(interpreter.autoDetected);
interpretersVar.append(QVariant(interpreterVar)); // new settings
}
settings->setValue(interpreterKey, interpretersVar);
settings->setValue(defaultKey, m_defaultInterpreterId);
settings->setValue(pylsConfigurationKey, m_pylsConfiguration);
settings->setValue(pylsEnabledKey, m_pylsEnabled);
settings->endGroup();
}
void PythonSettings::saveSettings()
{
const QList<Interpreter> &interpreters = interpreterOptionsPage().interpreters();
const QString defaultId = interpreterOptionsPage().defaultInterpreter().id;
const QString pylsConfiguration = pylspOptionsPage().configuration();
const bool pylsEnabled = pylspOptionsPage().enabled();
toSettings(Core::ICore::settings(), {interpreters, defaultId, pylsConfiguration, pylsEnabled});
if (QTC_GUARD(settingsInstance))
emit settingsInstance->interpretersChanged(interpreters, defaultId);
QTC_ASSERT(settingsInstance, return);
settingsInstance->writeToSettings(Core::ICore::settings());
emit settingsInstance->interpretersChanged(settingsInstance->m_interpreters,
settingsInstance->m_defaultInterpreterId);
}
QList<Interpreter> PythonSettings::interpreters()
{
return interpreterOptionsPage().interpreters();
return settingsInstance->m_interpreters;
}
Interpreter PythonSettings::defaultInterpreter()
{
return interpreterOptionsPage().defaultInterpreter();
return interpreter(settingsInstance->m_defaultInterpreterId);
}
Interpreter PythonSettings::interpreter(const QString &interpreterId)
{
const QList<Interpreter> interpreters = PythonSettings::interpreters();
return Utils::findOrDefault(interpreters, Utils::equal(&Interpreter::id, interpreterId));
return Utils::findOrDefault(settingsInstance->m_interpreters,
Utils::equal(&Interpreter::id, interpreterId));
}
} // Python::Internal

View File

@@ -39,7 +39,15 @@ signals:
private:
PythonSettings();
void initFromSettings(QSettings *settings);
void writeToSettings(QSettings *settings);
QList<Interpreter> m_interpreters;
QString m_defaultInterpreterId;
bool m_pylsEnabled = true;
QString m_pylsConfiguration;
static void saveSettings();
};
} // PythonEditor::Internal
} // Python::Internal