diff --git a/src/backends/R/CMakeLists.txt b/src/backends/R/CMakeLists.txt
--- a/src/backends/R/CMakeLists.txt
+++ b/src/backends/R/CMakeLists.txt
@@ -1,7 +1,7 @@
include_directories(${R_INCLUDEDIR})
LINK_DIRECTORIES(${R_SHAREDLIBDIR})
-add_subdirectory(rserver)
+#add_subdirectory(rserver)
set( RBackend_SRCS
rbackend.cpp
@@ -13,10 +13,11 @@
rsettingswidget.cpp
)
-kconfig_add_kcfg_files(RBackend_SRCS rserver/settings.kcfgc)
+kconfig_add_kcfg_files(RBackend_SRCS settings.kcfgc)
+install(FILES rbackend.kcfg DESTINATION ${KDE_INSTALL_KCFGDIR})
-set(network_xml rserver/org.kde.Cantor.R.xml)
-QT5_ADD_DBUS_INTERFACE(RBackend_SRCS ${network_xml} rserver_interface )
+#set(network_xml rserver/org.kde.Cantor.R.xml)
+#QT5_ADD_DBUS_INTERFACE(RBackend_SRCS ${network_xml} rserver_interface )
ki18n_wrap_ui(RBackend_SRCS settings.ui)
diff --git a/src/backends/R/rbackend.h b/src/backends/R/rbackend.h
--- a/src/backends/R/rbackend.h
+++ b/src/backends/R/rbackend.h
@@ -34,7 +34,6 @@
QString version() const override;
Cantor::Session *createSession();
Cantor::Backend::Capabilities capabilities() const;
- bool requirementsFullfilled() const;
virtual QWidget* settingsWidget(QWidget* parent) const;
virtual KConfigSkeleton* config() const;
diff --git a/src/backends/R/rbackend.cpp b/src/backends/R/rbackend.cpp
--- a/src/backends/R/rbackend.cpp
+++ b/src/backends/R/rbackend.cpp
@@ -69,12 +69,6 @@
Cantor::Backend::Completion;
}
-bool RBackend::requirementsFullfilled() const
-{
- QFileInfo info(QStandardPaths::findExecutable( QLatin1String("cantor_rserver") ) );
- return info.isExecutable();
-}
-
QWidget* RBackend::settingsWidget(QWidget* parent) const
{
return new RSettingsWidget(parent);
@@ -82,7 +76,7 @@
KConfigSkeleton* RBackend::config() const
{
- return RServerSettings::self();
+ return RBackendSettings::self();
}
QUrl RBackend::helpUrl() const
diff --git a/src/backends/R/rbackend.kcfg b/src/backends/R/rbackend.kcfg
new file mode 100644
--- /dev/null
+++ b/src/backends/R/rbackend.kcfg
@@ -0,0 +1,16 @@
+
+
+
+
+
+
+ true
+
+
+
+
+
+
diff --git a/src/backends/R/rexpression.h b/src/backends/R/rexpression.h
--- a/src/backends/R/rexpression.h
+++ b/src/backends/R/rexpression.h
@@ -25,9 +25,10 @@
class RExpression : public Cantor::Expression
{
- Q_OBJECT
- public:
- enum ServerReturnCode{SuccessCode=0, ErrorCode, InterruptedCode};
+ Q_OBJECT
+
+public:
+
RExpression( Cantor::Session* session);
~RExpression();
@@ -35,11 +36,13 @@
void interrupt();
void addInformation(const QString& information);
- public Q_SLOTS:
- void finished(int returnCode, const QString& text);
- void evaluationStarted();
+ void parseOutput(QString output);
+ void parseError(QString error);
+
+public Q_SLOTS:
void showFilesAsResult(const QStringList& files);
- private:
+
+private:
bool m_isHelpRequest;
};
diff --git a/src/backends/R/rexpression.cpp b/src/backends/R/rexpression.cpp
--- a/src/backends/R/rexpression.cpp
+++ b/src/backends/R/rexpression.cpp
@@ -34,6 +34,7 @@
#include
#include
#include
+#include
RExpression::RExpression( Cantor::Session* session ) : Cantor::Expression(session)
{
@@ -51,44 +52,78 @@
{
qDebug()<<"evaluating "<(session())->queueExpression(this);
+
+ RSession* session = dynamic_cast(this->session());
+
+ /* check if the command is a quit command. following are quit commands supported by R
+ * quit(save = "default", status = 0, runLast = TRUE)
+ * q(save = "default", status = 0, runLast = TRUE)
+ */
+ QRegExp regexp;
+ regexp.setCaseSensitivity(Qt::CaseSensitive);
+ regexp.setPattern(QLatin1String("\\s*q\\s*\\([\\w\\W]*\\)\\s*$|\\s*quit\\s*\\([\\w\\W]*\\)\\s*$"));
+ if(regexp.exactMatch(command().trimmed())) {
+ // since it's a quit command, logout from the session
+ setStatus(Cantor::Expression::Done);
+ session->logout();
+ return;
+ }
+
+ // done evaluation, finally running the command
+ session->runExpression(this);
+
+
}
-void RExpression::interrupt()
+void RExpression::parseOutput(QString output)
{
- qDebug()<<"interrupting command";
- if(status()==Cantor::Expression::Computing)
- session()->interrupt();
- setStatus(Cantor::Expression::Interrupted);
+ // remove garabage from output
+
+ output.replace(command(), QLatin1String(""));
+ output.replace(QLatin1String(">"), QLatin1String(""));
+ output = output.trimmed();
+
+ qDebug() << " final output of the command " << command() << output << endl;
+
+ if(m_isHelpRequest)
+ setResult(new Cantor::HelpResult(output));
+ else
+ setResult(new Cantor::TextResult(output));
+
+ setStatus(Cantor::Expression::Done);
}
-void RExpression::finished(int returnCode, const QString& text)
+void RExpression::parseError(QString error)
{
- if(returnCode==RExpression::SuccessCode)
- {
- setResult(new Cantor::TextResult(Qt::convertFromPlainText(text)));
- setStatus(Cantor::Expression::Done);
- }else if (returnCode==RExpression::ErrorCode)
- {
- setResult(new Cantor::TextResult(Qt::convertFromPlainText(text)));
- setStatus(Cantor::Expression::Error);
- setErrorMessage(Qt::convertFromPlainText(text));
- }
+ error.replace(command(), QLatin1String(""));
+ error.replace(QLatin1String(">"), QLatin1String(""));
+ error = error.trimmed();
+
+ setResult(new Cantor::TextResult(error));
+
+ setStatus(Cantor::Expression::Error);
+ setErrorMessage(error);
}
-void RExpression::evaluationStarted()
+void RExpression::interrupt()
{
- setStatus(Cantor::Expression::Computing);
+ qDebug()<<"interrupting command";
+ if(status()==Cantor::Expression::Computing)
+ session()->interrupt();
+ setStatus(Cantor::Expression::Interrupted);
}
void RExpression::addInformation(const QString& information)
{
- static_cast(session())->sendInputToServer(information);
+ /* not using this anymore since it was making use of rserver
+ *
+ */
+// static_cast(session())->sendInputToServer(information);
}
void RExpression::showFilesAsResult(const QStringList& files)
diff --git a/src/backends/R/rsession.h b/src/backends/R/rsession.h
--- a/src/backends/R/rsession.h
+++ b/src/backends/R/rsession.h
@@ -28,12 +28,12 @@
#include "rserver_interface.h"
class RExpression;
-class KProcess;
+class QProcess;
class RSession : public Cantor::Session
{
- Q_OBJECT
- public:
+ Q_OBJECT
+public:
RSession( Cantor::Backend* backend);
~RSession();
@@ -46,24 +46,27 @@
Cantor::CompletionObject* completionFor(const QString& command, int index=-1);
QSyntaxHighlighter* syntaxHighlighter(QObject* parent);
- void queueExpression(RExpression* expr);
- void sendInputToServer(const QString& input);
+ void runExpression(RExpression* expr);
- protected Q_SLOTS:
- void serverChangedStatus(int status);
- void runNextExpression();
+protected Q_SLOTS:
void receiveSymbols(const QStringList& v, const QStringList & f);
void fillSyntaxRegExps(QVector& v, QVector& f);
- Q_SIGNALS:
+Q_SIGNALS:
void symbolsChanged();
- private:
- KProcess* m_rProcess;
- org::kde::Cantor::R* m_rServer;
- QList m_expressionQueue;
+public Q_SLOTS:
+ void readOutput();
+ void readError();
+ void processStarted();
+ void currentExpressionStatusChanged(Cantor::Expression::Status status);
+private:
+ QProcess* m_Process;
+ RExpression* m_CurrentExpression;
+ QString m_Output;
+ QString m_Error;
/* Available variables and functions, TODO make full classes and type info */
QStringList m_variables;
QStringList m_functions;
diff --git a/src/backends/R/rsession.cpp b/src/backends/R/rsession.cpp
--- a/src/backends/R/rsession.cpp
+++ b/src/backends/R/rsession.cpp
@@ -25,79 +25,169 @@
#include
#include
-#include
+#include
+#include
+
#include
-RSession::RSession( Cantor::Backend* backend) : Session(backend)
+RSession::RSession( Cantor::Backend* backend) : Session(backend),
+ m_Process(0),
+ m_CurrentExpression(0)
{
- qDebug();
- m_rProcess=0;
}
RSession::~RSession()
{
qDebug();
- m_rProcess->terminate();
+ m_Process->terminate();
}
void RSession::login()
{
qDebug()<<"login";
- if(m_rProcess)
- m_rProcess->deleteLater();
- m_rProcess=new KProcess(this);
- m_rProcess->setOutputChannelMode(KProcess::ForwardedChannels);
- (*m_rProcess)<start();
+ m_Process=new QProcess(this);
+ m_Process->setProcessChannelMode(QProcess::SeparateChannels);
- m_rServer=new org::kde::Cantor::R(QString::fromLatin1("org.kde.cantor_rserver-%1").arg(m_rProcess->pid()), QLatin1String("/R"), QDBusConnection::sessionBus(), this);
+ QString path = QStandardPaths::findExecutable(QLatin1String("R"));
+ qDebug() << path;
- 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&)));
+ if(QStandardPaths::findExecutable(QLatin1String("R")).isEmpty())
+ qDebug() << "Could not find the R exe" << endl;
- changeStatus(Cantor::Session::Done);
- connect(m_rServer, SIGNAL(ready()), this, SIGNAL(ready()));
+
+ m_Process->setProgram(QStandardPaths::findExecutable(QLatin1String("R")));
+ QStringList args;
+ /*
+ * interactive - forcing an interactive session
+ * quiet - don't print the startup message
+ * no-save - don't save the workspace after the end of session(when users quits). Should the user be allowed to save the session?
+ */
+ args.append(QLatin1String("--interactive"));
+ args.append(QLatin1String("--quiet"));
+ args.append(QLatin1String("--no-save"));
+ m_Process->setArguments(args);
+
+ connect(m_Process, SIGNAL(readyReadStandardOutput()), this, SLOT(readOutput()));
+ connect(m_Process, SIGNAL(readyReadStandardError()), this, SLOT(readError()));
+ connect(m_Process, SIGNAL(started()), this, SLOT(processStarted()));
+
+
+ m_Process->start();
+
+}
+
+
+void RSession::readOutput()
+{
+ while(m_Process->bytesAvailable()) {
+ m_Output.append(QString::fromLocal8Bit(m_Process->readLine()));
+ }
+
+ if(m_CurrentExpression && !m_Output.isEmpty() && m_Output.trimmed().endsWith(QLatin1String(">"))) {
+ m_CurrentExpression->parseOutput(m_Output);
+ m_Output.clear();
+ }
+}
+
+void RSession::readError()
+{
+ m_Error = QString::fromLocal8Bit(m_Process->readAllStandardError());
+ m_CurrentExpression->parseError(m_Error);
+ m_Error.clear();
+}
+
+void RSession::processStarted()
+{
+ qDebug() << m_Process->program() << " with pid " << m_Process->processId() << " started successfully " << endl;
+ emit ready();
}
void RSession::logout()
{
- qDebug()<<"logout";
- m_rProcess->terminate();
+ qDebug()<<"logout" << endl;
+
+ // this happens if the user gives quit command
+ if(status() == Cantor::Session::Running)
+ changeStatus(Cantor::Session::Done);
+
+ if(m_Process && m_Process->state() == QProcess::Running){
+ qDebug () << " Killing the process ";
+ m_Process->kill();
+ }
}
void RSession::interrupt()
{
- qDebug()<<"interrupt" << m_rProcess->pid();
- if (m_rProcess->pid())
- kill(m_rProcess->pid(), 2);
- m_expressionQueue.removeFirst();
+ qDebug()<<"interrupt" << m_Process->pid();
changeStatus(Cantor::Session::Done);
}
Cantor::Expression* RSession::evaluateExpression(const QString& cmd, Cantor::Expression::FinishingBehavior behave)
{
qDebug()<<"evaluating: "<setFinishingBehavior(behave);
expr->setCommand(cmd);
- expr->evaluate();
+ /* start evaluating only if the process is in running state
+ * imo this is a late check, can this be done somewhere before ?
+ */
+ if(m_Process && m_Process->state() == QProcess::NotRunning){
+ changeStatus(Cantor::Session::Done);
+ return expr;
+ }
- changeStatus(Cantor::Session::Running);
+ expr->evaluate();
return expr;
}
+void RSession::runExpression(RExpression* expr)
+{
+ m_CurrentExpression = expr;
+ connect(m_CurrentExpression, SIGNAL(statusChanged(Cantor::Expression::Status)), this, SLOT(currentExpressionStatusChanged(Cantor::Expression::Status)));
+
+ QString currentCmd = m_CurrentExpression->command();
+ currentCmd.trimmed();
+ currentCmd += QLatin1String("\n");
+
+ m_Process->write(currentCmd.toLocal8Bit());
+
+
+}
+
+void RSession::currentExpressionStatusChanged(Cantor::Expression::Status status)
+{
+ switch (status) {
+
+ case Cantor::Expression::Computing:
+ break;
+ case Cantor::Expression::Interrupted:
+ changeStatus(Cantor::Session::Done);
+ break;
+ case Cantor::Expression::Done:
+ case Cantor::Expression::Error:
+ changeStatus(Cantor::Session::Done);
+
+ }
+}
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;
+ /*
+ * since we won't be using rserver anymore, we will have to find a different method to make completion work
+ * can we use R's command line interface for this ?
+ */
+
+// 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;
+ return 0;
}
QSyntaxHighlighter* RSession::syntaxHighlighter(QObject* parent)
@@ -130,60 +220,5 @@
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);
-}
#include "rsession.moc"
diff --git a/src/backends/R/settings.kcfgc b/src/backends/R/settings.kcfgc
new file mode 100644
--- /dev/null
+++ b/src/backends/R/settings.kcfgc
@@ -0,0 +1,3 @@
+File=rbackend.kcfg
+ClassName=RBackendSettings
+Singleton=true