WebAssembly: Improve browser selection combobox of run configuation

This adds a "Default Browser" entry to the browser selection combobox in
WebAssembly' run configuration. Choosing that omits the "--browser"
parameter and let's emrun determine which browser to launch (should by
the system default browser).

In order to implement that, the combobox items now got user data in
addition to have display data. The parsing of emrun's output was
extended to retrieve the long form of a browser name as display data:
"Mozilla Firefox 96.0.0.8041" instead of just "firefox".
The parsing of emrun's outout received a dedicated plugin test.

Turning the result in parseEmrunOutput() non-static fixed
QTCREATORBUG-26562

Fixes: QTCREATORBUG-25028
Fixes: QTCREATORBUG-26559
Change-Id: I18891b88b063903d1a9eeb88a6c906e596e561c1
Reviewed-by: <github-actions-qt-creator@cristianadam.eu>
Reviewed-by: Alessandro Portale <alessandro.portale@qt.io>
This commit is contained in:
Alessandro Portale
2022-01-12 22:55:10 +01:00
parent 4d9245b001
commit 0bbc465f61
4 changed files with 118 additions and 41 deletions

View File

@@ -49,6 +49,8 @@ public:
private slots: private slots:
void testEmSdkEnvParsing(); void testEmSdkEnvParsing();
void testEmSdkEnvParsing_data(); void testEmSdkEnvParsing_data();
void testEmrunBrowserListParsing();
void testEmrunBrowserListParsing_data();
#endif // WITH_TESTS #endif // WITH_TESTS
}; };

View File

@@ -66,14 +66,18 @@ static CommandLine emrunCommand(const RunConfiguration *rc, const QString &brows
const FilePath target = rc->buildTargetInfo().targetFilePath; const FilePath target = rc->buildTargetInfo().targetFilePath;
const FilePath html = target.absolutePath() / target.baseName() + ".html"; const FilePath html = target.absolutePath() / target.baseName() + ".html";
return CommandLine(pythonInterpreter(env), { QStringList args(emrunPy.path());
emrunPy.path(), if (!browser.isEmpty()) {
"--browser", browser, args.append("--browser");
"--port", port, args.append(browser);
"--no_emrun_detect", }
"--serve_after_close", args.append("--port");
html.toString() args.append(port);
}); args.append("--no_emrun_detect");
args.append("--serve_after_close");
args.append(html.toString());
return CommandLine(pythonInterpreter(env), args);
} }
return {}; return {};
} }
@@ -99,6 +103,7 @@ public:
"<port>").toUserOutput()); "<port>").toUserOutput());
}); });
connect(webBrowserAspect, &BaseAspect::changed, this, &RunConfiguration::update);
connect(target, &Target::buildSystemUpdated, this, &RunConfiguration::update); connect(target, &Target::buildSystemUpdated, this, &RunConfiguration::update);
} }
}; };
@@ -114,8 +119,10 @@ public:
setStarter([this, runControl, portsGatherer] { setStarter([this, runControl, portsGatherer] {
Runnable r; Runnable r;
const QString browserId =
runControl->aspect<WebBrowserSelectionAspect>()->currentBrowser();
r.command = emrunCommand(runControl->runConfiguration(), r.command = emrunCommand(runControl->runConfiguration(),
runControl->aspect<WebBrowserSelectionAspect>()->currentBrowser(), browserId,
QString::number(portsGatherer->findEndPoint().port())); QString::number(portsGatherer->findEndPoint().port()));
SimpleTargetRunner::doStart(r, {}); SimpleTargetRunner::doStart(r, {});
}); });

View File

