diff --git a/src/backends/julia/juliasession.cpp b/src/backends/julia/juliasession.cpp index 8d44157f..42d0e0c7 100644 --- a/src/backends/julia/juliasession.cpp +++ b/src/backends/julia/juliasession.cpp @@ -1,269 +1,273 @@ /* 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) 2016 Ivan Lakhtanov */ #include "juliasession.h" #include #include #include #include #include #include #include "defaultvariablemodel.h" #include "juliaexpression.h" #include "settings.h" #include "juliahighlighter.h" #include "juliakeywords.h" #include "juliavariablemodel.h" #include "juliaextensions.h" #include "juliabackend.h" #include "juliacompletionobject.h" using namespace Cantor; JuliaSession::JuliaSession(Cantor::Backend *backend) : Session(backend) , m_process(nullptr) , m_interface(nullptr) { setVariableModel(new JuliaVariableModel(this)); } JuliaSession::~JuliaSession() { if (m_process) { m_process->kill(); m_process->deleteLater(); m_process = nullptr; } } void JuliaSession::login() { if (m_process) return; emit loginStarted(); m_process = new KProcess(this); m_process->setOutputChannelMode(KProcess::OnlyStdoutChannel); (*m_process) << QStandardPaths::findExecutable(QLatin1String("cantor_juliaserver")); connect(m_process, &QProcess::errorOccurred, this, &JuliaSession::reportServerProcessError); m_process->start(); m_process->waitForStarted(); m_process->waitForReadyRead(); QTextStream stream(m_process->readAllStandardOutput()); QString readyStatus = QLatin1String("ready"); while (m_process->state() == QProcess::Running) { const QString &rl = stream.readLine(); if (rl == readyStatus) { break; } } if (!QDBusConnection::sessionBus().isConnected()) { qWarning() << "Can't connect to the D-Bus session bus.\n" "To start it, run: eval `dbus-launch --auto-syntax`"; return; } const QString &serviceName = QString::fromLatin1("org.kde.Cantor.Julia-%1").arg(m_process->pid()); m_interface = new QDBusInterface( serviceName, QString::fromLatin1("/"), QString(), QDBusConnection::sessionBus() ); if (!m_interface->isValid()) { qWarning() << QDBusConnection::sessionBus().lastError().message(); return; } m_interface->call( QString::fromLatin1("login"), JuliaSettings::self()->replPath().path() ); static_cast(variableModel())->setJuliaServer(m_interface); // Plots integration if (integratePlots()) { runJuliaCommand( QLatin1String("import GR; ENV[\"GKS_WSTYPE\"] = \"nul\"") ); updateVariables(); } changeStatus(Session::Done); emit loginDone(); qDebug() << "login to julia done"; } void JuliaSession::logout() { if(!m_process) return; if(status() == Cantor::Session::Running) + { + if(m_process && m_process->state() == QProcess::Running) + { + disconnect(m_process, &QProcess::errorOccurred, this, &JuliaSession::reportServerProcessError); + m_process->kill(); + } + m_process->deleteLater(); + m_process = nullptr; interrupt(); - - if (m_process->pid()) - m_process->terminate(); - m_process->deleteLater(); - m_process = nullptr; + } Session::logout(); } void JuliaSession::interrupt() { if (expressionQueue().isEmpty()) return; if (m_process && m_process->pid()) { disconnect(m_process, &QProcess::errorOccurred, this, &JuliaSession::reportServerProcessError); m_process->kill(); } qDebug()<<"interrupting " << expressionQueue().first()->command(); foreach (Cantor::Expression* expression, expressionQueue()) expression->setStatus(Cantor::Expression::Interrupted); expressionQueue().clear(); changeStatus(Cantor::Session::Done); } Cantor::Expression *JuliaSession::evaluateExpression( const QString &cmd, Cantor::Expression::FinishingBehavior behave, bool internal) { JuliaExpression *expr = new JuliaExpression(this, internal); expr->setFinishingBehavior(behave); expr->setCommand(cmd); expr->evaluate(); return expr; } Cantor::CompletionObject *JuliaSession::completionFor( const QString &command, int index) { return new JuliaCompletionObject(command, index, this); } QSyntaxHighlighter *JuliaSession::syntaxHighlighter(QObject *parent) { return new JuliaHighlighter(parent, this); } void JuliaSession::runJuliaCommand(const QString &command) const { m_interface->call(QLatin1String("runJuliaCommand"), command); } void JuliaSession::runJuliaCommandAsync(const QString &command) { m_interface->callWithCallback( QLatin1String("runJuliaCommand"), {command}, this, SLOT(onResultReady()) ); } void JuliaSession::onResultReady() { static_cast(expressionQueue().first())->finalize(getOutput(), getError(), getWasException()); finishFirstExpression(true); } void JuliaSession::reportServerProcessError(QProcess::ProcessError serverError) { switch(serverError) { case QProcess::Crashed: emit error(i18n("Julia process stopped working.")); break; case QProcess::FailedToStart: emit error(i18n("Failed to start Julia process.")); break; default: emit error(i18n("Communication with Julia process failed for unknown reasons.")); break; } qDebug() << "reportSessionCrash" << serverError; reportSessionCrash(); } void JuliaSession::runFirstExpression() { Cantor::Expression* expr = expressionQueue().first(); expr->setStatus(Cantor::Expression::Computing); runJuliaCommandAsync(expr->internalCommand()); } QString JuliaSession::getStringFromServer(const QString &method) { const QDBusReply &reply = m_interface->call(method); return (reply.isValid() ? reply.value() : reply.error().message()); } QString JuliaSession::getOutput() { return getStringFromServer(QLatin1String("getOutput")); } QString JuliaSession::getError() { return getStringFromServer(QLatin1String("getError")); } bool JuliaSession::getWasException() { const QDBusReply &reply = m_interface->call(QLatin1String("getWasException")); return reply.isValid() && reply.value(); } bool JuliaSession::integratePlots() { return JuliaSettings::integratePlots(); }