File indexing completed on 2024-05-19 05:28:21

0001 /*
0002     This file is part of Konsole QML plugin,
0003     which is a terminal emulator from KDE.
0004 
0005     SPDX-FileCopyrightText: 2013 Dmitry Zagnoyko <hiroshidi@gmail.com>
0006 
0007     SPDX-License-Identifier: GPL-2.0-or-later
0008 
0009     This program is distributed in the hope that it will be useful,
0010     but WITHOUT ANY WARRANTY; without even the implied warranty of
0011     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
0012     GNU General Public License for more details.
0013 
0014     You should have received a copy of the GNU General Public License
0015     along with this program; if not, write to the Free Software
0016     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
0017     02110-1301  USA.
0018 */
0019 
0020 // Own
0021 #include "TerminalSession.h"
0022 
0023 // Qt
0024 #include <QTextCodec>
0025 
0026 // Konsole
0027 #include "HistorySearch.h"
0028 #include "KeyboardTranslator.h"
0029 
0030 TerminalSession::TerminalSession(QObject *parent)
0031     : QObject(parent)
0032     , m_session(createSession(QString()))
0033 {
0034     connect(m_session.get(), &Konsole::Session::started, this, &TerminalSession::started);
0035     connect(m_session.get(), &Konsole::Session::finished, this, &TerminalSession::sessionFinished);
0036     connect(m_session.get(), &Konsole::Session::titleChanged, this, &TerminalSession::titleChanged);
0037 }
0038 
0039 TerminalSession::~TerminalSession()
0040 {
0041     if (m_session) {
0042         m_session->close();
0043         m_session->disconnect();
0044     }
0045 }
0046 
0047 void TerminalSession::setTitle(QString name)
0048 {
0049     m_session->setTitle(Session::NameRole, name);
0050 }
0051 
0052 std::unique_ptr<Session> TerminalSession::createSession(QString name)
0053 {
0054     auto session = std::make_unique<Session>();
0055 
0056     session->setTitle(Session::NameRole, name);
0057 
0058     /* Thats a freaking bad idea!!!!
0059      * /bin/bash is not there on every system
0060      * better set it to the current $SHELL
0061      * Maybe you can also make a list available and then let the widget-owner decide what to use.
0062      * By setting it to $SHELL right away we actually make the first filecheck obsolete.
0063      * But as iam not sure if you want to do anything else ill just let both checks in and set this to $SHELL anyway.
0064      */
0065 
0066     // cool-old-term: There is another check in the code. Not sure if useful.
0067 
0068     QString envshell = qEnvironmentVariable("SHELL");
0069     QString shellProg = !envshell.isNull() ? envshell : QStringLiteral("/bin/bash");
0070     session->setProgram(shellProg);
0071 
0072     setenv("TERM", "xterm", 1);
0073 
0074     // session->setProgram();
0075 
0076     QStringList args;
0077     session->setArguments(args);
0078     session->setAutoClose(true);
0079 
0080     session->setCodec(QTextCodec::codecForName("UTF-8"));
0081 
0082     session->setFlowControlEnabled(true);
0083     session->setHistoryType(HistoryTypeBuffer(1000));
0084 
0085     session->setDarkBackground(true);
0086 
0087     session->setKeyBindings(QString());
0088 
0089     return session;
0090 }
0091 
0092 /////////////////////////////////////////////////////////////////////////////////////
0093 /////////////////////////////////////////////////////////////////////////////////////
0094 
0095 int TerminalSession::getRandomSeed()
0096 {
0097     return m_session->sessionId() * 31;
0098 }
0099 
0100 void TerminalSession::addView(TerminalDisplay *display)
0101 {
0102     m_session->setView(display);
0103 }
0104 
0105 void TerminalSession::removeView(TerminalDisplay *display)
0106 {
0107     m_session->removeView(display);
0108 }
0109 
0110 void TerminalSession::sessionFinished()
0111 {
0112     Q_EMIT finished();
0113 }
0114 
0115 void TerminalSession::selectionChanged(bool textSelected)
0116 {
0117     Q_UNUSED(textSelected)
0118 }
0119 
0120 void TerminalSession::startShellProgram()
0121 {
0122     if (m_session->isRunning()) {
0123         return;
0124     }
0125 
0126     m_session->run();
0127 }
0128 
0129 bool TerminalSession::sendSignal(int signal)
0130 {
0131     if (!m_session->isRunning()) {
0132         return false;
0133     }
0134 
0135     return m_session->sendSignal(signal);
0136 }
0137 
0138 int TerminalSession::getShellPID()
0139 {
0140     return m_session->processId();
0141 }
0142 
0143 void TerminalSession::changeDir(const QString &dir)
0144 {
0145     /*
0146        this is a very hackish way of trying to determine if the shell is in
0147        the foreground before attempting to change the directory.  It may not
0148        be portable to anything other than Linux.
0149     */
0150     QString strCmd;
0151     strCmd.setNum(getShellPID());
0152     strCmd.prepend(u"ps -j ");
0153     strCmd.append(u" | tail -1 | awk '{ print $5 }' | grep -q \\+");
0154     int retval = system(strCmd.toStdString().c_str());
0155 
0156     if (!retval) {
0157         QString cmd = QStringLiteral(u"cd ") + dir + QStringLiteral("\n");
0158         sendText(cmd);
0159     }
0160 }
0161 
0162 void TerminalSession::setEnvironment(const QStringList &environment)
0163 {
0164     m_session->setEnvironment(environment);
0165 }
0166 
0167 QString TerminalSession::shellProgram() const
0168 {
0169     return m_session->program();
0170 }
0171 
0172 void TerminalSession::setShellProgram(const QString &progname)
0173 {
0174     m_session->setProgram(progname);
0175     Q_EMIT shellProgramChanged();
0176 }
0177 
0178 void TerminalSession::setInitialWorkingDirectory(const QString &dir)
0179 {
0180     if (_initialWorkingDirectory != dir) {
0181         _initialWorkingDirectory = dir;
0182         m_session->setInitialWorkingDirectory(dir);
0183         Q_EMIT initialWorkingDirectoryChanged();
0184     }
0185 }
0186 
0187 QString TerminalSession::getInitialWorkingDirectory()
0188 {
0189     return _initialWorkingDirectory;
0190 }
0191 
0192 QStringList TerminalSession::args() const
0193 {
0194     return m_session->arguments();
0195 }
0196 
0197 void TerminalSession::setArgs(const QStringList &args)
0198 {
0199     m_session->setArguments(args);
0200     Q_EMIT argsChanged();
0201 }
0202 
0203 void TerminalSession::setTextCodec(QTextCodec *codec)
0204 {
0205     m_session->setCodec(codec);
0206 }
0207 
0208 void TerminalSession::setHistorySize(int lines)
0209 {
0210     if (historySize() != lines) {
0211         if (lines < 0)
0212             m_session->setHistoryType(HistoryTypeFile());
0213         else
0214             m_session->setHistoryType(HistoryTypeBuffer(lines));
0215         Q_EMIT historySizeChanged();
0216     }
0217 }
0218 
0219 int TerminalSession::historySize() const
0220 {
0221     if (m_session->historyType().isUnlimited()) {
0222         return -1;
0223     } else {
0224         return m_session->historyType().maximumLineCount();
0225     }
0226 }
0227 
0228 QString TerminalSession::getHistory() const
0229 {
0230     QString history;
0231     QTextStream historyStream(&history);
0232     PlainTextDecoder historyDecoder;
0233 
0234     historyDecoder.begin(&historyStream);
0235     m_session->emulation()->writeToStream(&historyDecoder);
0236     historyDecoder.end();
0237 
0238     return history;
0239 }
0240 
0241 void TerminalSession::sendText(QString text)
0242 {
0243     m_session->sendText(text);
0244 }
0245 
0246 void TerminalSession::sendKey(int, int, int) const
0247 {
0248     // TODO implement or remove this function.
0249     //    Qt::KeyboardModifier kbm = Qt::KeyboardModifier(mod);
0250 
0251     //    QKeyEvent qkey(QEvent::KeyPress, key, kbm);
0252 
0253     //    while (rep > 0){
0254     //        m_session->sendKey(&qkey);
0255     //        --rep;
0256     //    }
0257 }
0258 
0259 void TerminalSession::clearScreen()
0260 {
0261     m_session->emulation()->clearEntireScreen();
0262 }
0263 
0264 void TerminalSession::search(const QString &regexp, int startLine, int startColumn, bool forwards)
0265 {
0266     HistorySearch *history = new HistorySearch(QPointer<Emulation>(m_session->emulation()), QRegExp(regexp), forwards, startColumn, startLine, this);
0267     connect(history, &HistorySearch::matchFound, this, &TerminalSession::matchFound);
0268     connect(history, &HistorySearch::noMatchFound, this, &TerminalSession::noMatchFound);
0269     history->search();
0270 }
0271 
0272 void TerminalSession::setFlowControlEnabled(bool enabled)
0273 {
0274     m_session->setFlowControlEnabled(enabled);
0275 }
0276 
0277 bool TerminalSession::flowControlEnabled()
0278 {
0279     return m_session->flowControlEnabled();
0280 }
0281 
0282 void TerminalSession::setKeyBindings(const QString &kb)
0283 {
0284     m_session->setKeyBindings(kb);
0285     Q_EMIT changedKeyBindings(kb);
0286 }
0287 
0288 QString TerminalSession::getKeyBindings()
0289 {
0290     return m_session->keyBindings();
0291 }
0292 
0293 QStringList TerminalSession::availableKeyBindings()
0294 {
0295     return KeyboardTranslatorManager::instance()->allTranslators();
0296 }
0297 
0298 QString TerminalSession::keyBindings()
0299 {
0300     return m_session->keyBindings();
0301 }
0302 
0303 QString TerminalSession::getTitle()
0304 {
0305     return m_session->userTitle();
0306 }
0307 
0308 bool TerminalSession::hasActiveProcess() const
0309 {
0310     return m_session->processId() != m_session->foregroundProcessId();
0311 }
0312 
0313 QString TerminalSession::foregroundProcessName()
0314 {
0315     return m_session->foregroundProcessName();
0316 }
0317 
0318 QString TerminalSession::currentDir()
0319 {
0320     return m_session->currentDir();
0321 }