File indexing completed on 2024-05-19 13:25:27
0001 /* 0002 SPDX-FileCopyrightText: 2006 Aaron Seigo <aseigo@kde.org> 0003 SPDX-FileCopyrightText: 2016 Kai Uwe Broulik <kde@privat.broulik.de> 0004 SPDX-FileCopyrightText: 2020-2021 Alexander Lohnau <alexander.lonau@gmx.de> 0005 0006 SPDX-License-Identifier: LGPL-2.0-only 0007 */ 0008 0009 #include "shellrunner.h" 0010 0011 #include <KAuthorized> 0012 #include <KLocalizedString> 0013 #include <KNotificationJobUiDelegate> 0014 #include <KShell> 0015 #include <KTerminalLauncherJob> 0016 #include <QAction> 0017 #include <QProcessEnvironment> 0018 #include <QRegularExpression> 0019 #include <QStandardPaths> 0020 0021 #include <KIO/CommandLauncherJob> 0022 0023 K_PLUGIN_CLASS_WITH_JSON(ShellRunner, "plasma-runner-shell.json") 0024 0025 ShellRunner::ShellRunner(QObject *parent, const KPluginMetaData &metaData, const QVariantList &args) 0026 : Plasma::AbstractRunner(parent, metaData, args) 0027 { 0028 setObjectName(QStringLiteral("Command")); 0029 // The results from the services runner are preferred, consequently we set a low priority 0030 setPriority(AbstractRunner::LowestPriority); 0031 // If the runner is not authorized we can suspend it 0032 bool enabled = KAuthorized::authorize(QStringLiteral("run_command")) && KAuthorized::authorize(KAuthorized::SHELL_ACCESS); 0033 suspendMatching(!enabled); 0034 0035 addSyntax(Plasma::RunnerSyntax(QStringLiteral(":q:"), i18n("Finds commands that match :q:, using common shell syntax"))); 0036 m_actionList = {new QAction(QIcon::fromTheme(QStringLiteral("utilities-terminal")), i18n("Run in Terminal Window"), this)}; 0037 m_matchIcon = QIcon::fromTheme(QStringLiteral("system-run")); 0038 } 0039 0040 ShellRunner::~ShellRunner() 0041 { 0042 } 0043 0044 void ShellRunner::match(Plasma::RunnerContext &context) 0045 { 0046 QStringList envs; 0047 std::optional<QString> parsingResult = parseShellCommand(context.query(), envs); 0048 if (parsingResult.has_value()) { 0049 const QString command = parsingResult.value(); 0050 Plasma::QueryMatch match(this); 0051 match.setId(QStringLiteral("exec://") + command); 0052 match.setType(Plasma::QueryMatch::ExactMatch); 0053 match.setIcon(m_matchIcon); 0054 match.setText(i18n("Run %1", context.query())); 0055 match.setData(QVariantList({command, envs})); 0056 match.setRelevance(0.7); 0057 match.setActions(m_actionList); 0058 context.addMatch(match); 0059 } 0060 } 0061 0062 void ShellRunner::run(const Plasma::RunnerContext &context, const Plasma::QueryMatch &match) 0063 { 0064 if (match.selectedAction()) { 0065 const QVariantList data = match.data().toList(); 0066 const QStringList list = data.at(1).toStringList(); 0067 QProcessEnvironment env = QProcessEnvironment::systemEnvironment(); 0068 for (const auto &str : list) { 0069 const int pos = str.indexOf('='); 0070 env.insert(str.left(pos), str.mid(pos + 1)); 0071 } 0072 auto job = new KTerminalLauncherJob(data.at(0).toString()); 0073 job->setProcessEnvironment(env); 0074 job->setUiDelegate(new KNotificationJobUiDelegate(KJobUiDelegate::AutoHandlingEnabled)); 0075 job->start(); 0076 return; 0077 } 0078 0079 auto *job = new KIO::CommandLauncherJob(context.query()); // The job can handle the env parameters 0080 job->setUiDelegate(new KNotificationJobUiDelegate(KJobUiDelegate::AutoHandlingEnabled)); 0081 job->start(); 0082 } 0083 0084 std::optional<QString> ShellRunner::parseShellCommand(const QString &query, QStringList &envs) 0085 { 0086 const static QRegularExpression envRegex = QRegularExpression(QStringLiteral("^.+=.+$")); 0087 const QStringList split = KShell::splitArgs(query); 0088 for (const auto &entry : split) { 0089 const QString executablePath = QStandardPaths::findExecutable(KShell::tildeExpand(entry)); 0090 if (!executablePath.isEmpty()) { 0091 QStringList executableParts{executablePath}; 0092 executableParts << split.mid(split.indexOf(entry) + 1); 0093 return KShell::joinArgs(executableParts); 0094 } else if (envRegex.match(entry).hasMatch()) { 0095 envs.append(entry); 0096 } else { 0097 return std::nullopt; 0098 } 0099 } 0100 return std::nullopt; 0101 } 0102 0103 #include "shellrunner.moc"