diff --git a/src/plugins/python/pythonsettings.cpp b/src/plugins/python/pythonsettings.cpp index f2f5975ff40..d9f5f74e9ff 100644 --- a/src/plugins/python/pythonsettings.cpp +++ b/src/plugins/python/pythonsettings.cpp @@ -53,9 +53,9 @@ #include #include +using namespace Layouting; using namespace ProjectExplorer; using namespace Utils; -using namespace Layouting; namespace Python::Internal { @@ -645,12 +645,15 @@ void PythonSettings::disableOutdatedPyls() } } -static QList pythonsFromRegistry() +static void pythonsFromRegistry(QPromise> &promise) { QList pythons; QSettings pythonRegistry("HKEY_LOCAL_MACHINE\\SOFTWARE\\Python\\PythonCore", QSettings::NativeFormat); for (const QString &versionGroup : pythonRegistry.childGroups()) { + if (promise.isCanceled()) + return; + pythonRegistry.beginGroup(versionGroup); QString name = pythonRegistry.value("DisplayName").toString(); QVariant regVal = pythonRegistry.value("InstallPath/ExecutablePath"); @@ -671,14 +674,17 @@ static QList pythonsFromRegistry() } pythonRegistry.endGroup(); } - return pythons; + promise.addResult(pythons); } -static QList pythonsFromPath() +static void pythonsFromPath(QPromise> &promise) { QList pythons; if (HostOsInfo::isWindowsHost()) { for (const FilePath &executable : FilePath("python").searchAllInPath()) { + if (promise.isCanceled()) + return; + // Windows creates empty redirector files that may interfere if (executable.toFileInfo().size() == 0) continue; @@ -695,6 +701,9 @@ static QList pythonsFromPath() for (const FilePath &path : dirs) { const QDir dir(path.toString()); for (const QFileInfo &fi : dir.entryInfoList(filters)) { + if (promise.isCanceled()) + return; + const FilePath executable = FilePath::fromUserInput(fi.canonicalFilePath()); if (!used.contains(executable) && executable.exists()) { used.insert(executable); @@ -703,7 +712,7 @@ static QList pythonsFromPath() } } } - return pythons; + promise.addResult(pythons); } static QString idForPythonFromPath(const QList &pythons) @@ -732,41 +741,6 @@ static bool alreadyRegistered(const Interpreter &candidate) }); } -static void scanPath() -{ - auto watcher = new QFutureWatcher>(); - QObject::connect(watcher, &QFutureWatcher>::finished, [watcher]() { - for (const Interpreter &interpreter : watcher->result()) { - if (!alreadyRegistered(interpreter)) - settingsInstance->addInterpreter(interpreter); - } - watcher->deleteLater(); - }); - watcher->setFuture(Utils::asyncRun(pythonsFromPath)); -} - -static void scanRegistry() -{ - auto watcher = new QFutureWatcher>(); - QObject::connect(watcher, &QFutureWatcher>::finished, [watcher]() { - for (const Interpreter &interpreter : watcher->result()) { - if (!alreadyRegistered(interpreter)) - settingsInstance->addInterpreter(interpreter); - } - watcher->deleteLater(); - scanPath(); - }); - watcher->setFuture(Utils::asyncRun(pythonsFromRegistry)); -} - -static void scanSystemForInterpreters() -{ - if (Utils::HostOsInfo::isWindowsHost()) - scanRegistry(); - else - scanPath(); -} - PythonSettings::PythonSettings() { QTC_ASSERT(!settingsInstance, return); @@ -777,7 +751,32 @@ PythonSettings::PythonSettings() initFromSettings(Core::ICore::settings()); - scanSystemForInterpreters(); + const auto onRegistrySetup = [](Async> &task) { + task.setFutureSynchronizer(ExtensionSystem::PluginManager::futureSynchronizer()); + task.setConcurrentCallData(pythonsFromRegistry); + }; + const auto onPathSetup = [](Async> &task) { + task.setFutureSynchronizer(ExtensionSystem::PluginManager::futureSynchronizer()); + task.setConcurrentCallData(pythonsFromPath); + }; + const auto onTaskDone = [](const Async> &task) { + if (!task.isResultAvailable()) + return; + + const auto interpreters = task.result(); + for (const Interpreter &interpreter : interpreters) { + if (!alreadyRegistered(interpreter)) + settingsInstance->addInterpreter(interpreter); + } + }; + + const Tasking::Group recipe { + Tasking::finishAllAndSuccess, + Utils::HostOsInfo::isWindowsHost() + ? AsyncTask>(onRegistrySetup, onTaskDone) : Tasking::GroupItem({}), + AsyncTask>(onPathSetup, onTaskDone) + }; + m_taskTreeRunner.start(recipe); if (m_defaultInterpreterId.isEmpty()) m_defaultInterpreterId = idForPythonFromPath(m_interpreters); diff --git a/src/plugins/python/pythonsettings.h b/src/plugins/python/pythonsettings.h index 892069431d5..ab5d092a5ff 100644 --- a/src/plugins/python/pythonsettings.h +++ b/src/plugins/python/pythonsettings.h @@ -5,6 +5,8 @@ #include +#include + #include namespace Python::Internal { @@ -69,6 +71,7 @@ private: QString m_defaultInterpreterId; bool m_pylsEnabled = true; QString m_pylsConfiguration; + Tasking::TaskTreeRunner m_taskTreeRunner; static void saveSettings(); };