forked from qt-creator/qt-creator
Promote previously python-specific InterpreterAspect
... and drop PythonRunConfiguration, which is a plain RunConfiguration now. Change-Id: I540cb738180fc1424f730d6d1998886915ce527b Reviewed-by: <github-actions-qt-creator@cristianadam.eu> Reviewed-by: David Schulz <david.schulz@qt.io>
This commit is contained in:
@@ -184,8 +184,8 @@ public:
|
||||
Utils::FilePaths projectSourceFiles;
|
||||
|
||||
// Used by Script debugging
|
||||
QString interpreter;
|
||||
QString mainScript;
|
||||
Utils::FilePath interpreter;
|
||||
Utils::FilePath mainScript;
|
||||
|
||||
// Used by AttachCrashedExternal.
|
||||
QString crashParameter;
|
||||
|
@@ -939,18 +939,19 @@ DebuggerRunTool::DebuggerRunTool(RunControl *runControl, AllowTerminal allowTerm
|
||||
m_runParameters.nativeMixedEnabled = bool(nativeMixedOverride);
|
||||
|
||||
|
||||
RunConfiguration *runConfig = runControl->runConfiguration();
|
||||
if (runConfig && runConfig->property("supportsDebugger").toBool()) {
|
||||
const QString mainScript = runConfig->property("mainScript").toString();
|
||||
const QString interpreter = runConfig->property("interpreter").toString();
|
||||
if (auto interpreterAspect = runControl->aspect<InterpreterAspect>()) {
|
||||
if (auto mainScriptAspect = runControl->aspect<MainScriptAspect>()) {
|
||||
const FilePath mainScript = mainScriptAspect->filePath;
|
||||
const FilePath interpreter = interpreterAspect->interpreter.command;
|
||||
if (!interpreter.isEmpty() && mainScript.endsWith(".py")) {
|
||||
m_runParameters.mainScript = mainScript;
|
||||
m_runParameters.interpreter = interpreter;
|
||||
const QString args = runConfig->property("arguments").toString();
|
||||
m_runParameters.inferior.command.addArgs(args, CommandLine::Raw);
|
||||
if (auto args = runControl->aspect<ArgumentsAspect>())
|
||||
m_runParameters.inferior.command.addArgs(args->arguments, CommandLine::Raw);
|
||||
m_engine = createPdbEngine();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
m_runParameters.dumperPath = Core::ICore::resourcePath("debugger/");
|
||||
if (QtSupport::QtVersion *baseQtVersion = QtSupport::QtKitAspect::qtVersion(kit)) {
|
||||
|
@@ -125,28 +125,24 @@ void PdbEngine::setupEngine()
|
||||
connect(&m_proc, &QtcProcess::readyReadStandardOutput, this, &PdbEngine::readPdbStandardOutput);
|
||||
connect(&m_proc, &QtcProcess::readyReadStandardError, this, &PdbEngine::readPdbStandardError);
|
||||
|
||||
QFile scriptFile(runParameters().mainScript);
|
||||
if (!scriptFile.open(QIODevice::ReadOnly|QIODevice::Text)) {
|
||||
const FilePath scriptFile = runParameters().mainScript;
|
||||
if (!scriptFile.isReadableFile()) {
|
||||
AsynchronousMessageBox::critical(tr("Python Error"),
|
||||
QString("Cannot open script file %1:\n%2").
|
||||
arg(scriptFile.fileName(), scriptFile.errorString()));
|
||||
QString("Cannot open script file %1").arg(scriptFile.toUserOutput()));
|
||||
notifyEngineSetupFailed();
|
||||
}
|
||||
|
||||
QStringList args = {bridge, scriptFile.fileName()};
|
||||
args.append(ProcessArgs::splitArgs(runParameters().inferior.workingDirectory.path()));
|
||||
showMessage("STARTING " + m_interpreter + ' ' + args.join(' '));
|
||||
CommandLine cmd{m_interpreter, {bridge, scriptFile.path()}};
|
||||
cmd.addArg(runParameters().inferior.workingDirectory.path());
|
||||
showMessage("STARTING " + cmd.toUserOutput());
|
||||
m_proc.setEnvironment(runParameters().debugger.environment);
|
||||
m_proc.setCommand({ FilePath::fromString(m_interpreter), args });
|
||||
m_proc.setCommand(cmd);
|
||||
m_proc.start();
|
||||
|
||||
if (!m_proc.waitForStarted()) {
|
||||
const QString msg = tr("Unable to start pdb \"%1\": %2")
|
||||
.arg(m_interpreter, m_proc.errorString());
|
||||
notifyEngineSetupFailed();
|
||||
showMessage("ADAPTER START FAILED");
|
||||
if (!msg.isEmpty())
|
||||
ICore::showWarningWithOptions(tr("Adapter start failed"), msg);
|
||||
ICore::showWarningWithOptions(tr("Adapter start failed"), m_proc.exitMessage());
|
||||
notifyEngineSetupFailed();
|
||||
return;
|
||||
}
|
||||
@@ -416,7 +412,7 @@ QString PdbEngine::errorMessage(QProcess::ProcessError error) const
|
||||
return tr("The Pdb process failed to start. Either the "
|
||||
"invoked program \"%1\" is missing, or you may have insufficient "
|
||||
"permissions to invoke the program.")
|
||||
.arg(m_interpreter);
|
||||
.arg(m_interpreter.toUserOutput());
|
||||
case QProcess::Crashed:
|
||||
return tr("The Pdb process crashed some time after starting "
|
||||
"successfully.");
|
||||
|
@@ -112,7 +112,7 @@ private:
|
||||
|
||||
QString m_inbuffer;
|
||||
Utils::QtcProcess m_proc;
|
||||
QString m_interpreter;
|
||||
Utils::FilePath m_interpreter;
|
||||
};
|
||||
|
||||
} // namespace Internal
|
||||
|
@@ -32,6 +32,8 @@
|
||||
#include "runconfiguration.h"
|
||||
#include "target.h"
|
||||
|
||||
#include <coreplugin/icore.h>
|
||||
|
||||
#include <utils/detailsbutton.h>
|
||||
#include <utils/fancylineedit.h>
|
||||
#include <utils/layoutbuilder.h>
|
||||
@@ -40,11 +42,13 @@
|
||||
#include <utils/utilsicons.h>
|
||||
|
||||
#include <QCheckBox>
|
||||
#include <QComboBox>
|
||||
#include <QLabel>
|
||||
#include <QLineEdit>
|
||||
#include <QFormLayout>
|
||||
#include <QPlainTextEdit>
|
||||
#include <QToolButton>
|
||||
#include <QPushButton>
|
||||
|
||||
using namespace Utils;
|
||||
|
||||
@@ -764,4 +768,109 @@ RunAsRootAspect::RunAsRootAspect()
|
||||
setLabel(tr("Run as root user"), LabelPlacement::AtCheckBox);
|
||||
}
|
||||
|
||||
Interpreter::Interpreter()
|
||||
: id(QUuid::createUuid().toString())
|
||||
{}
|
||||
|
||||
Interpreter::Interpreter(const QString &_id,
|
||||
const QString &_name,
|
||||
const FilePath &_command,
|
||||
bool _autoDetected)
|
||||
: id(_id)
|
||||
, name(_name)
|
||||
, command(_command)
|
||||
, autoDetected(_autoDetected)
|
||||
{}
|
||||
|
||||
/*!
|
||||
\class ProjectExplorer::InterpreterAspect
|
||||
\inmodule QtCreator
|
||||
|
||||
\brief The InterpreterAspect class lets a user specify an interpreter
|
||||
to use with files or projects using an interpreted language.
|
||||
*/
|
||||
|
||||
InterpreterAspect::InterpreterAspect()
|
||||
{
|
||||
addDataExtractor(this, &InterpreterAspect::currentInterpreter, &Data::interpreter);
|
||||
}
|
||||
|
||||
Interpreter InterpreterAspect::currentInterpreter() const
|
||||
{
|
||||
return Utils::findOrDefault(m_interpreters, Utils::equal(&Interpreter::id, m_currentId));
|
||||
}
|
||||
|
||||
void InterpreterAspect::updateInterpreters(const QList<Interpreter> &interpreters)
|
||||
{
|
||||
m_interpreters = interpreters;
|
||||
if (m_comboBox)
|
||||
updateComboBox();
|
||||
}
|
||||
|
||||
void InterpreterAspect::setCurrentInterpreter(const Interpreter &interpreter)
|
||||
{
|
||||
m_currentId = interpreter.id;
|
||||
emit changed();
|
||||
}
|
||||
|
||||
void InterpreterAspect::fromMap(const QVariantMap &map)
|
||||
{
|
||||
m_currentId = map.value(settingsKey(), m_defaultId).toString();
|
||||
}
|
||||
|
||||
void InterpreterAspect::toMap(QVariantMap &map) const
|
||||
{
|
||||
saveToMap(map, m_currentId, QString(), settingsKey());
|
||||
}
|
||||
|
||||
void InterpreterAspect::addToLayout(LayoutBuilder &builder)
|
||||
{
|
||||
if (QTC_GUARD(m_comboBox.isNull()))
|
||||
m_comboBox = new QComboBox;
|
||||
|
||||
updateComboBox();
|
||||
connect(m_comboBox, QOverload<int>::of(&QComboBox::currentIndexChanged),
|
||||
this, &InterpreterAspect::updateCurrentInterpreter);
|
||||
|
||||
auto manageButton = new QPushButton(tr("Manage..."));
|
||||
connect(manageButton, &QPushButton::clicked, [this] {
|
||||
Core::ICore::showOptionsDialog(m_settingsDialogId);
|
||||
});
|
||||
|
||||
builder.addItems({tr("Interpreter"), m_comboBox.data(), manageButton});
|
||||
}
|
||||
|
||||
void InterpreterAspect::updateCurrentInterpreter()
|
||||
{
|
||||
const int index = m_comboBox->currentIndex();
|
||||
if (index < 0)
|
||||
return;
|
||||
QTC_ASSERT(index < m_interpreters.size(), return);
|
||||
m_currentId = m_interpreters[index].id;
|
||||
m_comboBox->setToolTip(m_interpreters[index].command.toUserOutput());
|
||||
emit changed();
|
||||
}
|
||||
|
||||
void InterpreterAspect::updateComboBox()
|
||||
{
|
||||
int currentIndex = -1;
|
||||
int defaultIndex = -1;
|
||||
const QString currentId = m_currentId;
|
||||
m_comboBox->clear();
|
||||
for (const Interpreter &interpreter : qAsConst(m_interpreters)) {
|
||||
int index = m_comboBox->count();
|
||||
m_comboBox->addItem(interpreter.name);
|
||||
m_comboBox->setItemData(index, interpreter.command.toUserOutput(), Qt::ToolTipRole);
|
||||
if (interpreter.id == currentId)
|
||||
currentIndex = index;
|
||||
if (interpreter.id == m_defaultId)
|
||||
defaultIndex = index;
|
||||
}
|
||||
if (currentIndex >= 0)
|
||||
m_comboBox->setCurrentIndex(currentIndex);
|
||||
else if (defaultIndex >= 0)
|
||||
m_comboBox->setCurrentIndex(defaultIndex);
|
||||
updateCurrentInterpreter();
|
||||
}
|
||||
|
||||
} // namespace ProjectExplorer
|
||||
|
@@ -33,6 +33,7 @@
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
class QCheckBox;
|
||||
class QComboBox;
|
||||
class QPlainTextEdit;
|
||||
class QToolButton;
|
||||
QT_END_NAMESPACE
|
||||
@@ -214,4 +215,61 @@ public:
|
||||
SymbolFileAspect() = default;
|
||||
};
|
||||
|
||||
class PROJECTEXPLORER_EXPORT Interpreter
|
||||
{
|
||||
public:
|
||||
Interpreter();
|
||||
Interpreter(const QString &id,
|
||||
const QString &name,
|
||||
const Utils::FilePath &command,
|
||||
bool autoDetected = true);
|
||||
|
||||
inline bool operator==(const Interpreter &other) const
|
||||
{
|
||||
return id == other.id && name == other.name && command == other.command;
|
||||
}
|
||||
|
||||
QString id;
|
||||
QString name;
|
||||
Utils::FilePath command;
|
||||
bool autoDetected = true;
|
||||
};
|
||||
|
||||
class PROJECTEXPLORER_EXPORT InterpreterAspect : public Utils::BaseAspect
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
InterpreterAspect();
|
||||
|
||||
Interpreter currentInterpreter() const;
|
||||
void updateInterpreters(const QList<Interpreter> &interpreters);
|
||||
void setDefaultInterpreter(const Interpreter &interpreter) { m_defaultId = interpreter.id; }
|
||||
void setCurrentInterpreter(const Interpreter &interpreter);
|
||||
void setSettingsDialogId(Utils::Id id) { m_settingsDialogId = id; }
|
||||
|
||||
void fromMap(const QVariantMap &) override;
|
||||
void toMap(QVariantMap &) const override;
|
||||
void addToLayout(Utils::LayoutBuilder &builder) override;
|
||||
|
||||
struct Data : Utils::BaseAspect::Data { Interpreter interpreter; };
|
||||
|
||||
private:
|
||||
void updateCurrentInterpreter();
|
||||
void updateComboBox();
|
||||
QList<Interpreter> m_interpreters;
|
||||
QPointer<QComboBox> m_comboBox;
|
||||
QString m_defaultId;
|
||||
QString m_currentId;
|
||||
Utils::Id m_settingsDialogId;
|
||||
};
|
||||
|
||||
class PROJECTEXPLORER_EXPORT MainScriptAspect : public Utils::StringAspect
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
MainScriptAspect() = default;
|
||||
};
|
||||
|
||||
} // namespace ProjectExplorer
|
||||
|
@@ -25,6 +25,7 @@
|
||||
|
||||
#include "pyside.h"
|
||||
|
||||
#include "pythonconstants.h"
|
||||
#include "pythonplugin.h"
|
||||
#include "pythonproject.h"
|
||||
#include "pythonrunconfiguration.h"
|
||||
@@ -32,8 +33,12 @@
|
||||
#include "pythonutils.h"
|
||||
|
||||
#include <coreplugin/icore.h>
|
||||
|
||||
#include <projectexplorer/runconfigurationaspects.h>
|
||||
#include <projectexplorer/target.h>
|
||||
|
||||
#include <texteditor/textdocument.h>
|
||||
|
||||
#include <utils/algorithm.h>
|
||||
#include <utils/infobar.h>
|
||||
#include <utils/runextensions.h>
|
||||
@@ -42,6 +47,7 @@
|
||||
#include <QTextCursor>
|
||||
|
||||
using namespace Utils;
|
||||
using namespace ProjectExplorer;
|
||||
|
||||
namespace Python {
|
||||
namespace Internal {
|
||||
@@ -106,10 +112,12 @@ void PySideInstaller::installPyside(const Utils::FilePath &python,
|
||||
}
|
||||
|
||||
void PySideInstaller::changeInterpreter(const QString &interpreterId,
|
||||
PythonRunConfiguration *runConfig)
|
||||
RunConfiguration *runConfig)
|
||||
{
|
||||
if (runConfig)
|
||||
runConfig->setInterpreter(PythonSettings::interpreter(interpreterId));
|
||||
if (runConfig) {
|
||||
if (auto aspect = runConfig->aspect<InterpreterAspect>())
|
||||
aspect->setCurrentInterpreter(PythonSettings::interpreter(interpreterId));
|
||||
}
|
||||
}
|
||||
|
||||
void PySideInstaller::handlePySideMissing(const FilePath &python,
|
||||
@@ -128,21 +136,23 @@ void PySideInstaller::handlePySideMissing(const FilePath &python,
|
||||
|
||||
if (PythonProject *project = pythonProjectForFile(document->filePath())) {
|
||||
if (ProjectExplorer::Target *target = project->activeTarget()) {
|
||||
if (auto runConfiguration = qobject_cast<PythonRunConfiguration *>(
|
||||
target->activeRunConfiguration())) {
|
||||
auto runConfiguration = target->activeRunConfiguration();
|
||||
if (runConfiguration->id() == Constants::C_PYTHONRUNCONFIGURATION_ID) {
|
||||
const QList<InfoBarEntry::ComboInfo> interpreters = Utils::transform(
|
||||
PythonSettings::interpreters(), [](const Interpreter &interpreter) {
|
||||
return InfoBarEntry::ComboInfo{interpreter.name, interpreter.id};
|
||||
});
|
||||
auto interpreterChangeCallback =
|
||||
[=, rc = QPointer<PythonRunConfiguration>(runConfiguration)](
|
||||
[=, rc = QPointer<RunConfiguration>(runConfiguration)](
|
||||
const InfoBarEntry::ComboInfo &info) {
|
||||
changeInterpreter(info.data.toString(), rc);
|
||||
};
|
||||
|
||||
const auto isCurrentInterpreter
|
||||
= Utils::equal(&InfoBarEntry::ComboInfo::data,
|
||||
QVariant(runConfiguration->interpreter().id));
|
||||
auto interpreterAspect = runConfiguration->aspect<InterpreterAspect>();
|
||||
QTC_ASSERT(interpreterAspect, return);
|
||||
const QString id = interpreterAspect->currentInterpreter().id;
|
||||
const auto isCurrentInterpreter = Utils::equal(&InfoBarEntry::ComboInfo::data,
|
||||
QVariant(id));
|
||||
const QString switchTooltip = tr("Switch the Python interpreter for %1")
|
||||
.arg(runConfiguration->displayName());
|
||||
info.setComboInfo(interpreters,
|
||||
|
@@ -32,11 +32,11 @@
|
||||
#include <QTextDocument>
|
||||
|
||||
namespace TextEditor { class TextDocument; }
|
||||
namespace ProjectExplorer { class RunConfiguration; }
|
||||
|
||||
namespace Python {
|
||||
namespace Internal {
|
||||
|
||||
class PythonRunConfiguration;
|
||||
|
||||
class PySideInstaller : public QObject
|
||||
{
|
||||
Q_DECLARE_TR_FUNCTIONS(Python::Internal::PySideInstaller)
|
||||
@@ -49,7 +49,7 @@ private:
|
||||
|
||||
void installPyside(const Utils::FilePath &python,
|
||||
const QString &pySide, TextEditor::TextDocument *document);
|
||||
void changeInterpreter(const QString &interpreterId, PythonRunConfiguration *runConfig);
|
||||
void changeInterpreter(const QString &interpreterId, ProjectExplorer::RunConfiguration *runConfig);
|
||||
void handlePySideMissing(const Utils::FilePath &python,
|
||||
const QString &pySide,
|
||||
TextEditor::TextDocument *document);
|
||||
|
@@ -31,6 +31,8 @@ namespace Python {
|
||||
namespace Constants {
|
||||
|
||||
const char C_PYTHONEDITOR_ID[] = "PythonEditor.PythonEditor";
|
||||
const char C_PYTHONRUNCONFIGURATION_ID[] = "PythonEditor.RunConfiguration.";
|
||||
|
||||
const char C_EDITOR_DISPLAY_NAME[] =
|
||||
QT_TRANSLATE_NOOP("OpenWith::Editors", "Python Editor");
|
||||
|
||||
|
@@ -56,6 +56,7 @@
|
||||
#include <QTimer>
|
||||
|
||||
using namespace LanguageClient;
|
||||
using namespace ProjectExplorer;
|
||||
using namespace Utils;
|
||||
|
||||
namespace Python {
|
||||
|
@@ -37,7 +37,6 @@ namespace TextEditor { class TextDocument; }
|
||||
namespace Python {
|
||||
namespace Internal {
|
||||
|
||||
class Interpreter;
|
||||
struct PythonLanguageServerState;
|
||||
|
||||
class PyLSSettings : public LanguageClient::StdIOSettings
|
||||
|
@@ -135,131 +135,36 @@ private:
|
||||
|
||||
////////////////////////////////////////////////////////////////
|
||||
|
||||
class InterpreterAspect : public BaseAspect
|
||||
class PythonRunConfiguration : public RunConfiguration
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
InterpreterAspect() = default;
|
||||
|
||||
Interpreter currentInterpreter() const;
|
||||
void updateInterpreters(const QList<Interpreter> &interpreters);
|
||||
void setDefaultInterpreter(const Interpreter &interpreter) { m_defaultId = interpreter.id; }
|
||||
void setCurrentInterpreter(const Interpreter &interpreter);
|
||||
|
||||
void fromMap(const QVariantMap &) override;
|
||||
void toMap(QVariantMap &) const override;
|
||||
void addToLayout(LayoutBuilder &builder) override;
|
||||
|
||||
private:
|
||||
void updateCurrentInterpreter();
|
||||
void updateComboBox();
|
||||
QList<Interpreter> m_interpreters;
|
||||
QPointer<QComboBox> m_comboBox;
|
||||
QString m_defaultId;
|
||||
QString m_currentId;
|
||||
};
|
||||
|
||||
Interpreter InterpreterAspect::currentInterpreter() const
|
||||
{
|
||||
return Utils::findOrDefault(m_interpreters, Utils::equal(&Interpreter::id, m_currentId));
|
||||
}
|
||||
|
||||
void InterpreterAspect::updateInterpreters(const QList<Interpreter> &interpreters)
|
||||
{
|
||||
m_interpreters = interpreters;
|
||||
if (m_comboBox)
|
||||
updateComboBox();
|
||||
}
|
||||
|
||||
void InterpreterAspect::setCurrentInterpreter(const Interpreter &interpreter)
|
||||
{
|
||||
m_currentId = interpreter.id;
|
||||
emit changed();
|
||||
}
|
||||
|
||||
void InterpreterAspect::fromMap(const QVariantMap &map)
|
||||
{
|
||||
m_currentId = map.value(settingsKey(), m_defaultId).toString();
|
||||
}
|
||||
|
||||
void InterpreterAspect::toMap(QVariantMap &map) const
|
||||
{
|
||||
saveToMap(map, m_currentId, QString(), settingsKey());
|
||||
}
|
||||
|
||||
void InterpreterAspect::addToLayout(LayoutBuilder &builder)
|
||||
{
|
||||
if (QTC_GUARD(m_comboBox.isNull()))
|
||||
m_comboBox = new QComboBox;
|
||||
|
||||
updateComboBox();
|
||||
connect(m_comboBox, QOverload<int>::of(&QComboBox::currentIndexChanged),
|
||||
this, &InterpreterAspect::updateCurrentInterpreter);
|
||||
|
||||
auto manageButton = new QPushButton(tr("Manage..."));
|
||||
connect(manageButton, &QPushButton::clicked, []() {
|
||||
Core::ICore::showOptionsDialog(Constants::C_PYTHONOPTIONS_PAGE_ID);
|
||||
});
|
||||
|
||||
builder.addItems({tr("Interpreter"), m_comboBox.data(), manageButton});
|
||||
}
|
||||
|
||||
void InterpreterAspect::updateCurrentInterpreter()
|
||||
{
|
||||
const int index = m_comboBox->currentIndex();
|
||||
if (index < 0)
|
||||
return;
|
||||
QTC_ASSERT(index < m_interpreters.size(), return);
|
||||
m_currentId = m_interpreters[index].id;
|
||||
m_comboBox->setToolTip(m_interpreters[index].command.toUserOutput());
|
||||
emit changed();
|
||||
}
|
||||
|
||||
void InterpreterAspect::updateComboBox()
|
||||
{
|
||||
int currentIndex = -1;
|
||||
int defaultIndex = -1;
|
||||
const QString currentId = m_currentId;
|
||||
m_comboBox->clear();
|
||||
for (const Interpreter &interpreter : qAsConst(m_interpreters)) {
|
||||
int index = m_comboBox->count();
|
||||
m_comboBox->addItem(interpreter.name);
|
||||
m_comboBox->setItemData(index, interpreter.command.toUserOutput(), Qt::ToolTipRole);
|
||||
if (interpreter.id == currentId)
|
||||
currentIndex = index;
|
||||
if (interpreter.id == m_defaultId)
|
||||
defaultIndex = index;
|
||||
}
|
||||
if (currentIndex >= 0)
|
||||
m_comboBox->setCurrentIndex(currentIndex);
|
||||
else if (defaultIndex >= 0)
|
||||
m_comboBox->setCurrentIndex(defaultIndex);
|
||||
updateCurrentInterpreter();
|
||||
}
|
||||
|
||||
class MainScriptAspect : public StringAspect
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
MainScriptAspect() = default;
|
||||
};
|
||||
|
||||
PythonRunConfiguration::PythonRunConfiguration(Target *target, Utils::Id id)
|
||||
PythonRunConfiguration(Target *target, Id id)
|
||||
: RunConfiguration(target, id)
|
||||
{
|
||||
{
|
||||
auto interpreterAspect = addAspect<InterpreterAspect>();
|
||||
interpreterAspect->setSettingsKey("PythonEditor.RunConfiguation.Interpreter");
|
||||
connect(interpreterAspect, &InterpreterAspect::changed,
|
||||
this, &PythonRunConfiguration::interpreterChanged);
|
||||
interpreterAspect->setSettingsDialogId(Constants::C_PYTHONOPTIONS_PAGE_ID);
|
||||
|
||||
connect(interpreterAspect, &InterpreterAspect::changed, this, [this, interpreterAspect] {
|
||||
using namespace LanguageClient;
|
||||
const FilePath python = interpreterAspect->currentInterpreter().command;
|
||||
|
||||
for (FilePath &file : project()->files(Project::AllFiles)) {
|
||||
if (auto document = TextEditor::TextDocument::textDocumentForFilePath(file)) {
|
||||
if (document->mimeType() == Constants::C_PY_MIMETYPE) {
|
||||
PyLSConfigureAssistant::instance()->openDocumentWithPython(python, document);
|
||||
PySideInstaller::instance()->checkPySideInstallation(python, document);
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
connect(PythonSettings::instance(), &PythonSettings::interpretersChanged,
|
||||
interpreterAspect, &InterpreterAspect::updateInterpreters);
|
||||
|
||||
QList<Interpreter> interpreters = PythonSettings::detectPythonVenvs(project()->projectDirectory());
|
||||
aspect<InterpreterAspect>()->updateInterpreters(PythonSettings::interpreters());
|
||||
aspect<InterpreterAspect>()->setDefaultInterpreter(
|
||||
interpreterAspect->updateInterpreters(PythonSettings::interpreters());
|
||||
interpreterAspect->setDefaultInterpreter(
|
||||
interpreters.isEmpty() ? PythonSettings::defaultInterpreter() : interpreters.first());
|
||||
|
||||
auto bufferedAspect = addAspect<BoolAspect>();
|
||||
@@ -280,11 +185,11 @@ PythonRunConfiguration::PythonRunConfiguration(Target *target, Utils::Id id)
|
||||
addAspect<WorkingDirectoryAspect>(nullptr);
|
||||
addAspect<TerminalAspect>();
|
||||
|
||||
setCommandLineGetter([this, bufferedAspect, interpreterAspect, argumentsAspect] {
|
||||
setCommandLineGetter([this, bufferedAspect, interpreterAspect, argumentsAspect, scriptAspect] {
|
||||
CommandLine cmd{interpreterAspect->currentInterpreter().command};
|
||||
if (!bufferedAspect->value())
|
||||
cmd.addArg("-u");
|
||||
cmd.addArg(mainScript());
|
||||
cmd.addArg(scriptAspect->filePath().fileName());
|
||||
cmd.addArgs(argumentsAspect->arguments(macroExpander()), CommandLine::Raw);
|
||||
return cmd;
|
||||
});
|
||||
@@ -298,57 +203,12 @@ PythonRunConfiguration::PythonRunConfiguration(Target *target, Utils::Id id)
|
||||
});
|
||||
|
||||
connect(target, &Target::buildSystemUpdated, this, &RunConfiguration::update);
|
||||
}
|
||||
|
||||
void PythonRunConfiguration::interpreterChanged()
|
||||
{
|
||||
using namespace LanguageClient;
|
||||
|
||||
const FilePath python = interpreter().command;
|
||||
|
||||
for (FilePath &file : project()->files(Project::AllFiles)) {
|
||||
if (auto document = TextEditor::TextDocument::textDocumentForFilePath(file)) {
|
||||
if (document->mimeType() == Constants::C_PY_MIMETYPE) {
|
||||
PyLSConfigureAssistant::instance()->openDocumentWithPython(python, document);
|
||||
PySideInstaller::instance()->checkPySideInstallation(python, document);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
bool PythonRunConfiguration::supportsDebugger() const
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
QString PythonRunConfiguration::mainScript() const
|
||||
{
|
||||
return aspect<MainScriptAspect>()->value();
|
||||
}
|
||||
|
||||
QString PythonRunConfiguration::arguments() const
|
||||
{
|
||||
return aspect<ArgumentsAspect>()->arguments(macroExpander());
|
||||
}
|
||||
|
||||
Interpreter PythonRunConfiguration::interpreter() const
|
||||
{
|
||||
return aspect<InterpreterAspect>()->currentInterpreter();
|
||||
}
|
||||
|
||||
QString PythonRunConfiguration::interpreterPath() const
|
||||
{
|
||||
return interpreter().command.toString();
|
||||
}
|
||||
|
||||
void PythonRunConfiguration::setInterpreter(const Interpreter &interpreter)
|
||||
{
|
||||
aspect<InterpreterAspect>()->setCurrentInterpreter(interpreter);
|
||||
}
|
||||
};
|
||||
|
||||
PythonRunConfigurationFactory::PythonRunConfigurationFactory()
|
||||
{
|
||||
registerRunConfiguration<PythonRunConfiguration>("PythonEditor.RunConfiguration.");
|
||||
registerRunConfiguration<PythonRunConfiguration>(Constants::C_PYTHONRUNCONFIGURATION_ID);
|
||||
addSupportedProjectType(PythonProjectId);
|
||||
}
|
||||
|
||||
@@ -363,5 +223,3 @@ PythonOutputFormatterFactory::PythonOutputFormatterFactory()
|
||||
|
||||
} // namespace Internal
|
||||
} // namespace Python
|
||||
|
||||
#include "pythonrunconfiguration.moc"
|
||||
|
@@ -31,31 +31,6 @@
|
||||
namespace Python {
|
||||
namespace Internal {
|
||||
|
||||
class Interpreter;
|
||||
|
||||
class PythonRunConfiguration : public ProjectExplorer::RunConfiguration
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
Q_PROPERTY(bool supportsDebugger READ supportsDebugger)
|
||||
Q_PROPERTY(QString interpreter READ interpreterPath)
|
||||
Q_PROPERTY(QString mainScript READ mainScript)
|
||||
Q_PROPERTY(QString arguments READ arguments)
|
||||
|
||||
public:
|
||||
PythonRunConfiguration(ProjectExplorer::Target *target, Utils::Id id);
|
||||
Interpreter interpreter() const;
|
||||
QString interpreterPath() const;
|
||||
void setInterpreter(const Interpreter &interpreterId);
|
||||
|
||||
private:
|
||||
void interpreterChanged();
|
||||
|
||||
bool supportsDebugger() const;
|
||||
QString mainScript() const;
|
||||
QString arguments() const;
|
||||
};
|
||||
|
||||
class PythonRunConfigurationFactory : public ProjectExplorer::RunConfigurationFactory
|
||||
{
|
||||
public:
|
||||
|
@@ -50,11 +50,38 @@
|
||||
#include <QTreeView>
|
||||
#include <QWidget>
|
||||
|
||||
using namespace ProjectExplorer;
|
||||
using namespace Utils;
|
||||
using namespace Layouting;
|
||||
|
||||
namespace Python {
|
||||
namespace Internal {
|
||||
|
||||
using namespace Utils;
|
||||
using namespace Layouting;
|
||||
static Interpreter createInterpreter(const FilePath &python,
|
||||
const QString &defaultName,
|
||||
bool windowedSuffix = false)
|
||||
{
|
||||
Interpreter result;
|
||||
result.id = QUuid::createUuid().toString();
|
||||
result.command = python;
|
||||
|
||||
QtcProcess pythonProcess;
|
||||
pythonProcess.setProcessChannelMode(QProcess::MergedChannels);
|
||||
pythonProcess.setTimeoutS(1);
|
||||
pythonProcess.setCommand({python, {"--version"}});
|
||||
pythonProcess.runBlocking();
|
||||
if (pythonProcess.result() == ProcessResult::FinishedWithSuccess)
|
||||
result.name = pythonProcess.stdOut().trimmed();
|
||||
if (result.name.isEmpty())
|
||||
result.name = defaultName;
|
||||
if (windowedSuffix)
|
||||
result.name += " (Windowed)";
|
||||
QDir pythonDir(python.parentDir().toString());
|
||||
if (pythonDir.exists() && pythonDir.exists("activate") && pythonDir.cdUp())
|
||||
result.name += QString(" (%1 Virtual Environment)").arg(pythonDir.dirName());
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
class InterpreterDetailsWidget : public QWidget
|
||||
{
|
||||
@@ -331,36 +358,6 @@ static bool alreadyRegistered(const QList<Interpreter> &pythons, const FilePath
|
||||
});
|
||||
}
|
||||
|
||||
Interpreter::Interpreter(const FilePath &python, const QString &defaultName, bool windowedSuffix)
|
||||
: id(QUuid::createUuid().toString())
|
||||
, command(python)
|
||||
{
|
||||
QtcProcess pythonProcess;
|
||||
pythonProcess.setProcessChannelMode(QProcess::MergedChannels);
|
||||
pythonProcess.setTimeoutS(1);
|
||||
pythonProcess.setCommand({python, {"--version"}});
|
||||
pythonProcess.runBlocking();
|
||||
if (pythonProcess.result() == ProcessResult::FinishedWithSuccess)
|
||||
name = pythonProcess.stdOut().trimmed();
|
||||
if (name.isEmpty())
|
||||
name = defaultName;
|
||||
if (windowedSuffix)
|
||||
name += " (Windowed)";
|
||||
QDir pythonDir(python.parentDir().toString());
|
||||
if (pythonDir.exists() && pythonDir.exists("activate") && pythonDir.cdUp())
|
||||
name += QString(" (%1 Virtual Environment)").arg(pythonDir.dirName());
|
||||
}
|
||||
|
||||
Interpreter::Interpreter(const QString &_id,
|
||||
const QString &_name,
|
||||
const FilePath &_command,
|
||||
bool _autoDetected)
|
||||
: id(_id)
|
||||
, name(_name)
|
||||
, command(_command)
|
||||
, autoDetected(_autoDetected)
|
||||
{}
|
||||
|
||||
static InterpreterOptionsPage &interpreterOptionsPage()
|
||||
{
|
||||
static InterpreterOptionsPage page;
|
||||
@@ -480,10 +477,10 @@ static void addPythonsFromRegistry(QList<Interpreter> &pythons)
|
||||
const FilePath &path = FilePath::fromUserInput(regVal.toString());
|
||||
const FilePath python = path.pathAppended("python").withExecutableSuffix();
|
||||
if (python.exists() && !alreadyRegistered(pythons, python))
|
||||
pythons << Interpreter(python, "Python " + versionGroup);
|
||||
pythons << createInterpreter(python, "Python " + versionGroup);
|
||||
const FilePath pythonw = path.pathAppended("pythonw").withExecutableSuffix();
|
||||
if (pythonw.exists() && !alreadyRegistered(pythons, pythonw))
|
||||
pythons << Interpreter(pythonw, "Python " + versionGroup, true);
|
||||
pythons << createInterpreter(pythonw, "Python " + versionGroup, true);
|
||||
}
|
||||
pythonRegistry.endGroup();
|
||||
}
|
||||
@@ -499,11 +496,11 @@ static void addPythonsFromPath(QList<Interpreter> &pythons)
|
||||
if (executable.toFileInfo().size() == 0)
|
||||
continue;
|
||||
if (executable.exists() && !alreadyRegistered(pythons, executable))
|
||||
pythons << Interpreter(executable, "Python from Path");
|
||||
pythons << createInterpreter(executable, "Python from Path");
|
||||
}
|
||||
for (const FilePath &executable : env.findAllInPath("pythonw")) {
|
||||
if (executable.exists() && !alreadyRegistered(pythons, executable))
|
||||
pythons << Interpreter(executable, "Python from Path", true);
|
||||
pythons << createInterpreter(executable, "Python from Path", true);
|
||||
}
|
||||
} else {
|
||||
const QStringList filters = {"python",
|
||||
@@ -515,7 +512,7 @@ static void addPythonsFromPath(QList<Interpreter> &pythons)
|
||||
for (const QFileInfo &fi : dir.entryInfoList(filters)) {
|
||||
const FilePath executable = Utils::FilePath::fromFileInfo(fi);
|
||||
if (executable.exists() && !alreadyRegistered(pythons, executable))
|
||||
pythons << Interpreter(executable, "Python from Path");
|
||||
pythons << createInterpreter(executable, "Python from Path");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -601,7 +598,7 @@ QList<Interpreter> PythonSettings::detectPythonVenvs(const FilePath &path)
|
||||
= Utils::findOrDefault(PythonSettings::interpreters(),
|
||||
Utils::equal(&Interpreter::command, python));
|
||||
if (interpreter.command.isEmpty()) {
|
||||
interpreter = Interpreter(python, defaultName);
|
||||
interpreter = createInterpreter(python, defaultName);
|
||||
PythonSettings::addInterpreter(interpreter);
|
||||
}
|
||||
result << interpreter;
|
||||
|
@@ -25,6 +25,8 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <projectexplorer/runconfigurationaspects.h>
|
||||
|
||||
#include <utils/fileutils.h>
|
||||
#include <utils/optional.h>
|
||||
|
||||
@@ -33,35 +35,14 @@
|
||||
namespace Python {
|
||||
namespace Internal {
|
||||
|
||||
class Interpreter
|
||||
{
|
||||
public:
|
||||
Interpreter() = default;
|
||||
Interpreter(const Utils::FilePath &python,
|
||||
const QString &defaultName,
|
||||
bool windowedSuffix = false);
|
||||
Interpreter(const QString &id,
|
||||
const QString &name,
|
||||
const Utils::FilePath &command,
|
||||
bool autoDetected = true);
|
||||
|
||||
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;
|
||||
bool autoDetected = true;
|
||||
};
|
||||
|
||||
class PythonSettings : public QObject
|
||||
{
|
||||
Q_OBJECT
|
||||
public:
|
||||
static void init();
|
||||
|
||||
using Interpreter = ProjectExplorer::Interpreter;
|
||||
|
||||
static QList<Interpreter> interpreters();
|
||||
static Interpreter defaultInterpreter();
|
||||
static Interpreter interpreter(const QString &interpreterId);
|
||||
|
@@ -39,6 +39,7 @@
|
||||
#include <utils/mimeutils.h>
|
||||
#include <utils/qtcprocess.h>
|
||||
|
||||
using namespace ProjectExplorer;
|
||||
using namespace Utils;
|
||||
|
||||
namespace Python {
|
||||
@@ -51,15 +52,15 @@ FilePath detectPython(const FilePath &documentPath)
|
||||
PythonProject *project = documentPath.isEmpty()
|
||||
? nullptr
|
||||
: qobject_cast<PythonProject *>(
|
||||
ProjectExplorer::SessionManager::projectForFile(documentPath));
|
||||
SessionManager::projectForFile(documentPath));
|
||||
if (!project)
|
||||
project = qobject_cast<PythonProject *>(ProjectExplorer::SessionManager::startupProject());
|
||||
project = qobject_cast<PythonProject *>(SessionManager::startupProject());
|
||||
|
||||
if (project) {
|
||||
if (auto target = project->activeTarget()) {
|
||||
if (auto runConfig = qobject_cast<PythonRunConfiguration *>(
|
||||
target->activeRunConfiguration())) {
|
||||
python = runConfig->interpreter().command;
|
||||
if (auto runConfig = target->activeRunConfiguration()) {
|
||||
if (auto interpreter = runConfig->aspect<InterpreterAspect>())
|
||||
python = interpreter->currentInterpreter().command;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -99,7 +100,7 @@ void openPythonRepl(QObject *parent, const FilePath &file, ReplType type)
|
||||
{
|
||||
static const auto workingDir = [](const FilePath &file) {
|
||||
if (file.isEmpty()) {
|
||||
if (ProjectExplorer::Project *project = ProjectExplorer::SessionManager::startupProject())
|
||||
if (Project *project = SessionManager::startupProject())
|
||||
return project->projectDirectory();
|
||||
return FilePath::fromString(QDir::currentPath());
|
||||
}
|
||||
@@ -147,7 +148,7 @@ QString pythonName(const FilePath &pythonPath)
|
||||
|
||||
PythonProject *pythonProjectForFile(const FilePath &pythonFile)
|
||||
{
|
||||
for (ProjectExplorer::Project *project : ProjectExplorer::SessionManager::projects()) {
|
||||
for (Project *project : SessionManager::projects()) {
|
||||
if (auto pythonProject = qobject_cast<PythonProject *>(project)) {
|
||||
if (pythonProject->isKnownFile(pythonFile))
|
||||
return pythonProject;
|
||||
|
Reference in New Issue
Block a user