File indexing completed on 2023-10-01 07:35:56
0001 /* 0002 SPDX-License-Identifier: GPL-2.0-or-later 0003 SPDX-FileCopyrightText: 2009 Alexander Rieder <alexanderrieder@gmail.com> 0004 SPDX-FileCopyrightText: 2018 Alexander Semke <alexander.semke@web.de> 0005 */ 0006 0007 #include "rsession.h" 0008 #include "rexpression.h" 0009 #include "rcompletionobject.h" 0010 #include "rhighlighter.h" 0011 #include "rvariablemodel.h" 0012 #include <defaultvariablemodel.h> 0013 0014 #include <QTimer> 0015 #include <QDebug> 0016 #include <KProcess> 0017 0018 #ifndef Q_OS_WIN 0019 #include <signal.h> 0020 #endif 0021 0022 RSession::RSession(Cantor::Backend* backend) : Session(backend), 0023 m_process(nullptr), 0024 m_rServer(nullptr) 0025 { 0026 setVariableModel(new RVariableModel(this)); 0027 } 0028 0029 RSession::~RSession() 0030 { 0031 if (m_process) 0032 m_process->terminate(); 0033 } 0034 0035 void RSession::login() 0036 { 0037 qDebug()<<"login"; 0038 if (m_process) 0039 return; 0040 emit loginStarted(); 0041 0042 m_process = new QProcess(this); 0043 m_process->setProcessChannelMode(QProcess::ForwardedErrorChannel); 0044 #ifdef Q_OS_WIN 0045 m_process->start(QStandardPaths::findExecutable(QLatin1String("cantor_rserver.exe"))); 0046 #else 0047 m_process->start(QStandardPaths::findExecutable(QLatin1String("cantor_rserver"))); 0048 #endif 0049 0050 m_process->waitForStarted(); 0051 m_process->waitForReadyRead(); 0052 qDebug()<<m_process->readAllStandardOutput(); 0053 0054 m_rServer = new org::kde::Cantor::R(QString::fromLatin1("org.kde.Cantor.R-%1").arg(m_process->processId()), QLatin1String("/"), QDBusConnection::sessionBus(), this); 0055 0056 connect(m_rServer, &org::kde::Cantor::R::statusChanged, this, &RSession::serverChangedStatus); 0057 connect(m_rServer, &org::kde::Cantor::R::expressionFinished, this, &RSession::expressionFinished); 0058 connect(m_rServer, &org::kde::Cantor::R::inputRequested, this, &RSession::inputRequested); 0059 0060 changeStatus(Session::Done); 0061 emit loginDone(); 0062 qDebug()<<"login done"; 0063 } 0064 0065 void RSession::logout() 0066 { 0067 qDebug()<<"logout"; 0068 if (!m_process) 0069 return; 0070 0071 if(status() == Cantor::Session::Running) 0072 interrupt(); 0073 0074 m_process->kill(); 0075 m_process->deleteLater(); 0076 m_process = nullptr; 0077 0078 Session::logout(); 0079 } 0080 0081 void RSession::interrupt() 0082 { 0083 if(!expressionQueue().isEmpty()) 0084 { 0085 qDebug()<<"interrupting " << expressionQueue().first()->command(); 0086 if(m_process && m_process->state() != QProcess::NotRunning) 0087 { 0088 #ifndef Q_OS_WIN 0089 const int pid = m_process->processId(); 0090 kill(pid, SIGINT); 0091 #else 0092 ; //TODO: interrupt the process on windows 0093 #endif 0094 } 0095 for (auto* expression : expressionQueue()) 0096 expression->setStatus(Cantor::Expression::Interrupted); 0097 expressionQueue().clear(); 0098 0099 qDebug()<<"done interrupting"; 0100 } 0101 0102 changeStatus(Cantor::Session::Done); 0103 } 0104 0105 Cantor::Expression* RSession::evaluateExpression(const QString& cmd, Cantor::Expression::FinishingBehavior behave, bool internal) 0106 { 0107 qDebug()<<"evaluating: "<<cmd; 0108 auto* expr = new RExpression(this, internal); 0109 expr->setFinishingBehavior(behave); 0110 expr->setCommand(cmd); 0111 0112 expr->evaluate(); 0113 0114 return expr; 0115 } 0116 0117 Cantor::CompletionObject* RSession::completionFor(const QString& command, int index) 0118 { 0119 auto* cmp = new RCompletionObject(command, index, this); 0120 return cmp; 0121 } 0122 0123 QSyntaxHighlighter* RSession::syntaxHighlighter(QObject* parent) 0124 { 0125 return new RHighlighter(parent, this); 0126 } 0127 0128 void RSession::serverChangedStatus(int status) 0129 { 0130 qDebug()<<"changed status to "<<status; 0131 if(status==0) 0132 { 0133 if(expressionQueue().isEmpty()) 0134 changeStatus(Cantor::Session::Done); 0135 } 0136 else 0137 changeStatus(Cantor::Session::Running); 0138 } 0139 0140 void RSession::expressionFinished(int returnCode, const QString& text, const QStringList& files) 0141 { 0142 if (!expressionQueue().isEmpty()) 0143 { 0144 auto* expr = expressionQueue().first(); 0145 if (expr->status() == Cantor::Expression::Interrupted) 0146 return; 0147 0148 static_cast<RExpression*>(expr)->showFilesAsResult(files); 0149 0150 if(returnCode==RExpression::SuccessCode) 0151 expr->parseOutput(text); 0152 else if (returnCode==RExpression::ErrorCode) 0153 expr->parseError(text); 0154 0155 qDebug()<<"done running "<<expr<<" "<<expr->command(); 0156 finishFirstExpression(); 0157 } 0158 } 0159 0160 void RSession::runFirstExpression() 0161 { 0162 if (expressionQueue().isEmpty()) 0163 return; 0164 0165 auto* expr = expressionQueue().first(); 0166 qDebug()<<"running expression: "<<expr->command(); 0167 0168 expr->setStatus(Cantor::Expression::Computing); 0169 m_rServer->runCommand(expr->internalCommand(), expr->isInternal()); 0170 changeStatus(Cantor::Session::Running); 0171 } 0172 0173 void RSession::sendInputToServer(const QString& input) 0174 { 0175 QString s = input; 0176 if(!input.endsWith(QLatin1Char('\n'))) 0177 s += QLatin1Char('\n'); 0178 m_rServer->answerRequest(s); 0179 } 0180 0181 void RSession::inputRequested(QString info) 0182 { 0183 if (expressionQueue().isEmpty()) 0184 return; 0185 0186 emit expressionQueue().first()->needsAdditionalInformation(info); 0187 }