diff --git a/src/backends/R/rsession.cpp b/src/backends/R/rsession.cpp index e35728b0..2eccfcd7 100644 --- a/src/backends/R/rsession.cpp +++ b/src/backends/R/rsession.cpp @@ -1,195 +1,196 @@ /* This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. --- Copyright (C) 2009 Alexander Rieder Copyright (C) 2018 Alexander Semke */ #include "rsession.h" #include "rexpression.h" #include "rcompletionobject.h" #include "rhighlighter.h" #include #include #include #ifndef Q_OS_WIN #include #endif RSession::RSession(Cantor::Backend* backend) : Session(backend), m_process(nullptr), m_rServer(nullptr) { } RSession::~RSession() { qDebug(); - m_process->terminate(); + if (m_process) + m_process->terminate(); } void RSession::login() { qDebug()<<"login"; emit loginStarted(); if(m_process) m_process->deleteLater(); m_process = new QProcess(this); m_process->start(QStandardPaths::findExecutable(QLatin1String("cantor_rserver"))); m_process->waitForStarted(); m_process->waitForReadyRead(); qDebug()<readAllStandardOutput(); m_rServer = new org::kde::Cantor::R(QString::fromLatin1("org.kde.Cantor.R-%1").arg(m_process->pid()), QLatin1String("/"), QDBusConnection::sessionBus(), this); connect(m_rServer, SIGNAL(statusChanged(int)), this, SLOT(serverChangedStatus(int))); connect(m_rServer,SIGNAL(symbolList(const QStringList&,const QStringList&)),this,SLOT(receiveSymbols(const QStringList&,const QStringList&))); emit loginDone(); qDebug()<<"login done"; } void RSession::logout() { qDebug()<<"logout"; m_process->terminate(); } void RSession::interrupt() { const int pid = m_process->pid(); qDebug()<<"interrupt" << pid; if (pid) { #ifndef Q_OS_WIN kill(pid, SIGINT); #else //TODO: interrupt the process on windows #endif } m_expressionQueue.removeFirst(); changeStatus(Cantor::Session::Done); } Cantor::Expression* RSession::evaluateExpression(const QString& cmd, Cantor::Expression::FinishingBehavior behave) { qDebug()<<"evaluating: "<setFinishingBehavior(behave); expr->setCommand(cmd); expr->evaluate(); changeStatus(Cantor::Session::Running); return expr; } Cantor::CompletionObject* RSession::completionFor(const QString& command, int index) { RCompletionObject *cmp=new RCompletionObject(command, index, this); connect(m_rServer,SIGNAL(completionFinished(const QString&,const QStringList&)),cmp,SLOT(receiveCompletions(const QString&,const QStringList&))); connect(cmp,SIGNAL(requestCompletion(const QString&)),m_rServer,SLOT(completeCommand(const QString&))); return cmp; } QSyntaxHighlighter* RSession::syntaxHighlighter(QObject* parent) { RHighlighter *h=new RHighlighter(parent); connect(h,SIGNAL(syntaxRegExps(QVector&,QVector&)),this,SLOT(fillSyntaxRegExps(QVector&,QVector&))); connect(this,SIGNAL(symbolsChanged()),h,SLOT(refreshSyntaxRegExps())); return h; } void RSession::fillSyntaxRegExps(QVector& v, QVector& f) { // WARNING: current implementation as-in-maxima is a performance hit // think about grouping expressions together or only fetching needed ones v.clear(); f.clear(); foreach (const QString s, m_variables) if (!s.contains(QRegExp(QLatin1String("[^A-Za-z0-9_.]")))) v.append(QRegExp(QLatin1String("\\b")+s+QLatin1String("\\b"))); foreach (const QString s, m_functions) if (!s.contains(QRegExp(QLatin1String("[^A-Za-z0-9_.]")))) f.append(QRegExp(QLatin1String("\\b")+s+QLatin1String("\\b"))); } void RSession::receiveSymbols(const QStringList& v, const QStringList & f) { m_variables=v; m_functions=f; emit symbolsChanged(); } void RSession::queueExpression(RExpression* expr) { m_expressionQueue.append(expr); if(status()==Cantor::Session::Done) QTimer::singleShot(0, this, SLOT(runNextExpression())); } void RSession::serverChangedStatus(int status) { qDebug()<<"changed status to "<command(); } if(m_expressionQueue.isEmpty()) changeStatus(Cantor::Session::Done); else runNextExpression(); } else changeStatus(Cantor::Session::Running); } void RSession::runNextExpression() { if (m_expressionQueue.isEmpty()) return; disconnect(m_rServer, SIGNAL(expressionFinished(int, const QString&)), 0, 0); disconnect(m_rServer, SIGNAL(inputRequested(const QString&)), 0, 0); disconnect(m_rServer, SIGNAL(showFilesNeeded(const QStringList&)), 0, 0); qDebug()<<"size: "<command(); connect(m_rServer, SIGNAL(expressionFinished(int, const QString &)), expr, SLOT(finished(int, const QString&))); connect(m_rServer, SIGNAL(inputRequested(const QString&)), expr, SIGNAL(needsAdditionalInformation(const QString&))); connect(m_rServer, SIGNAL(showFilesNeeded(const QStringList&)), expr, SLOT(showFilesAsResult(const QStringList&))); m_rServer->runCommand(expr->command()); } void RSession::sendInputToServer(const QString& input) { QString s=input; if(!input.endsWith(QLatin1Char('\n'))) s+=QLatin1Char('\n'); m_rServer->answerRequest(s); } diff --git a/src/backends/scilab/scilabsession.cpp b/src/backends/scilab/scilabsession.cpp index dc8e68af..3556d5c4 100644 --- a/src/backends/scilab/scilabsession.cpp +++ b/src/backends/scilab/scilabsession.cpp @@ -1,305 +1,306 @@ /* This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. --- Copyright (C) 2011 Filipe Saraiva */ #include "scilabsession.h" #include "scilabexpression.h" #include "scilabhighlighter.h" #include "scilabkeywords.h" #include "scilabcompletionobject.h" #include #include #include #include #include #include #include #include #include #include #include ScilabSession::ScilabSession( Cantor::Backend* backend) : Session(backend), m_variableModel(new Cantor::DefaultVariableModel(this)) { m_process = nullptr; qDebug(); } ScilabSession::~ScilabSession() { - m_process->terminate(); + if (m_process) + m_process->terminate(); qDebug(); } void ScilabSession::login() { qDebug()<<"login"; emit loginStarted(); QStringList args; args << QLatin1String("-nb"); m_process = new QProcess(this); m_process->setArguments(args); m_process->setProgram(ScilabSettings::self()->path().toLocalFile()); qDebug() << m_process->program(); m_process->setProcessChannelMode(QProcess::SeparateChannels); m_process->start(); if(ScilabSettings::integratePlots()){ qDebug() << "integratePlots"; QString tempPath = QDir::tempPath(); QString pathScilabOperations = tempPath; pathScilabOperations.prepend(QLatin1String("chdir('")); pathScilabOperations.append(QLatin1String("');\n")); qDebug() << "Processing command to change chdir in Scilab. Command " << pathScilabOperations.toLocal8Bit(); m_process->write(pathScilabOperations.toLocal8Bit()); m_watch = new KDirWatch(this); m_watch->setObjectName(QLatin1String("ScilabDirWatch")); m_watch->addDir(tempPath, KDirWatch::WatchFiles); qDebug() << "addDir " << tempPath << "? " << m_watch->contains(QLatin1String(tempPath.toLocal8Bit())); QObject::connect(m_watch, &KDirWatch::created, this, &ScilabSession::plotFileChanged); } if(!ScilabSettings::self()->autorunScripts().isEmpty()){ QString autorunScripts = ScilabSettings::self()->autorunScripts().join(QLatin1String("\n")); m_process->write(autorunScripts.toLocal8Bit()); } QObject::connect(m_process, &QProcess::readyReadStandardOutput, this, &ScilabSession::listKeywords); QObject::connect(m_process, &QProcess::readyReadStandardError, this, &ScilabSession::readError); m_process->readAllStandardOutput().clear(); m_process->readAllStandardError().clear(); ScilabExpression *listKeywords = new ScilabExpression(this); listKeywords->setCommand(QLatin1String("disp(getscilabkeywords());")); runExpression(listKeywords); emit loginDone(); } void ScilabSession::logout() { qDebug()<<"logout"; m_process->write("exit\n"); m_runningExpressions.clear(); qDebug() << "m_runningExpressions: " << m_runningExpressions.isEmpty(); QDir removePlotFigures; QListIterator i(m_listPlotName); while(i.hasNext()){ removePlotFigures.remove(QLatin1String(i.next().toLocal8Bit().constData())); } } void ScilabSession::interrupt() { qDebug()<<"interrupt"; foreach(Cantor::Expression* e, m_runningExpressions) e->interrupt(); m_runningExpressions.clear(); changeStatus(Cantor::Session::Done); } Cantor::Expression* ScilabSession::evaluateExpression(const QString& cmd, Cantor::Expression::FinishingBehavior behave) { qDebug() << "evaluating: " << cmd; ScilabExpression* expr = new ScilabExpression(this); changeStatus(Cantor::Session::Running); expr->setFinishingBehavior(behave); expr->setCommand(cmd); expr->evaluate(); return expr; } void ScilabSession::runExpression(ScilabExpression* expr) { QString command; command.prepend(QLatin1String("\nprintf('begin-cantor-scilab-command-processing')\n")); command += expr->command(); m_currentExpression = expr; connect(m_currentExpression, &ScilabExpression::statusChanged, this, &ScilabSession::currentExpressionStatusChanged); command += QLatin1String("\nprintf('terminated-cantor-scilab-command-processing')\n"); qDebug() << "Writing command to process" << command; m_process->write(command.toLocal8Bit()); } void ScilabSession::expressionFinished() { qDebug()<<"finished"; ScilabExpression* expression = qobject_cast(sender()); m_runningExpressions.removeAll(expression); qDebug() << "size: " << m_runningExpressions.size(); } void ScilabSession::readError() { qDebug() << "readError"; QString error = QLatin1String(m_process->readAllStandardError()); qDebug() << "error: " << error; m_currentExpression->parseError(error); } void ScilabSession::readOutput() { qDebug() << "readOutput"; while(m_process->bytesAvailable() > 0){ m_output.append(QString::fromLocal8Bit(m_process->readLine())); } qDebug() << "output.isNull? " << m_output.isNull(); qDebug() << "output: " << m_output; if(status() != Running || m_output.isNull()){ return; } if(m_output.contains(QLatin1String("begin-cantor-scilab-command-processing")) && m_output.contains(QLatin1String("terminated-cantor-scilab-command-processing"))){ m_output.remove(QLatin1String("begin-cantor-scilab-command-processing")); m_output.remove(QLatin1String("terminated-cantor-scilab-command-processing")); m_currentExpression->parseOutput(m_output); m_output.clear(); } } void ScilabSession::plotFileChanged(QString filename) { qDebug() << "plotFileChanged filename:" << filename; if ((m_currentExpression) && (filename.contains(QLatin1String("cantor-export-scilab-figure")))){ qDebug() << "Calling parsePlotFile"; m_currentExpression->parsePlotFile(filename); m_listPlotName.append(filename); } } void ScilabSession::currentExpressionStatusChanged(Cantor::Expression::Status status) { qDebug() << "currentExpressionStatusChanged: " << status; switch (status){ case Cantor::Expression::Computing: break; case Cantor::Expression::Interrupted: break; case Cantor::Expression::Done: case Cantor::Expression::Error: changeStatus(Done); emit updateVariableHighlighter(); break; } } void ScilabSession::listKeywords() { qDebug(); while(m_process->bytesAvailable() > 0){ m_output.append(QString::fromLocal8Bit(m_process->readLine())); } if(m_output.contains(QLatin1String("begin-cantor-scilab-command-processing")) && m_output.contains(QLatin1String("terminated-cantor-scilab-command-processing"))){ m_output.remove(QLatin1String("begin-cantor-scilab-command-processing")); m_output.remove(QLatin1String("terminated-cantor-scilab-command-processing")); ScilabKeywords::instance()->setupKeywords(m_output); QObject::disconnect(m_process, &QProcess::readyReadStandardOutput, this, &ScilabSession::listKeywords); QObject::connect(m_process, &QProcess::readyReadStandardOutput, this, &ScilabSession::readOutput); m_process->readAllStandardOutput().clear(); m_process->readAllStandardError().clear(); m_output.clear(); } changeStatus(Done); m_currentExpression->evalFinished(); emit updateHighlighter(); } QSyntaxHighlighter* ScilabSession::syntaxHighlighter(QObject* parent) { qDebug(); ScilabHighlighter *highlighter = new ScilabHighlighter(parent); QObject::connect(this, &ScilabSession::updateHighlighter, highlighter, &ScilabHighlighter::updateHighlight); QObject::connect(this, &ScilabSession::updateVariableHighlighter, highlighter, &ScilabHighlighter::addVariableHighlight); return highlighter; } Cantor::CompletionObject* ScilabSession::completionFor(const QString& command, int index) { return new ScilabCompletionObject(command, index, this); } QAbstractItemModel* ScilabSession::variableModel() { return m_variableModel; }