/* SPDX-FileCopyrightText: 2006 Aaron Seigo SPDX-FileCopyrightText: 2016 Kai Uwe Broulik SPDX-FileCopyrightText: 2020-2021 Alexander Lohnau SPDX-License-Identifier: LGPL-2.0-only */ #include "shellrunner.h" #include #include #include #include #include #include #include #include #include #include K_PLUGIN_CLASS_WITH_JSON(ShellRunner, "plasma-runner-shell.json") ShellRunner::ShellRunner(QObject *parent, const KPluginMetaData &metaData) : KRunner::AbstractRunner(parent, metaData) , m_actionList{KRunner::Action(QStringLiteral("run-in-terminal"), QStringLiteral("utilities-terminal"), i18n("Run in Terminal Window"))} , m_matchIcon(QIcon::fromTheme(QStringLiteral("system-run"))) { // If the runner is not authorized we can suspend it bool enabled = KAuthorized::authorize(QStringLiteral("run_command")) && KAuthorized::authorize(KAuthorized::SHELL_ACCESS); suspendMatching(!enabled); addSyntax(QStringLiteral(":q:"), i18n("Finds commands that match :q:, using common shell syntax")); } void ShellRunner::match(KRunner::RunnerContext &context) { QStringList envs; std::optional parsingResult = parseShellCommand(context.query(), envs); if (parsingResult.has_value()) { const QString command = parsingResult.value(); KRunner::QueryMatch match(this); match.setId(QString(u"exec://" + command)); match.setCategoryRelevance(KRunner::QueryMatch::CategoryRelevance::Highest); match.setIcon(m_matchIcon); match.setText(i18n("Run %1", context.query())); match.setData(QVariantList({command, envs})); match.setRelevance(0.7); match.setActions(m_actionList); context.addMatch(match); } } void ShellRunner::run(const KRunner::RunnerContext &context, const KRunner::QueryMatch &match) { if (match.selectedAction()) { const QVariantList data = match.data().toList(); const QStringList list = data.at(1).toStringList(); QProcessEnvironment env = QProcessEnvironment::systemEnvironment(); for (const QString &str : list) { const int pos = str.indexOf(u'='); env.insert(str.left(pos), str.mid(pos + 1)); } auto job = new KTerminalLauncherJob(data.at(0).toString()); job->setProcessEnvironment(env); job->setUiDelegate(new KNotificationJobUiDelegate(KJobUiDelegate::AutoHandlingEnabled)); job->start(); return; } auto *job = new KIO::CommandLauncherJob(context.query()); // The job can handle the env parameters job->setUiDelegate(new KNotificationJobUiDelegate(KJobUiDelegate::AutoHandlingEnabled)); job->start(); } std::optional ShellRunner::parseShellCommand(const QString &query, QStringList &envs) { const static QRegularExpression envRegex = QRegularExpression(QStringLiteral("^.+=.+$")); const QStringList split = KShell::splitArgs(query); for (const auto &entry : split) { const QString executablePath = QStandardPaths::findExecutable(KShell::tildeExpand(entry)); if (!executablePath.isEmpty()) { QStringList executableParts{executablePath}; executableParts << split.mid(split.indexOf(entry) + 1); return KShell::joinArgs(executableParts); } else if (envRegex.match(entry).hasMatch()) { envs.append(entry); } else { return std::nullopt; } } return std::nullopt; } #include "shellrunner.moc"