diff --git a/src/backends/R/rexpression.cpp b/src/backends/R/rexpression.cpp index b72ab7da..eba97d44 100644 --- a/src/backends/R/rexpression.cpp +++ b/src/backends/R/rexpression.cpp @@ -1,150 +1,146 @@ /* 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 */ #include "rexpression.h" #include "textresult.h" #include "imageresult.h" #include "helpresult.h" #include "epsresult.h" #include "rsession.h" #include #include #include #include #include #include #include RExpression::RExpression( Cantor::Session* session, bool internal ) : Cantor::Expression(session, internal), m_isHelpRequest(false) { } void RExpression::evaluate() { if(command().startsWith(QLatin1Char('?'))) m_isHelpRequest=true; else m_isHelpRequest=false; session()->enqueueExpression(this); } void RExpression::interrupt() { qDebug()<<"interrupting command"; setStatus(Cantor::Expression::Interrupted); } -void RExpression::finished(int returnCode, const QString& text) +void RExpression::parseOutput(const QString& text) { - if (status() == Expression::Interrupted) - return; + qDebug() << "output text: " << text; + if (!text.trimmed().isEmpty()) + addResult(new Cantor::TextResult(text)); + setStatus(Cantor::Expression::Done); +} - if(returnCode==RExpression::SuccessCode) - { - qDebug() << "text: " << text; - if (!text.trimmed().isEmpty()) - addResult(new Cantor::TextResult(text)); - setStatus(Cantor::Expression::Done); - }else if (returnCode==RExpression::ErrorCode) - { - qDebug() << "text: " << text; - setErrorMessage(text); - setStatus(Cantor::Expression::Error); - } +void RExpression::parseError(const QString& text) +{ + qDebug() << "error text: " << text; + setErrorMessage(text); + setStatus(Cantor::Expression::Error); } void RExpression::addInformation(const QString& information) { static_cast(session())->sendInputToServer(information); } void RExpression::showFilesAsResult(const QStringList& files) { qDebug()<<"showing files: "< */ #ifndef _REXPRESSION_H #define _REXPRESSION_H #include "expression.h" class RExpression : public Cantor::Expression { Q_OBJECT public: enum ServerReturnCode{SuccessCode=0, ErrorCode, InterruptedCode}; explicit RExpression( Cantor::Session*, bool internal = false); ~RExpression() override = default; void evaluate() override; void interrupt() override; - - void addInformation(const QString&) override; - - public Q_SLOTS: - void finished(int returnCode, const QString& text); + void parseOutput(const QString& text); + void parseError(const QString& text); void showFilesAsResult(const QStringList& files); + void addInformation(const QString&) override; private: bool m_isHelpRequest; }; #endif /* _REXPRESSION_H */ diff --git a/src/backends/R/rserver/org.kde.Cantor.R.xml b/src/backends/R/rserver/org.kde.Cantor.R.xml index 21c3996d..1cf4f49c 100644 --- a/src/backends/R/rserver/org.kde.Cantor.R.xml +++ b/src/backends/R/rserver/org.kde.Cantor.R.xml @@ -1,42 +1,40 @@ + - - - diff --git a/src/backends/R/rserver/rcallbacks.cpp b/src/backends/R/rserver/rcallbacks.cpp index 02f899be..0cd3c53d 100644 --- a/src/backends/R/rserver/rcallbacks.cpp +++ b/src/backends/R/rserver/rcallbacks.cpp @@ -1,119 +1,118 @@ /* 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 */ #include "rcallbacks.h" #include "rserver.h" #include #include #include #include RServer* server; Expression* currentExpression; void setupCallbacks(RServer* r) { - qDebug()<<"setting up callbacks"; + qDebug()<<"RServer: "<<"setting up callbacks"; server=r; currentExpression=nullptr; R_Outputfile=nullptr; R_Consolefile=nullptr; ptr_R_WriteConsole=nullptr; ptr_R_WriteConsoleEx=onWriteConsoleEx; ptr_R_ShowMessage=onShowMessage; ptr_R_Busy=onBusy; ptr_R_ReadConsole=onReadConsole; ptr_R_ShowFiles=onShowFiles; } void setCurrentExpression(Expression* expr) { currentExpression=expr; } enum OutputType { NormalOutput=0, ErrorOutput=1 }; void onWriteConsoleEx(const char* text, int size, int otype) { const QString string=QString::fromUtf8(text, size); if (otype==NormalOutput) { currentExpression->std_buffer+=string; }else { currentExpression->err_buffer+=string; } } void onShowMessage(const char* text) { const QString string=QString::fromUtf8(text); currentExpression->std_buffer+=string; } void onBusy(int which) { - qDebug()<<"onBusy: "<requestInput(QLatin1String(prompt)); if(input.size()>buflen) input.truncate(buflen); strcpy( (char*) buf, input.toStdString().c_str()); return input.size(); } int onShowFiles(int nfile, const char** file, const char** headers, const char* wtitle, Rboolean del, const char* pager) { int i; - qDebug()<<"show files: "; + qDebug()<<"RServer: "<<"show files: "; for (i=0;iaddFileToOutput(QString::fromLocal8Bit(file[i])); - server->showFiles(files); currentExpression->hasOtherResults=true; return 0; } diff --git a/src/backends/R/rserver/rserver.cpp b/src/backends/R/rserver/rserver.cpp index 0cdb3789..1d910e33 100644 --- a/src/backends/R/rserver/rserver.cpp +++ b/src/backends/R/rserver/rserver.cpp @@ -1,513 +1,511 @@ /* 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) 2010 Oleksiy Protas */ // TODO: setStatus in syntax and completions, to be or not to be? // on the one hand comme il faut, on another, causes flickering in UI #include "rserver.h" #include #include "radaptor.h" #include "rcallbacks.h" #include "settings.h" #include #include #include #include #include //R includes #include #include #include #include #define R_INTERFACE_PTRS #include RServer::RServer() : m_isInitialized(false),m_isCompletionAvailable(false) { new RAdaptor(this); m_tmpDir = QDir::tempPath() + QString::fromLatin1("/cantor_rserver-%1").arg(getpid()); QDir dir; dir.mkdir(m_tmpDir); - qDebug()<<"storing plots at "<integratePlots()) { - qDebug()<<"integrating plots"; + qDebug()<<"RServer: "<<"integrating plots"; newPlotDevice(); } //Loading automatic run scripts foreach (const QString& path, RServerSettings::self()->autorunScripts()) { int errorOccurred=0; if (QFile::exists(path)) R_tryEval(lang2(install("source"),mkString(path.toUtf8().data())),nullptr,&errorOccurred); // TODO: error handling else { - qDebug()<<(QLatin1String("Script ")+path+QLatin1String(" not found")); // FIXME: or should we throw a messagebox + qDebug()<<"RServer: "<<(QLatin1String("Script ")+path+QLatin1String(" not found")); // FIXME: or should we throw a messagebox } } - qDebug()<<"done initializing"; + qDebug()<<"RServer: "<<"done initializing"; } //Code from the RInside library void RServer::autoload() { #include "rautoloads.h" /* Autoload default packages and names from autoloads.h * * This function behaves in almost every way like * R's autoload: * function (name, package, reset = FALSE, ...) * { * if (!reset && exists(name, envir = .GlobalEnv, inherits = FALSE)) * stop("an object with that name already exists") * m <- match.call() * m[[1]] <- as.name("list") * newcall <- eval(m, parent.frame()) * newcall <- as.call(c(as.name("autoloader"), newcall)) * newcall$reset <- NULL * if (is.na(match(package, .Autoloaded))) * assign(".Autoloaded", c(package, .Autoloaded), env = .AutoloadEnv) * do.call("delayedAssign", list(name, newcall, .GlobalEnv, * .AutoloadEnv)) * invisible() * } * * What's missing is the updating of the string vector .Autoloaded with * the list of packages, which by my code analysis is useless and only * for informational purposes. * */ //void autoloads(void){ SEXP da, dacall, al, alcall, AutoloadEnv, name, package; int i,j, idx=0, errorOccurred, ptct; /* delayedAssign call*/ PROTECT(da = Rf_findFun(Rf_install("delayedAssign"), R_GlobalEnv)); PROTECT(AutoloadEnv = Rf_findVar(Rf_install(".AutoloadEnv"), R_GlobalEnv)); if (AutoloadEnv == R_NilValue){ - qDebug()<<"Cannot find .AutoloadEnv"; + qDebug()<<"RServer: "<<"Cannot find .AutoloadEnv"; //exit(1); } PROTECT(dacall = allocVector(LANGSXP,5)); SETCAR(dacall,da); /* SETCAR(CDR(dacall),name); */ /* arg1: assigned in loop */ /* SETCAR(CDR(CDR(dacall)),alcall); */ /* arg2: assigned in loop */ SETCAR(CDR(CDR(CDR(dacall))),R_GlobalEnv); /* arg3 */ SETCAR(CDR(CDR(CDR(CDR(dacall)))),AutoloadEnv); /* arg3 */ /* autoloader call */ PROTECT(al = Rf_findFun(Rf_install("autoloader"), R_GlobalEnv)); PROTECT(alcall = allocVector(LANGSXP,3)); SET_TAG(alcall, R_NilValue); /* just like do_ascall() does */ SETCAR(alcall,al); /* SETCAR(CDR(alcall),name); */ /* arg1: assigned in loop */ /* SETCAR(CDR(CDR(alcall)),package); */ /* arg2: assigned in loop */ ptct = 5; for(i = 0; i < packc; ++i){ idx += (i != 0)? packobjc[i-1] : 0; for (j = 0; j < packobjc[i]; ++j){ /*printf("autload(%s,%s)\n",packobj[idx+j],pack[i]);*/ PROTECT(name = NEW_CHARACTER(1)); PROTECT(package = NEW_CHARACTER(1)); SET_STRING_ELT(name, 0, COPY_TO_USER_STRING(packobj[idx+j])); SET_STRING_ELT(package, 0, COPY_TO_USER_STRING(pack[i])); /* Set up autoloader call */ PROTECT(alcall = allocVector(LANGSXP,3)); SET_TAG(alcall, R_NilValue); /* just like do_ascall() does */ SETCAR(alcall,al); SETCAR(CDR(alcall),name); SETCAR(CDR(CDR(alcall)),package); /* Setup delayedAssign call */ SETCAR(CDR(dacall),name); SETCAR(CDR(CDR(dacall)),alcall); R_tryEval(dacall,R_GlobalEnv,&errorOccurred); if (errorOccurred){ - qDebug()<<"Error calling delayedAssign!"; + qDebug()<<"RServer: "<<"Error calling delayedAssign!"; //exit(1); } ptct += 3; } } UNPROTECT(ptct); /* Initialize the completion libraries if needed, adapted from sys-std.c of R */ // TODO: should we do this or init on demand? // if (completion is needed) // TODO: discuss how to pass parameter { /* First check if namespace is loaded */ if (findVarInFrame(R_NamespaceRegistry,install("utils"))==R_UnboundValue) { /* Then try to load it */ SEXP cmdSexp, cmdexpr; ParseStatus status; int i; const char *p="try(loadNamespace('rcompgen'), silent=TRUE)"; PROTECT(cmdSexp=mkString(p)); cmdexpr=PROTECT(R_ParseVector(cmdSexp,-1,&status,R_NilValue)); if(status==PARSE_OK) { for(i=0;icmd=cmd; expr->hasOtherResults=false; setStatus(RServer::Busy); setCurrentExpression(expr); expr->std_buffer.clear(); expr->err_buffer.clear(); ReturnCode returnCode=RServer::SuccessCode; QString returnText; QStringList neededFiles; //Code to evaluate an R function (taken from RInside library) ParseStatus status; SEXP cmdSexp, cmdexpr = R_NilValue; - SEXP result; + SEXP result = nullptr; int i, errorOccurred; QByteArray memBuf; memBuf.append(cmd.toUtf8()); PROTECT(cmdSexp = allocVector(STRSXP, 1)); SET_STRING_ELT(cmdSexp, 0, mkChar((char*)memBuf.data())); cmdexpr = PROTECT(R_ParseVector(cmdSexp, -1, &status, R_NilValue)); switch (status) { case PARSE_OK: - qDebug()<<"PARSING "< 1 */ for (i = 0; i < length(cmdexpr); ++i) { result = R_tryEval(VECTOR_ELT(cmdexpr, i), nullptr, &errorOccurred); if (errorOccurred) { - qDebug()<<"Error occurred."; + qDebug()<<"RServer: "<<"Error occurred."; break; } // TODO: multiple results } memBuf.clear(); break; case PARSE_INCOMPLETE: /* need to read another line */ - qDebug()<<"parse incomplete.."; + qDebug()<<"RServer: "<<"parse incomplete.."; break; case PARSE_NULL: - qDebug()<<"ParseStatus is null: "<std_buffer<<" err: "<err_buffer; + qDebug()<<"RServer: "<<"result: " << result << " std: "<std_buffer<<" err: "<err_buffer; //if the command didn't print anything on its own, print the result + //but only, if result exists, because comment expression don't create result //TODO: handle some known result types like lists, matrices separately // to make the output look better, by using html (tables etc.) - if(expr->std_buffer.isEmpty()&&expr->err_buffer.isEmpty()) + if(result && expr->std_buffer.isEmpty()&&expr->err_buffer.isEmpty()) { - qDebug()<<"printing result..."; + qDebug()<<"RServer: "<<"printing result..."; SEXP count=PROTECT(R_tryEval(lang2(install("length"),result),nullptr,&errorOccurred)); // TODO: error checks if (*INTEGER(count)==0) - qDebug() << "no result, so show nothing"; + qDebug()<<"RServer: " << "no result, so show nothing"; else Rf_PrintValue(result); UNPROTECT(1); } setCurrentExpression(nullptr); //is this save? if(!expr->err_buffer.isEmpty()) { returnCode=RServer::ErrorCode; returnText=expr->err_buffer; } else { returnCode=RServer::SuccessCode; returnText=expr->std_buffer; } }else { returnCode=RServer::ErrorCode; returnText=i18n("Error Parsing Command"); } if(internal) { - qDebug()<<"internal result: "<hasOtherResults=true; newPlotDevice(); neededFiles<hasOtherResults) - emit expressionFinished(returnCode, returnText); - else - showFiles(neededFiles); + qDebug()<<"RServer: " << "files: " << neededFiles+m_expressionFiles; + emit expressionFinished(returnCode, returnText, neededFiles+m_expressionFiles); setStatus(Idle); } void RServer::completeCommand(const QString& cmd) { // setStatus(RServer::Busy); // TODO: is static okay? guess RServer is a singletone, but ... // TODO: error handling? // TODO: investigate encoding problem // TODO: propage the flexibility of token selection upward // TODO: what if install() fails? investigate // TODO: investigate why errors break the whole foodchain of RServer callbacks in here static SEXP comp_env=R_FindNamespace(mkString("utils")); static SEXP tokenizer_func=install(".guessTokenFromLine"); static SEXP linebuffer_func=install(".assignLinebuffer"); static SEXP buffer_end_func=install(".assignEnd"); static SEXP complete_func=install(".completeToken"); static SEXP retrieve_func=install(".retrieveCompletions"); /* Setting buffer parameters */ int errorOccurred=0; // TODO: error cheks, too lazy to do it now R_tryEval(lang2(linebuffer_func,mkString(cmd.toUtf8().data())),comp_env,&errorOccurred); R_tryEval(lang2(buffer_end_func,ScalarInteger(cmd.size())),comp_env,&errorOccurred); /* Passing the tokenizing work to professionals */ SEXP token=PROTECT(R_tryEval(lang1(tokenizer_func),comp_env,&errorOccurred)); /* Doing the actual stuff */ R_tryEval(lang1(complete_func),comp_env,&errorOccurred); SEXP completions=PROTECT(R_tryEval(lang1(retrieve_func),comp_env,&errorOccurred)); /* Populating the list of completions */ QStringList completionOptions; for (int i=0;i */ #ifndef _RSERVER_H #define _RSERVER_H #include class Expression { public: QString cmd; int returnCode; bool hasOtherResults; QString err_buffer; QString std_buffer; }; class RServer : public QObject { Q_OBJECT Q_CLASSINFO("D-Bus Interface", "org.kde.Cantor.R") public: enum Status { Idle=0, Busy }; enum ReturnCode { SuccessCode=0, ErrorCode, InterruptedCode}; RServer( ); ~RServer() override; void initR(); void autoload(); void endR(); QString requestInput(const QString& prompt); - void showFiles(const QStringList& files); + void addFileToOutput(const QString& file); Q_SIGNALS: void ready(); void statusChanged(int status); - void expressionFinished(int returnCode, const QString& text); + void expressionFinished(int returnCode, const QString& text, const QStringList& files); void completionFinished(const QString& token,const QStringList& options); - void showFilesNeeded(const QStringList& files); void inputRequested(const QString& prompt); void requestAnswered(); void symbolList(const QStringList& variables, const QStringList& values, const QStringList& functions); public Q_SLOTS: void runCommand(const QString& cmd, bool internal=false); void answerRequest(const QString& answer); void completeCommand(const QString& cmd); // TODO: comment properly, only takes command from start to cursor void listSymbols(); private: void setStatus(Status status); void newPlotDevice(); private: bool m_isInitialized; bool m_isCompletionAvailable; Status m_status; QString m_requestCache; QString m_tmpDir; QString m_curPlotFile; + QStringList m_expressionFiles; }; #endif /* _RSERVER_H */ diff --git a/src/backends/R/rsession.cpp b/src/backends/R/rsession.cpp index c5cd0f72..4848e771 100644 --- a/src/backends/R/rsession.cpp +++ b/src/backends/R/rsession.cpp @@ -1,183 +1,204 @@ /* 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 "rvariablemodel.h" #include #include #include #include #ifndef Q_OS_WIN #include #endif RSession::RSession(Cantor::Backend* backend) : Session(backend), m_process(nullptr), m_rServer(nullptr) { setVariableModel(new RVariableModel(this)); } RSession::~RSession() { 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->setProcessChannelMode(QProcess::ForwardedErrorChannel); 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)), Qt::QueuedConnection); - connect(m_rServer, SIGNAL(symbolList(QStringList,QStringList,QStringList)), variableModel(), SLOT(parseResult(QStringList,QStringList,QStringList))); + connect(m_rServer, &org::kde::Cantor::R::statusChanged, this, &RSession::serverChangedStatus); + connect(m_rServer, &org::kde::Cantor::R::symbolList, static_cast(variableModel()), &RVariableModel::parseResult); + connect(m_rServer, &org::kde::Cantor::R::expressionFinished, this, &RSession::expressionFinished); + connect(m_rServer, &org::kde::Cantor::R::inputRequested, this, &RSession::inputRequested); changeStatus(Session::Done); emit loginDone(); qDebug()<<"login done"; } void RSession::logout() { qDebug()<<"logout"; m_process->terminate(); variableModel()->clearVariables(); variableModel()->clearFunctions(); emit symbolsChanged(); changeStatus(Status::Disable); } void RSession::interrupt() { if(!expressionQueue().isEmpty()) { qDebug()<<"interrupting " << expressionQueue().first()->command(); if(m_process->state() != QProcess::NotRunning) { #ifndef Q_OS_WIN const int pid=m_process->pid(); kill(pid, SIGINT); #else ; //TODO: interrupt the process on windows #endif } - foreach (Cantor::Expression* expression, expressionQueue()) + foreach (Cantor::Expression* expression, expressionQueue()) expression->setStatus(Cantor::Expression::Interrupted); expressionQueue().clear(); qDebug()<<"done interrupting"; } changeStatus(Cantor::Session::Done); } Cantor::Expression* RSession::evaluateExpression(const QString& cmd, Cantor::Expression::FinishingBehavior behave, bool internal) { qDebug()<<"evaluating: "<setFinishingBehavior(behave); expr->setCommand(cmd); expr->evaluate(); return expr; } Cantor::CompletionObject* RSession::completionFor(const QString& command, int index) { RCompletionObject *cmp=new RCompletionObject(command, index, this); connect(m_rServer,SIGNAL(completionFinished(QString,QStringList)),cmp,SLOT(receiveCompletions(QString,QStringList))); connect(cmp,SIGNAL(requestCompletion(QString)),m_rServer,SLOT(completeCommand(QString))); return cmp; } QSyntaxHighlighter* RSession::syntaxHighlighter(QObject* parent) { return new RHighlighter(parent, this); } void RSession::serverChangedStatus(int status) { qDebug()<<"changed status to "<command(); - } - finishFirstExpression(); + if(expressionQueue().isEmpty()) + changeStatus(Cantor::Session::Done); } else changeStatus(Cantor::Session::Running); } +void RSession::expressionFinished(int returnCode, const QString& text, const QStringList& files) +{ + if (!expressionQueue().isEmpty()) + { + RExpression* expr = static_cast(expressionQueue().first()); + if (expr->status() == Cantor::Expression::Interrupted) + return; + + if (!files.isEmpty()) + expr->showFilesAsResult(files); + + if(returnCode==RExpression::SuccessCode) + expr->parseOutput(text); + else if (returnCode==RExpression::ErrorCode) + expr->parseError(text); + + qDebug()<<"done running "<command(); + finishFirstExpression(); + } +} + void RSession::runFirstExpression() { if (expressionQueue().isEmpty()) return; - disconnect(m_rServer, SIGNAL(expressionFinished(int,QString)), nullptr, nullptr); - disconnect(m_rServer, SIGNAL(inputRequested(QString)), nullptr, nullptr); - disconnect(m_rServer, SIGNAL(showFilesNeeded(QStringList)), nullptr, nullptr); - qDebug()<<"size: "<(expressionQueue().first()); qDebug()<<"running expression: "<command(); - connect(m_rServer, SIGNAL(expressionFinished(int,QString)), expr, SLOT(finished(int,QString))); - connect(m_rServer, SIGNAL(inputRequested(QString)), expr, SIGNAL(needsAdditionalInformation(QString))); - connect(m_rServer, SIGNAL(showFilesNeeded(QStringList)), expr, SLOT(showFilesAsResult(QStringList))); - expr->setStatus(Cantor::Expression::Computing); - m_rServer->runCommand(expr->command()); + m_rServer->runCommand(expr->internalCommand()); + changeStatus(Cantor::Session::Running); } void RSession::sendInputToServer(const QString& input) { QString s=input; if(!input.endsWith(QLatin1Char('\n'))) s+=QLatin1Char('\n'); m_rServer->answerRequest(s); } +void RSession::inputRequested(QString info) +{ + if (expressionQueue().isEmpty()) + return; + + emit expressionQueue().first()->needsAdditionalInformation(info); +} + void RSession::updateSymbols() { m_rServer->listSymbols(); } diff --git a/src/backends/R/rsession.h b/src/backends/R/rsession.h index 1ef38913..6bee0231 100644 --- a/src/backends/R/rsession.h +++ b/src/backends/R/rsession.h @@ -1,68 +1,70 @@ /* 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 */ #ifndef _RSESSION_H #define _RSESSION_H #include #include #include "session.h" #include "rserver_interface.h" class RExpression; class RVariableModel; class QProcess; namespace Cantor { class DefaultVariableModel; } class RSession : public Cantor::Session { Q_OBJECT public: explicit RSession( Cantor::Backend* backend); ~RSession() override; void login() override; void logout() override; void interrupt() override; Cantor::Expression* evaluateExpression(const QString& command, Cantor::Expression::FinishingBehavior behave = Cantor::Expression::FinishingBehavior::DoNotDelete, bool internal = false) override; Cantor::CompletionObject* completionFor(const QString& command, int index=-1) override; QSyntaxHighlighter* syntaxHighlighter(QObject* parent) override; void runFirstExpression() override; void sendInputToServer(const QString& input); void updateSymbols(); protected Q_SLOTS: void serverChangedStatus(int status); + void expressionFinished(int returnCode, const QString& text, const QStringList& files); + void inputRequested(QString info); Q_SIGNALS: void symbolsChanged(); private: QProcess* m_process; org::kde::Cantor::R* m_rServer; }; #endif /* _RSESSION_H */