Merge remote-tracking branch 'origin/4.11'

Conflicts:
	share/qtcreator/qml/qmlpuppet/qml2puppet/instances/quick3dnodeinstance.cpp

Change-Id: I8ea57eba526ab830608fd928c28771c5441749f8
This commit is contained in:
Eike Ziller
2019-11-01 15:31:19 +01:00
170 changed files with 2592 additions and 526 deletions

View File

@@ -257,8 +257,10 @@ PythonRunConfiguration::PythonRunConfiguration(Target *target, Core::Id id)
connect(PythonSettings::instance(), &PythonSettings::interpretersChanged,
interpreterAspect, &InterpreterAspect::updateInterpreters);
interpreterAspect->updateInterpreters(PythonSettings::interpreters());
interpreterAspect->setDefaultInterpreter(PythonSettings::defaultInterpreter());
QList<Interpreter> interpreters = PythonSettings::detectPythonVenvs(project()->projectDirectory());
aspect<InterpreterAspect>()->updateInterpreters(PythonSettings::interpreters());
aspect<InterpreterAspect>()->setDefaultInterpreter(
interpreters.isEmpty() ? PythonSettings::defaultInterpreter() : interpreters.first());
auto scriptAspect = addAspect<MainScriptAspect>();
scriptAspect->setSettingsKey("PythonEditor.RunConfiguation.Script");

View File

@@ -211,6 +211,7 @@ 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; }
@@ -278,6 +279,7 @@ Interpreter::Interpreter(const FilePath &python, const QString &defaultName, boo
{
SynchronousProcess pythonProcess;
pythonProcess.setProcessChannelMode(QProcess::MergedChannels);
pythonProcess.setTimeoutS(1);
SynchronousProcessResponse response = pythonProcess.runBlocking(
CommandLine(python, {"--version"}));
if (response.result == SynchronousProcessResponse::Finished)
@@ -465,11 +467,21 @@ void PythonSettings::init()
void PythonSettings::setInterpreter(const QList<Interpreter> &interpreters, const QString &defaultId)
{
if (defaultId == interpreterOptionsPage().defaultInterpreter().id
&& interpreters == interpreterOptionsPage().interpreters()) {
return;
}
interpreterOptionsPage().setInterpreter(interpreters);
interpreterOptionsPage().setDefaultInterpreter(defaultId);
toSettings(Core::ICore::settings(), {interpreters, defaultId});
if (QTC_GUARD(settingsInstance))
emit settingsInstance->interpretersChanged(interpreters, defaultId);
saveSettings();
}
void PythonSettings::addInterpreter(const Interpreter &interpreter, bool isDefault)
{
interpreterOptionsPage().addInterpreter(interpreter);
if (isDefault)
interpreterOptionsPage().setDefaultInterpreter(interpreter.id);
saveSettings();
}
PythonSettings *PythonSettings::instance()
@@ -478,6 +490,52 @@ PythonSettings *PythonSettings::instance()
return settingsInstance;
}
QList<Interpreter> PythonSettings::detectPythonVenvs(const FilePath &path)
{
QList<Interpreter> result;
QDir dir = path.toFileInfo().isDir() ? QDir(path.toString()) : path.toFileInfo().dir();
if (dir.exists()) {
const QString venvPython = HostOsInfo::withExecutableSuffix("python");
const QString activatePath = HostOsInfo::isWindowsHost() ? QString{"Scripts"}
: QString{"bin"};
do {
for (const QString &directory : dir.entryList(QDir::Dirs | QDir::NoDotAndDotDot)) {
if (dir.cd(directory)) {
if (dir.cd(activatePath)) {
if (dir.exists("activate") && dir.exists(venvPython)) {
FilePath python = FilePath::fromString(dir.absoluteFilePath(venvPython));
dir.cdUp();
const QString defaultName = QString("Python (%1 Virtual Environment)")
.arg(dir.dirName());
Interpreter interpreter
= Utils::findOrDefault(PythonSettings::interpreters(),
Utils::equal(&Interpreter::command, python));
if (interpreter.command.isEmpty()) {
interpreter = Interpreter(python, defaultName);
PythonSettings::addInterpreter(interpreter);
}
result << interpreter;
} else {
dir.cdUp();
}
}
dir.cdUp();
}
}
} while (dir.cdUp());
}
return result;
}
void PythonSettings::saveSettings()
{
const QList<Interpreter> &interpreters = interpreterOptionsPage().interpreters();
const QString &defaultId = interpreterOptionsPage().defaultInterpreter().id;
toSettings(Core::ICore::settings(), {interpreters, defaultId});
if (QTC_GUARD(settingsInstance))
emit settingsInstance->interpretersChanged(interpreters, defaultId);
}
QList<Interpreter> PythonSettings::interpreters()
{
return interpreterOptionsPage().interpreters();

View File

@@ -26,6 +26,7 @@
#pragma once
#include <utils/fileutils.h>
#include <utils/optional.h>
#include <QUuid>
@@ -43,6 +44,11 @@ public:
const QString &name,
const Utils::FilePath &command);
inline bool operator==(const Interpreter &other) const
{
return id == other.id && name == other.name && command == other.command;
}
QString id = QUuid::createUuid().toString();
QString name;
Utils::FilePath command;
@@ -57,13 +63,18 @@ public:
static QList<Interpreter> interpreters();
static Interpreter defaultInterpreter();
static void setInterpreter(const QList<Interpreter> &interpreters, const QString &defaultId);
static void addInterpreter(const Interpreter &interpreter, bool isDefault = false);
static PythonSettings *instance();
static QList<Interpreter> detectPythonVenvs(const Utils::FilePath &path);
signals:
void interpretersChanged(const QList<Interpreter> &interpreters, const QString &defaultId);
private:
PythonSettings();
static void saveSettings();
};
} // namespace Internal

