From f38d08fc42de985f290eedaa7a21127aae633fe3 Mon Sep 17 00:00:00 2001 From: hjk Date: Tue, 27 Jun 2023 16:49:59 +0200 Subject: [PATCH] Qmake: Rudimentary support for prompt() in .pro file This is good enough to open Qt5's toplevel .pro, but not much more. Ideally, prompt() should not be used in files that are meant to be used non-interactively. Task-number: QTCREATORBUG-18220 Change-Id: I842d3c1a8c742d55cbe89a8d0980f34d179ec011 Reviewed-by: Eike Ziller --- src/plugins/qtsupport/qtsupportplugin.cpp | 32 +++++++++++++++++ src/shared/proparser/qmakebuiltins.cpp | 44 +++++++++++++++++------ src/shared/proparser/qmakeevaluator.h | 5 +++ 3 files changed, 70 insertions(+), 11 deletions(-) diff --git a/src/plugins/qtsupport/qtsupportplugin.cpp b/src/plugins/qtsupport/qtsupportplugin.cpp index 41c88d18e36..497390045b5 100644 --- a/src/plugins/qtsupport/qtsupportplugin.cpp +++ b/src/plugins/qtsupport/qtsupportplugin.cpp @@ -35,6 +35,8 @@ #include #include +#include + using namespace Core; using namespace Utils; using namespace ProjectExplorer; @@ -94,6 +96,36 @@ void QtSupportPlugin::initialize() { theProcessRunner() = processRunnerCallback; + thePrompter() = [this](const QString &msg, const QStringList &context) -> std::optional { + std::optional res; + QEventLoop loop; + + QMetaObject::invokeMethod(this, [msg, context, &res, &loop] { + QString text; + if (!context.isEmpty()) { + text = "Preceding lines:
   ..." + + context.join("
   ") + + "

"; + } + text += msg; + bool ok = false; + const QString line = QInputDialog::getText( + ICore::dialogParent(), + /*title*/ "QMake Prompt", + /*label*/ text, + /*echo mode*/ QLineEdit::Normal, + /*text*/ QString(), + /*ok*/ &ok, + /*flags*/ Qt::WindowFlags(), + /*QInputMethodHints*/ Qt::ImhNone); + if (ok) + res = line; + loop.quit(); + }, Qt::QueuedConnection); + loop.exec(QEventLoop::ExcludeUserInputEvents); + return res; + }; + QMakeParser::initialize(); ProFileEvaluator::initialize(); new ProFileCacheManager(this); diff --git a/src/shared/proparser/qmakebuiltins.cpp b/src/shared/proparser/qmakebuiltins.cpp index 87707106e61..505b4cf9895 100644 --- a/src/shared/proparser/qmakebuiltins.cpp +++ b/src/shared/proparser/qmakebuiltins.cpp @@ -441,6 +441,13 @@ QMAKE_EXPORT std::function &theProcessRunner() return runner; } +QMAKE_EXPORT std::function(const QString &, const QStringList &)> + &thePrompter() +{ + static std::function(const QString &, const QStringList &)> prompter; + return prompter; +} + void QMakeEvaluator::runProcessHelper(ProcessData *data) const { const QString root = deviceRoot(); @@ -1161,12 +1168,12 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateBuiltinExpand( } } break; -#ifdef PROEVALUATOR_FULL +//#ifdef PROEVALUATOR_FULL case E_PROMPT: { if (args.count() != 1 && args.count() != 2) { evalError(fL1S("prompt(question, [decorate=true]) requires one or two arguments.")); -// } else if (currentFileName() == QLatin1String("-")) { -// evalError(fL1S("prompt(question) cannot be used when '-o -' is used")); + } else if (currentFileName() == QLatin1String("-")) { + evalError(fL1S("prompt(question) cannot be used when '-o -' is used")); } else { QString msg = m_option->expandEnvVars(args.at(0).toQString(m_tmp1)); bool decorate = true; @@ -1179,20 +1186,32 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateBuiltinExpand( } else { fputs(qPrintable(msg), stderr); } - QFile qfile; - if (qfile.open(stdin, QIODevice::ReadOnly)) { - QTextStream t(&qfile); - const QString &line = t.readLine(); - if (t.atEnd()) { + + if (thePrompter()) { + std::optional line = thePrompter()(msg, m_logBuffer); + m_logBuffer.clear(); + if (!line) { fputs("\n", stderr); evalError(fL1S("Unexpected EOF.")); return ReturnError; } - ret = split_value_list(QStringView(line)); - } + ret = split_value_list(QStringView(*line)); + } else { + QFile qfile; + if (qfile.open(stdin, QIODevice::ReadOnly)) { + QTextStream t(&qfile); + const QString &line = t.readLine(); + if (t.atEnd()) { + fputs("\n", stderr); + evalError(fL1S("Unexpected EOF.")); + return ReturnError; + } + ret = split_value_list(QStringView(line)); + } + } } break; } -#endif +//#endif case E_REPLACE: if (args.count() != 3 ) { evalError(fL1S("replace(var, before, after) requires three arguments.")); @@ -1827,6 +1846,9 @@ QMakeEvaluator::VisitReturn QMakeEvaluator::evaluateBuiltinConditional( const QString &msg = m_option->expandEnvVars(args.at(0).toQString(m_tmp2)); if (!m_skipLevel) { if (func_t == T_LOG) { + m_logBuffer.append(msg); + if (m_logBuffer.size() > 15) + m_logBuffer.takeFirst(); #ifdef PROEVALUATOR_FULL fputs(msg.toLatin1().constData(), stderr); #endif diff --git a/src/shared/proparser/qmakeevaluator.h b/src/shared/proparser/qmakeevaluator.h index da681b3bbe6..a3d7438d829 100644 --- a/src/shared/proparser/qmakeevaluator.h +++ b/src/shared/proparser/qmakeevaluator.h @@ -48,6 +48,10 @@ public: QT_BEGIN_NAMESPACE QMAKE_EXPORT std::function &theProcessRunner(); + +QMAKE_EXPORT std::function(const QString &, const QStringList &)> & + thePrompter(); + QMAKE_EXPORT QString removeHostAndScheme(const QString &remotePath); class QMakeGlobals; @@ -296,6 +300,7 @@ public: QStringList m_qmakepath; QStringList m_qmakefeatures; QStringList m_mkspecPaths; + QStringList m_logBuffer; QExplicitlySharedDataPointer m_featureRoots; ProString m_dirSep; ProFunctionDefs m_functionDefs;