Fwd: [GSoC 2016] Julia backend for Cantor
Иван Лахтанов
ivan.lakhtanov at gmail.com
Mon Mar 21 09:28:37 UTC 2016
Hello!
I've messed git diff master..vaness-julia-backend with git diff
vaness-julia-backend..master. Attaching fixed patch. You maybe noticed that
there is some workaround on detecting end of the command output (print
"julia>"), Julia detects that it is communicating through program and
doesn't show prompt. I'm now thinking on how to overcome this or make more
reliable workaround.
I haven't submitted proposal draft yet -- planing to do it today.
2016-03-20 22:55 GMT+03:00 Filipe Saraiva <filipe at kde.org>:
> Em 18-03-2016 17:40, Иван Лахтанов escreveu:
>
> Hello, KDE-edu team!
>
> I want to participate Google Summer of Code this year. My friend
> recommended me to apply for KDE projects and I am a big fun of Qt and KDE.
>
> I looked through the ideas list and choosen "Julia backend for Cantor
> <https://community.kde.org/GSoC/2016/Ideas#Project:_Backend_for_Julia>".
> I am student of Moscow State University Mechanics and Mathematics
> department and have experience on porting Julia math library to Python 2
> during one of my courseworks.
>
> I have already developed executing Julia commands and attaching the
> current patch with this email. If you expect me to do more as preliminary
> task tell me and I will try to hurry until proposal deadline.
>
>
> Hello Ivan, thank you for the patch, looks like you did an interesting
> work.
> But your patch is reverting/removing the files and contributions of you
> did.
>
> Please could you fix the patch? Did You submit a project to GSoC?
>
> Best regards;
>
> --
> Filipe Saraivahttp://filipesaraiva.info/
>
>
> _______________________________________________
> kde-edu mailing list
> kde-edu at mail.kde.org
> https://mail.kde.org/mailman/listinfo/kde-edu
>
>
--
Best regards, Ivan Lakhtanov
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.kde.org/pipermail/kde-edu/attachments/20160321/bc2f1638/attachment-0003.html>
-------------- next part --------------
diff --git a/src/backends/CMakeLists.txt b/src/backends/CMakeLists.txt
index 4987b37..fa14700 100644
--- a/src/backends/CMakeLists.txt
+++ b/src/backends/CMakeLists.txt
@@ -15,6 +15,9 @@ add_subdirectory(maxima)
add_subdirectory(octave)
add_subdirectory(scilab)
+# FIXME: wrap this properly
+add_subdirectory(julia)
+
if(NOT WIN32)
add_subdirectory(sage)
endif(NOT WIN32)
diff --git a/src/backends/julia/CMakeLists.txt b/src/backends/julia/CMakeLists.txt
new file mode 100644
index 0000000..3036f40
--- /dev/null
+++ b/src/backends/julia/CMakeLists.txt
@@ -0,0 +1,8 @@
+set( JuliaBackend_SRCS
+ juliabackend.cpp
+ juliasession.cpp
+ juliaexpression.cpp
+ juliacompletionobject.cpp
+)
+
+add_backend(juliabackend ${JuliaBackend_SRCS})
diff --git a/src/backends/julia/juliabackend.cpp b/src/backends/julia/juliabackend.cpp
new file mode 100644
index 0000000..31b586d
--- /dev/null
+++ b/src/backends/julia/juliabackend.cpp
@@ -0,0 +1,61 @@
+/*
+ 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 <alexanderrieder at gmail.com>
+ Copyright (C) 2016 Ivan Lakhtanov <ivan.lakhtanov at gmail.com>
+ */
+
+#include "juliabackend.h"
+
+#include <QDebug>
+
+#include "cantor_macros.h"
+#include "juliasession.h"
+
+JuliaBackend::JuliaBackend(QObject *parent, const QList<QVariant> args)
+ : Cantor::Backend(parent, args)
+{
+ setObjectName(QLatin1String("juliabackend"));
+ qDebug() << "Creating JuliaBackend";
+ setEnabled(true);
+}
+
+JuliaBackend::~JuliaBackend()
+{
+ qDebug() << "Destroying JuliaBackend";
+}
+
+QString JuliaBackend::id() const
+{
+ return QLatin1String("julia");
+}
+
+Cantor::Session *JuliaBackend::createSession()
+{
+ qDebug() << "Spawning a new Julia session";
+
+ return new JuliaSession(this);
+}
+
+Cantor::Backend::Capabilities JuliaBackend::capabilities() const
+{
+ qDebug() << "Requesting capabilities of JuliaSession";
+ return Cantor::Backend::Nothing;
+}
+
+K_PLUGIN_FACTORY_WITH_JSON(juliabackend, "juliabackend.json", registerPlugin<JuliaBackend>();)
+#include "juliabackend.moc"
diff --git a/src/backends/julia/juliabackend.h b/src/backends/julia/juliabackend.h
new file mode 100644
index 0000000..9322263
--- /dev/null
+++ b/src/backends/julia/juliabackend.h
@@ -0,0 +1,41 @@
+/*
+ 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 <alexanderrieder at gmail.com>
+ Copyright (C) 2016 Ivan Lakhtanov <ivan.lakhtanov at gmail.com>
+ */
+
+#ifndef _JULIABACKEND_H
+#define _JULIABACKEND_H
+
+#include "backend.h"
+
+class JuliaBackend: public Cantor::Backend
+{
+ Q_OBJECT
+
+public:
+ explicit JuliaBackend(QObject *parent = 0, const QList<QVariant> args = QList<QVariant>());
+ ~JuliaBackend();
+
+ QString id() const;
+
+ Cantor::Session *createSession();
+ Cantor::Backend::Capabilities capabilities() const;
+};
+
+#endif /* _JULIABACKEND_H */
diff --git a/src/backends/julia/juliabackend.json b/src/backends/julia/juliabackend.json
new file mode 100644
index 0000000..1aa221b
--- /dev/null
+++ b/src/backends/julia/juliabackend.json
@@ -0,0 +1,12 @@
+{
+ "KPlugin": {
+ "Dependencies": [],
+ "Description": "Julia backend for Cantor",
+ "Id": "juliabackend",
+ "License": "GPL",
+ "Name": "juliabackend",
+ "ServiceTypes": [
+ "Cantor/Backend"
+ ]
+ }
+}
diff --git a/src/backends/julia/juliacompletionobject.cpp b/src/backends/julia/juliacompletionobject.cpp
new file mode 100644
index 0000000..25e3c5d
--- /dev/null
+++ b/src/backends/julia/juliacompletionobject.cpp
@@ -0,0 +1,48 @@
+/*
+ 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 <alexanderrieder at gmail.com>
+ Copyright (C) 2016 Ivan Lakhtanov <ivan.lakhtanov at gmail.com>
+ */
+
+#include "juliacompletionobject.h"
+
+#include <QStringList>
+#include <QDebug>
+
+#include "juliasession.h"
+
+JuliaCompletionObject::JuliaCompletionObject(const QString &command, int index, JuliaSession *session)
+ : Cantor::CompletionObject(session)
+{
+ setLine(command, index);
+}
+
+JuliaCompletionObject::~JuliaCompletionObject()
+{
+
+}
+
+void JuliaCompletionObject::fetchCompletions()
+{
+ qDebug() << "fetching...";
+ QStringList comp;
+ for (int i = 0; i < 5; i++)
+ comp << QString::fromLatin1("%1 %2").arg(command()).arg(i);
+ setCompletions(comp);
+ emit fetchingDone();
+}
diff --git a/src/backends/julia/juliacompletionobject.h b/src/backends/julia/juliacompletionobject.h
new file mode 100644
index 0000000..fc80aed
--- /dev/null
+++ b/src/backends/julia/juliacompletionobject.h
@@ -0,0 +1,40 @@
+/*
+ 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 <alexanderrieder at gmail.com>
+ Copyright (C) 2016 Ivan Lakhtanov <ivan.lakhtanov at gmail.com>
+ */
+
+#ifndef _JULIACOMPLETIONOBJECT_H
+#define _JULIACOMPLETIONOBJECT_H
+
+#include "completionobject.h"
+
+class JuliaSession;
+
+class JuliaCompletionObject: public Cantor::CompletionObject
+{
+ public:
+ JuliaCompletionObject(const QString &command, int index, JuliaSession *session);
+ ~JuliaCompletionObject();
+
+ protected Q_SLOTS:
+ void fetchCompletions();
+
+};
+
+#endif /* _JULIACOMPLETIONOBJECT_H */
diff --git a/src/backends/julia/juliaexpression.cpp b/src/backends/julia/juliaexpression.cpp
new file mode 100644
index 0000000..ec05ce2
--- /dev/null
+++ b/src/backends/julia/juliaexpression.cpp
@@ -0,0 +1,90 @@
+/*
+ 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 <alexanderrieder at gmail.com>
+ Copyright (C) 2016 Ivan Lakhtanov <ivan.lakhtanov at gmail.com>
+ */
+
+#include "juliaexpression.h"
+
+#include <QDebug>
+#include <KIconLoader>
+#include <QTimer>
+
+#include "textresult.h"
+#include "imageresult.h"
+#include "helpresult.h"
+
+#include "juliasession.h"
+
+JuliaExpression::JuliaExpression(Cantor::Session *session)
+ : Cantor::Expression(session)
+{
+ qDebug() << "JuliaExpression constructor";
+ m_error = false;
+}
+
+JuliaExpression::~JuliaExpression()
+{
+}
+
+
+void JuliaExpression::evaluate()
+{
+ qDebug() << "evaluating " << command();
+
+ QString cmd = command();
+ m_finished = false;
+ setStatus(Cantor::Expression::Computing);
+ JuliaSession *juliasession = dynamic_cast<JuliaSession *>(session());
+ if (juliasession) {
+ juliasession->runExpression(this);
+ }
+}
+
+void JuliaExpression::interrupt()
+{
+ qDebug() << "interrupting command";
+ setStatus(Cantor::Expression::Interrupted);
+}
+
+void JuliaExpression::parseOutput(QString output)
+{
+ qDebug() << "parseOutput: " << output;
+ m_resultString += output;
+ if (!m_resultString.trimmed().isEmpty()) {
+ setResult(new Cantor::TextResult(m_resultString));
+ }
+}
+
+void JuliaExpression::parseError(QString error)
+{
+ qDebug() << "parseError: " << error;
+ m_error = true;
+ setErrorMessage(error);
+ setStatus(Error);
+}
+
+void JuliaExpression::finalize()
+{
+ qDebug() << "finalize: " << m_resultString;
+ m_finished = true;
+ setStatus(m_error ? Error : Done);
+}
+
+
+#include "juliaexpression.moc"
diff --git a/src/backends/julia/juliaexpression.h b/src/backends/julia/juliaexpression.h
new file mode 100644
index 0000000..d93eeb9
--- /dev/null
+++ b/src/backends/julia/juliaexpression.h
@@ -0,0 +1,51 @@
+/*
+ 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 <alexanderrieder at gmail.com>
+ Copyright (C) 2016 Ivan Lakhtanov <ivan.lakhtanov at gmail.com>
+ */
+
+#ifndef _JULIAEXPRESSION_H
+#define _JULIAEXPRESSION_H
+
+#include "expression.h"
+
+class JuliaExpression: public Cantor::Expression
+{
+ Q_OBJECT
+public:
+ JuliaExpression(Cantor::Session *session);
+ ~JuliaExpression();
+
+ void evaluate();
+ void interrupt();
+
+ void parseOutput(QString output);
+ void parseError(QString error);
+
+ void finalize();
+
+private:
+ QString m_resultString;
+ int m_numberOfLines;
+ bool m_plotPending;
+ bool m_finished;
+ bool m_error;
+ QStringList m_plotCommands;
+};
+
+#endif /* _JULIAEXPRESSION_H */
diff --git a/src/backends/julia/juliasession.cpp b/src/backends/julia/juliasession.cpp
new file mode 100644
index 0000000..bd33e57
--- /dev/null
+++ b/src/backends/julia/juliasession.cpp
@@ -0,0 +1,199 @@
+/*
+ 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 <alexanderrieder at gmail.com>
+ Copyright (C) 2016 Ivan Lakhtanov <ivan.lakhtanov at gmail.com>
+ */
+
+#include "juliasession.h"
+
+#include <QDebug>
+#include <KProcess>
+#include <signal.h>
+
+#include "juliaexpression.h"
+#include "juliacompletionobject.h"
+
+JuliaSession::JuliaSession(Cantor::Backend *backend)
+ : Session(backend)
+ , m_process(0)
+ , m_currentExpression(0)
+{
+ qDebug();
+
+ m_prompt.setPattern(QLatin1String("julia>"));
+}
+
+JuliaSession::~JuliaSession()
+{
+ qDebug();
+}
+
+void JuliaSession::login()
+{
+ qDebug() << "login";
+
+ QStringList args;
+ args << QLatin1String("--quiet"); // No banner on startup
+ args << QLatin1String("-i"); // Force interactive mode
+ args << QLatin1String("--color=no"); // No color
+ args << QLatin1String("--no-history-file"); // No history
+ args << QLatin1String("--no-startup"); // No startup scripts
+ m_process = new KProcess(this);
+ m_process->setProgram(QLatin1String("/usr/bin/julia"), args);
+ qDebug() << m_process->program();
+ m_process->setOutputChannelMode(KProcess::SeparateChannels);
+ connect(m_process, SIGNAL(readyReadStandardOutput()), SLOT(readOutput()));
+ connect(m_process, SIGNAL(readyReadStandardError()), SLOT(readError()));
+ connect(m_process, SIGNAL(error(QProcess::ProcessError)), SLOT(processError()));
+ m_process->start();
+
+ changeStatus(Cantor::Session::Done);
+ emit ready();
+}
+
+void JuliaSession::logout()
+{
+ qDebug() << "logout";
+ m_process->write("exit(0)\n");
+ if (!m_process->waitForFinished(1000)) {
+ m_process->kill();
+ }
+}
+
+void JuliaSession::interrupt()
+{
+ qDebug() << "interrupt";
+ if (m_currentExpression) {
+ m_currentExpression->interrupt();
+ }
+ m_expressionQueue.clear();
+ qDebug() << "Sending SINGINT to Julia";
+ kill(m_process->pid(), SIGINT);
+ changeStatus(Cantor::Session::Done);
+}
+
+Cantor::Expression *JuliaSession::evaluateExpression(const QString &cmd, Cantor::Expression::FinishingBehavior behave)
+{
+ qDebug() << "evaluateExpression: " << cmd;
+
+ JuliaExpression *expression = new JuliaExpression(this);
+ expression->setCommand(cmd);
+ expression->setFinishingBehavior(behave);
+ expression->evaluate();
+
+ return expression;
+}
+
+Cantor::CompletionObject *JuliaSession::completionFor(const QString &command, int index)
+{
+ qDebug() << "tab completion for " << command;
+ return new JuliaCompletionObject(command, index, this);
+}
+
+void JuliaSession::processError()
+{
+ qDebug() << "processError";
+ emit error(m_process->errorString());
+}
+
+void JuliaSession::readError()
+{
+ qDebug() << "readError";
+ QString error = QString::fromLocal8Bit(m_process->readAllStandardError());
+ if (!m_currentExpression || error.isEmpty()) {
+ qDebug() << error;
+ return;
+ }
+ m_currentExpression->parseError(error);
+}
+
+void JuliaSession::readOutput()
+{
+ qDebug() << "readOutput";
+ while (m_process->bytesAvailable() > 0) {
+ if (!m_process->canReadLine()) {
+ qDebug() << "Waiting";
+ return;
+ }
+
+ QString line = QString::fromLocal8Bit(m_process->readLine());
+ qDebug() << line;
+ if (!m_currentExpression) {
+ changeStatus(Done);
+ if (!m_expressionQueue.isEmpty()) {
+ runExpression(m_expressionQueue.dequeue());
+ }
+ emit ready();
+ } else if (line.contains(m_prompt)) {
+ readError();
+ m_currentExpression->finalize();
+ } else {
+ while (m_process->canReadLine()) {
+ line += QString::fromLocal8Bit(m_process->readLine());
+ }
+ m_currentExpression->parseOutput(line);
+ }
+ }
+}
+
+void JuliaSession::runExpression(JuliaExpression *expression)
+{
+ qDebug() << "runExpression";
+ if (status() != Done) {
+ m_expressionQueue.enqueue(expression);
+ qDebug() << m_expressionQueue.size();
+ } else {
+ m_currentExpression = expression;
+ changeStatus(Running);
+ connect(
+ m_currentExpression,
+ SIGNAL(statusChanged(Cantor::Expression::Status)),
+ this,
+ SLOT(currentExpressionStatusChanged(Cantor::Expression::Status))
+ );
+ QString command = expression->command();
+ command.replace(QLatin1Char('\n'), QLatin1Char(';'));
+ command = QLatin1String("println(eval(:(") +
+ command +
+ QLatin1String(")));println(\"julia>\");\n");
+ m_process->write(command.toLocal8Bit());
+ }
+}
+
+void JuliaSession::currentExpressionStatusChanged(Cantor::Expression::Status status)
+{
+ qDebug() << "currentExpressionStatusChanged";
+ if (!m_currentExpression) {
+ return;
+ }
+ switch (status) {
+ case Cantor::Expression::Computing:
+ break;
+ case Cantor::Expression::Interrupted:
+ break;
+ case Cantor::Expression::Done:
+ case Cantor::Expression::Error:
+ changeStatus(Done);
+ if (!m_expressionQueue.isEmpty()) {
+ runExpression(m_expressionQueue.dequeue());
+ }
+ break;
+ }
+}
+
+#include "juliasession.moc"
diff --git a/src/backends/julia/juliasession.h b/src/backends/julia/juliasession.h
new file mode 100644
index 0000000..3a5f6ad
--- /dev/null
+++ b/src/backends/julia/juliasession.h
@@ -0,0 +1,63 @@
+/*
+ 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 <alexanderrieder at gmail.com>
+ Copyright (C) 2016 Ivan Lakhtanov <ivan.lakhtanov at gmail.com>
+ */
+
+#ifndef _JULIASESSION_H
+#define _JULIASESSION_H
+
+#include <QPointer>
+#include <QQueue>
+
+#include "session.h"
+
+class JuliaExpression;
+class KProcess;
+
+class JuliaSession: public Cantor::Session
+{
+ Q_OBJECT
+public:
+ JuliaSession(Cantor::Backend *backend);
+ ~JuliaSession();
+
+ virtual void login();
+ virtual void logout();
+
+ void interrupt();
+
+ Cantor::Expression *evaluateExpression(const QString &command, Cantor::Expression::FinishingBehavior behave);
+ Cantor::CompletionObject *completionFor(const QString &cmd, int index = -1);
+
+ void runExpression(JuliaExpression *expression);
+
+private Q_SLOTS:
+ void readOutput();
+ void readError();
+ void currentExpressionStatusChanged(Cantor::Expression::Status status);
+ void processError();
+
+private:
+ QQueue<JuliaExpression *> m_expressionQueue;
+ QPointer<JuliaExpression> m_currentExpression;
+ KProcess *m_process;
+ QRegExp m_prompt;
+};
+
+#endif /* _JULIASESSION_H */
More information about the kde-edu
mailing list