@@ -34,6 +34,11 @@
#include <QComboBox> #include <QComboBox>
#ifdef WITH_TESTS
# include <QTest>
# include "webassemblyplugin.h"
#endif // WITH_TESTS
using namespace Utils; using namespace Utils;
namespace WebAssembly { namespace WebAssembly {
@@ -41,10 +46,24 @@ namespace Internal {
static const char BROWSER_KEY[] = "WASM.WebBrowserSelectionAspect.Browser"; static const char BROWSER_KEY[] = "WASM.WebBrowserSelectionAspect.Browser";
static QStringList detectedBrowsers(ProjectExplorer::Target *target) static WebBrowserEntries parseEmrunOutput(const QByteArray &output)
{ {
static QStringList result; WebBrowserEntries result;
if (result.isEmpty()) { QTextStream ts(output);
QString line;
const QRegularExpression regExp(" - (.*):(.*)");
while (ts.readLineInto(&line)) {
const QRegularExpressionMatch match = regExp.match(line);
if (match.hasMatch())
result << qMakePair(match.captured(1), match.captured(2).trimmed());
}
return result;
}
static WebBrowserEntries emrunBrowsers(ProjectExplorer::Target *target)
{
WebBrowserEntries result;
result.append(qMakePair(QString(), WebBrowserSelectionAspect::tr("Default Browser")));
if (auto bc = target->activeBuildConfiguration()) { if (auto bc = target->activeBuildConfiguration()) {
const Utils::Environment environment = bc->environment(); const Utils::Environment environment = bc->environment();
const Utils::FilePath emrunPath = environment.searchInPath("emrun"); const Utils::FilePath emrunPath = environment.searchInPath("emrun");
@@ -54,27 +73,19 @@ static QStringList detectedBrowsers(ProjectExplorer::Target *target)
browserLister.setCommand({emrunPath, {"--list_browsers"}}); browserLister.setCommand({emrunPath, {"--list_browsers"}});
browserLister.start(); browserLister.start();
if (browserLister.waitForFinished()) { if (browserLister.waitForFinished())
const QByteArray output = browserLister.readAllStandardOutput(); result.append(parseEmrunOutput(browserLister.readAllStandardOutput()));
QTextStream ts(output);
QString line;
const QRegularExpression regExp(" - (.*):.*");
while (ts.readLineInto(&line)) {
const QRegularExpressionMatch match = regExp.match(line);
if (match.hasMatch())
result << match.captured(1);
}
}
}
} }
return result; return result;
} }
WebBrowserSelectionAspect::WebBrowserSelectionAspect(ProjectExplorer::Target *target) WebBrowserSelectionAspect::WebBrowserSelectionAspect(ProjectExplorer::Target *target)
: m_availableBrowsers(detectedBrowsers(target)) : m_availableBrowsers(emrunBrowsers(target))
{ {
if (!m_availableBrowsers.isEmpty()) if (!m_availableBrowsers.isEmpty()) {
m_currentBrowser = m_availableBrowsers.first(); const int defaultIndex = qBound(0, m_availableBrowsers.count() - 1, 1);
m_currentBrowser = m_availableBrowsers.at(defaultIndex).first;
}
setDisplayName(tr("Web Browser")); setDisplayName(tr("Web Browser"));
setId("WebBrowserAspect"); setId("WebBrowserAspect");
setSettingsKey("RunConfiguration.WebBrowser"); setSettingsKey("RunConfiguration.WebBrowser");
@@ -84,11 +95,12 @@ void WebBrowserSelectionAspect::addToLayout(LayoutBuilder &builder)
{ {
QTC_CHECK(!m_webBrowserComboBox); QTC_CHECK(!m_webBrowserComboBox);
m_webBrowserComboBox = new QComboBox; m_webBrowserComboBox = new QComboBox;
m_webBrowserComboBox->addItems(m_availableBrowsers); for (const WebBrowserEntry &be : m_availableBrowsers)
m_webBrowserComboBox->setCurrentText(m_currentBrowser); m_webBrowserComboBox->addItem(be.second, be.first);
connect(m_webBrowserComboBox, &QComboBox::currentTextChanged, m_webBrowserComboBox->setCurrentIndex(m_webBrowserComboBox->findData(m_currentBrowser));
[this](const QString &selectedBrowser){ connect(m_webBrowserComboBox, &QComboBox::currentIndexChanged,
m_currentBrowser = selectedBrowser; [this]() {
m_currentBrowser = m_webBrowserComboBox->currentData().toString();
emit changed(); emit changed();
}); });
builder.addItems({tr("Web browser:"), m_webBrowserComboBox}); builder.addItems({tr("Web browser:"), m_webBrowserComboBox});
@@ -97,7 +109,7 @@ void WebBrowserSelectionAspect::addToLayout(LayoutBuilder &builder)
void WebBrowserSelectionAspect::fromMap(const QVariantMap &map) void WebBrowserSelectionAspect::fromMap(const QVariantMap &map)
{ {
if (!m_availableBrowsers.isEmpty()) if (!m_availableBrowsers.isEmpty())
m_currentBrowser = map.value(BROWSER_KEY, m_availableBrowsers.first()).toString(); m_currentBrowser = map.value(BROWSER_KEY, m_availableBrowsers.first().first).toString();
} }
void WebBrowserSelectionAspect::toMap(QVariantMap &map) const void WebBrowserSelectionAspect::toMap(QVariantMap &map) const
@@ -110,5 +122,58 @@ QString WebBrowserSelectionAspect::currentBrowser() const
return m_currentBrowser; return m_currentBrowser;
} }
// Unit tests:
#ifdef WITH_TESTS
void testEmrunBrowserListParsing();
void testEmrunBrowserListParsing_data();
void WebAssemblyPlugin::testEmrunBrowserListParsing()
{
QFETCH(QByteArray, emrunOutput);
QFETCH(WebBrowserEntries, expectedBrowsers);
QCOMPARE(parseEmrunOutput(emrunOutput), expectedBrowsers);
}
void WebAssemblyPlugin::testEmrunBrowserListParsing_data()
{
QTest::addColumn<QByteArray>("emrunOutput");
QTest::addColumn<WebBrowserEntries>("expectedBrowsers");
QTest::newRow("emsdk 1.39.8")
// Output of "emrun --list_browsers"
<< QByteArray(
R"(emrun has automatically found the following browsers in the default install locations on the system:
- firefox: Mozilla Firefox
- chrome: Google Chrome
You can pass the --browser <id> option to launch with the given browser above.
Even if your browser was not detected, you can use --browser /path/to/browser/executable to launch with that browser.
)")
<< WebBrowserEntries({
qMakePair(QLatin1String("firefox"), QLatin1String("Mozilla Firefox")),
qMakePair(QLatin1String("chrome"), QLatin1String("Google Chrome"))});
QTest::newRow("emsdk 2.0.14")
<< QByteArray(
R"(emrun has automatically found the following browsers in the default install locations on the system:
- firefox: Mozilla Firefox 96.0.0.8041
- chrome: Google Chrome 97.0.4692.71
You can pass the --browser <id> option to launch with the given browser above.
Even if your browser was not detected, you can use --browser /path/to/browser/executable to launch with that browser.
)")
<< WebBrowserEntries({
qMakePair(QLatin1String("firefox"), QLatin1String("Mozilla Firefox 96.0.0.8041")),
qMakePair(QLatin1String("chrome"), QLatin1String("Google Chrome 97.0.4692.71"))});
}
#endif // WITH_TESTS
} // namespace Internal } // namespace Internal
} // namespace Webassembly } // namespace Webassembly

View File

@@ -32,6 +32,9 @@ QT_FORWARD_DECLARE_CLASS(QComboBox)
namespace WebAssembly { namespace WebAssembly {
namespace Internal { namespace Internal {
using WebBrowserEntry = QPair<QString, QString>; // first: id, second: display name
using WebBrowserEntries = QList<WebBrowserEntry>;
class WebBrowserSelectionAspect : public Utils::BaseAspect class WebBrowserSelectionAspect : public Utils::BaseAspect
{ {
Q_OBJECT Q_OBJECT
@@ -49,7 +52,7 @@ public:
private: private:
QComboBox *m_webBrowserComboBox = nullptr; QComboBox *m_webBrowserComboBox = nullptr;
QString m_currentBrowser; QString m_currentBrowser;
QStringList m_availableBrowsers; const WebBrowserEntries m_availableBrowsers;
}; };
} // namespace Internal } // namespace Internal