View File

@@ -175,6 +175,11 @@ static FilePath detectPython(const FilePath &documentPath)
}
}
// check whether this file is inside a python virtual environment
QList<Interpreter> venvInterpreters = PythonSettings::detectPythonVenvs(documentPath);
if (!python.exists())
python = venvInterpreters.value(0).command;
if (!python.exists())
python = PythonSettings::defaultInterpreter().command;
@@ -248,9 +253,15 @@ public:
? QString{"python-language-server[pyflakes]"}
: QString{"python-language-server[all]"};
m_process.start(m_python.toString(), {"-m", "pip", "install", "--user", pylsVersion});
QStringList arguments = {"-m", "pip", "install", pylsVersion};
Core::MessageManager::write(tr("Running '%1 %2' to install python language server")
// add --user to global pythons, but skip it for venv pythons
if (!QDir(m_python.parentDir().toString()).exists("activate"))
arguments << "--user";
m_process.start(m_python.toString(), arguments);
Core::MessageManager::write(tr("Running \"%1 %2\" to install Python language server")
.arg(m_process.program(), m_process.arguments().join(' ')));
m_killTimer.setSingleShot(true);
@@ -261,7 +272,7 @@ private:
void cancel()
{
SynchronousProcess::stopProcess(m_process);
Core::MessageManager::write(tr("The Python language server installation canceled by %1.")
Core::MessageManager::write(tr("The Python language server installation was canceled by %1.")
.arg(m_killTimer.isActive() ? tr("user") : tr("time out")));
}
@@ -371,7 +382,7 @@ void PyLSConfigureAssistant::openDocumentWithPython(const FilePath &python,
&& infoBar->canInfoBeAdded(installPylsInfoBarId)) {
auto message
= tr("Install and set up Python language server (PyLS) for %1 (%2). "
"The language server provides Python specific completions and annotations.")
"The language server provides Python specific completion and annotation.")
.arg(pythonName(python), python.toUserOutput());
Core::InfoBarEntry info(installPylsInfoBarId,
message,
@@ -383,7 +394,7 @@ void PyLSConfigureAssistant::openDocumentWithPython(const FilePath &python,
} else if (lsState.state == PythonLanguageServerState::AlreadyInstalled
&& infoBar->canInfoBeAdded(startPylsInfoBarId)) {
auto message = tr("Found a Python language server for %1 (%2). "
"Should this one be set up for this document?")
"Set it up for this document?")
.arg(pythonName(python), python.toUserOutput());
Core::InfoBarEntry info(startPylsInfoBarId,
message,