File indexing completed on 2024-04-28 05:52:25
0001 /* 0002 * Copyright 2010-2012 Bart Kroon <bart@tarmack.eu> 0003 * 0004 * Redistribution and use in source and binary forms, with or without 0005 * modification, are permitted provided that the following conditions 0006 * are met: 0007 * 0008 * 1. Redistributions of source code must retain the above copyright 0009 * notice, this list of conditions and the following disclaimer. 0010 * 2. Redistributions in binary form must reproduce the above copyright 0011 * notice, this list of conditions and the following disclaimer in the 0012 * documentation and/or other materials provided with the distribution. 0013 * 0014 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 0015 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 0016 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 0017 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 0018 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 0019 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 0020 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 0021 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 0022 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 0023 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 0024 */ 0025 0026 #include "Shell.h" 0027 0028 #include <stdlib.h> 0029 #include <QDBusInterface> 0030 #include <QDir> 0031 #include <klocalizedstring.h> 0032 #include <QDebug> 0033 #include <QProcess> 0034 #include <QDateTime> 0035 #include <QFileSystemWatcher> 0036 0037 void Shell::walkDir(QString path) 0038 { 0039 QDir dir = QDir(QFileInfo(path).canonicalFilePath()); 0040 QFileInfoList list = dir.entryInfoList(QStringList(), QDir::NoDotAndDotDot | QDir::Files); 0041 0042 for (const QFileInfo &file : list) { 0043 const QString canonicalPath = file.canonicalFilePath(); 0044 0045 if (file.isFile() && file.isExecutable()) { 0046 m_index[file.fileName()] = canonicalPath; 0047 m_modified[file.fileName()] = file.lastModified().toSecsSinceEpoch(); 0048 } 0049 } 0050 } 0051 0052 namespace 0053 { 0054 QStringList parsePathEnv() 0055 { 0056 QString pathEnv = getenv("PATH"); 0057 #if QT_VERSION < QT_VERSION_CHECK(5, 14, 0) 0058 QStringList pathList = pathEnv.split(":", QString::SkipEmptyParts); 0059 #else 0060 QStringList pathList = pathEnv.split(":", Qt::SkipEmptyParts); 0061 #endif 0062 QStringList absPathList; 0063 for (const QString &path : pathList) { 0064 const QString canonicalPath = QFileInfo(path).canonicalFilePath(); 0065 if (canonicalPath.isEmpty()) { 0066 continue; 0067 } 0068 absPathList.append(canonicalPath); 0069 } 0070 0071 absPathList.removeDuplicates(); 0072 return absPathList; 0073 } 0074 } 0075 0076 Shell::Shell(QObject *parent) : 0077 Provider(parent), 0078 m_fsWatcher(new QFileSystemWatcher(this)) 0079 { 0080 connect(m_fsWatcher, &QFileSystemWatcher::directoryChanged, this, &Shell::onDirectoryChanged); 0081 0082 for (const QString &dir : parsePathEnv()) { 0083 m_fsWatcher->addPath(dir); 0084 walkDir(dir); 0085 } 0086 } 0087 0088 Shell::~Shell() 0089 {} 0090 0091 QList<ProviderResult *> Shell::getResults(QString query) 0092 { 0093 QList<ProviderResult*> list; 0094 0095 QString command; 0096 QString args; 0097 0098 if (query.contains(' ')) { 0099 command = query.left(query.indexOf(" ")); 0100 args = query.right(query.length() - query.indexOf(" ")); 0101 } else { 0102 command = query; 0103 } 0104 0105 const qint64 currentSecsSinceEpoch = QDateTime::currentSecsSinceEpoch(); 0106 QHashIterator<QString, QString> iterator(this->m_index); 0107 while (iterator.hasNext()) { 0108 iterator.next(); 0109 0110 if (!iterator.key().startsWith(command, Qt::CaseInsensitive)) { 0111 continue; 0112 } 0113 0114 ProviderResult *app = new ProviderResult; 0115 app->name = iterator.value() + args; 0116 app->completion = iterator.key(); 0117 app->icon = "system-run"; 0118 app->object = this; 0119 app->program = iterator.value() + args; 0120 app->type = i18n("Shell command"); 0121 0122 app->priority = currentSecsSinceEpoch - m_modified[iterator.key()]; 0123 0124 list.append(app); 0125 } 0126 return list; 0127 } 0128 0129 int Shell::launch(const QString &exec) 0130 { 0131 #if QT_VERSION < QT_VERSION_CHECK(5, 15, 0) 0132 QStringList args = exec.split(" "); 0133 #else 0134 QStringList args = QProcess::splitCommand(exec); 0135 #endif 0136 if (args.isEmpty()) { 0137 qWarning() << "Asked to launch invalid program:" << exec; 0138 return 0; 0139 } 0140 QString program(args.takeFirst()); 0141 QProcess::startDetached(program, args); 0142 return 0; 0143 } 0144 0145 void Shell::onDirectoryChanged(const QString &path) 0146 { 0147 // First remove the old 0148 QStringList toRemove; 0149 for (const QString &fullProgramPath : m_index.values()) { 0150 if (!fullProgramPath.startsWith(path)) { 0151 continue; 0152 } 0153 0154 QFileInfo programInfo(fullProgramPath); 0155 if (programInfo.dir().path() == path) { 0156 toRemove.append(programInfo.fileName()); 0157 } 0158 } 0159 0160 // Too lazy to use an iterator 0161 for (const QString &program : toRemove) { 0162 m_index.remove(program); 0163 m_modified.remove(program); 0164 } 0165 0166 // Then re-index the path 0167 walkDir(path); 0168 } 0169 0170 0171 // kate: indent-mode cstyle; space-indent on; indent-width 4;