diff --git a/src/backends/R/rbackend.cpp b/src/backends/R/rbackend.cpp index 19bfbfec..070fcdbb 100644 --- a/src/backends/R/rbackend.cpp +++ b/src/backends/R/rbackend.cpp @@ -1,105 +1,107 @@ /* 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 "rbackend.h" #include "rsession.h" #include "rextensions.h" #include "settings.h" #include "rsettingswidget.h" #include #include "cantor_macros.h" #include RBackend::RBackend( QObject* parent,const QList args ) : Cantor::Backend( parent,args ) { setObjectName(QLatin1String("rbackend")); qDebug()<<"Creating RBackend"; new RScriptExtension(this); new RPlotExtension(this); + new RVariableManagementExtension(this); } RBackend::~RBackend() { qDebug()<<"Destroying RBackend"; } QString RBackend::id() const { return QLatin1String("r"); } QString RBackend::version() const { return QLatin1String("Undefined"); } Cantor::Session* RBackend::createSession() { qDebug()<<"Spawning a new R session"; return new RSession(this); } Cantor::Backend::Capabilities RBackend::capabilities() const { qDebug()<<"Requesting capabilities of RSession"; return Cantor::Backend::InteractiveMode | Cantor::Backend::SyntaxHighlighting | - Cantor::Backend::Completion; + Cantor::Backend::Completion | + Cantor::Backend::VariableManagement; } bool RBackend::requirementsFullfilled() const { QFileInfo info(QStandardPaths::findExecutable( QLatin1String("cantor_rserver") ) ); return info.isExecutable(); } QWidget* RBackend::settingsWidget(QWidget* parent) const { return new RSettingsWidget(parent); } KConfigSkeleton* RBackend::config() const { return RServerSettings::self(); } QUrl RBackend::helpUrl() const { return QUrl(i18nc("the url to the documentation of R, please check if there is a translated version and use the correct url", "http://rwiki.sciviews.org/doku.php?id=rdoc:rdoc")); } QString RBackend::description() const { return i18n("R is a language and environment for statistical computing and graphics, similar to the S language and environment.
"\ "It provides a wide variety of statistical (linear and nonlinear modelling, "\ "classical statistical tests, time-series analysis, classification, clustering, ...) "\ "and graphical techniques, and is highly extensible. The S language is often the "\ "vehicle of choice for research in statistical methodology, "\ "and R provides an Open Source route to participation in that activity."); } K_PLUGIN_FACTORY_WITH_JSON(rbackend, "rbackend.json", registerPlugin();) #include "rbackend.moc" diff --git a/src/backends/R/rextensions.cpp b/src/backends/R/rextensions.cpp index 1a805529..57a39dfc 100644 --- a/src/backends/R/rextensions.cpp +++ b/src/backends/R/rextensions.cpp @@ -1,67 +1,110 @@ /* 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 "rextensions.h" #include RScriptExtension::RScriptExtension(QObject* parent) : Cantor::ScriptExtension(parent) { } RScriptExtension::~RScriptExtension() { } QString RScriptExtension::runExternalScript(const QString& path) { return QString::fromLatin1("source(\"%1\")").arg(path); } QString RScriptExtension::scriptFileFilter() { return i18n("R script file (*.R)"); } QString RScriptExtension::highlightingMode() { return QLatin1String("r script"); } RPlotExtension::RPlotExtension(QObject* parent) : Cantor::AdvancedPlotExtension(parent) { } // TODO: injection prevention QString RPlotExtension::accept(const Cantor::PlotTitleDirective& directive) const { return QLatin1String("main=\"")+directive.title()+QLatin1String("\""); } QString RPlotExtension::accept(const Cantor::OrdinateScaleDirective& directive) const { return QLatin1String("ylim=range(")+QString::number(directive.min())+QLatin1String(",")+QString::number(directive.max())+QLatin1String(")"); } QString RPlotExtension::accept(const Cantor::AbscissScaleDirective& directive) const { return QLatin1String("xlim=range(")+QString::number(directive.min())+QLatin1String(",")+QString::number(directive.max())+QLatin1String(")"); } + +RVariableManagementExtension::RVariableManagementExtension(QObject* parent) : Cantor::VariableManagementExtension(parent) +{ + +} + + +RVariableManagementExtension::~RVariableManagementExtension() +{ + +} + +QString RVariableManagementExtension::addVariable(const QString& name, const QString& value) + { + return setValue(name, value); + } + +QString RVariableManagementExtension::setValue(const QString& name, const QString& value) + { + return QString::fromLatin1("%1 = %2").arg(name).arg(value); + } + +QString RVariableManagementExtension::removeVariable(const QString& name) + { + return QString::fromLatin1("remove(%1)").arg(name); + } + +QString RVariableManagementExtension::saveVariables(const QString& fileName) + { + Q_UNUSED(fileName); + return QString(); + } + +QString RVariableManagementExtension::loadVariables(const QString& fileName) + { + Q_UNUSED(fileName); + return QString(); + } + +QString RVariableManagementExtension::clearVariables() + { + return QLatin1String("rm(list=ls())"); + } diff --git a/src/backends/R/rextensions.h b/src/backends/R/rextensions.h index fe8df759..f33437ca 100644 --- a/src/backends/R/rextensions.h +++ b/src/backends/R/rextensions.h @@ -1,54 +1,67 @@ /* 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 _REXTENSIONS_H #define _REXTENSIONS_H #include "extension.h" #include "directives/plotdirectives.h" class RScriptExtension : public Cantor::ScriptExtension { public: RScriptExtension(QObject* parent); ~RScriptExtension(); public Q_SLOTS: QString runExternalScript(const QString& path) override; QString scriptFileFilter() override; QString highlightingMode() override; }; class RPlotExtension : public Cantor::AdvancedPlotExtension, public Cantor::AdvancedPlotExtension::DirectiveAcceptor, public Cantor::AdvancedPlotExtension::DirectiveAcceptor, public Cantor::AdvancedPlotExtension::DirectiveAcceptor { public: RPlotExtension(QObject* parent); ~RPlotExtension() {} QString accept(const Cantor::PlotTitleDirective&) const override; QString accept(const Cantor::OrdinateScaleDirective&) const override; QString accept(const Cantor::AbscissScaleDirective&) const override; protected: QString plotCommand() const override { return QLatin1String("plot"); } }; +class RVariableManagementExtension : public Cantor::VariableManagementExtension +{ + public: + RVariableManagementExtension(QObject* parent); + ~RVariableManagementExtension(); + QString addVariable(const QString& name, const QString& value) Q_DECL_OVERRIDE; + QString setValue(const QString& name, const QString& value) Q_DECL_OVERRIDE; + QString removeVariable(const QString& name) Q_DECL_OVERRIDE; + QString saveVariables(const QString& fileName) Q_DECL_OVERRIDE; + QString loadVariables(const QString& fileName) Q_DECL_OVERRIDE; + QString clearVariables() Q_DECL_OVERRIDE; +}; + #endif /* _REXTENSIONS_H */ diff --git a/src/backends/R/rserver/org.kde.Cantor.R.xml b/src/backends/R/rserver/org.kde.Cantor.R.xml index 42381e3e..21c3996d 100644 --- a/src/backends/R/rserver/org.kde.Cantor.R.xml +++ b/src/backends/R/rserver/org.kde.Cantor.R.xml @@ -1,41 +1,42 @@ + diff --git a/src/backends/R/rserver/rserver.cpp b/src/backends/R/rserver/rserver.cpp index a5f9ef38..d3335578 100644 --- a/src/backends/R/rserver/rserver.cpp +++ b/src/backends/R/rserver/rserver.cpp @@ -1,507 +1,513 @@ /* 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"; 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())),NULL,&errorOccurred); // TODO: error handling else { qDebug()<<(QLatin1String("Script ")+path+QLatin1String(" not found")); // FIXME: or should we throw a messagebox } } qDebug()<<"done initializing"; // FIXME: other way to search symbols, see listSymbols for details listSymbols(); } //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"; //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!"; //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; 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), NULL, &errorOccurred); if (errorOccurred) { qDebug()<<"Error occurred."; break; } // TODO: multiple results } memBuf.clear(); break; case PARSE_INCOMPLETE: /* need to read another line */ qDebug()<<"parse incomplete.."; break; case PARSE_NULL: qDebug()<<"ParseStatus is null: "<std_buffer<<" err: "<err_buffer; //if the command didn't print anything on its own, print the result //TODO: handle some known result types like lists, matrices spearately // to make the output look better, by using html (tables etc.) if(expr->std_buffer.isEmpty()&&expr->err_buffer.isEmpty()) { qDebug()<<"printing result..."; SEXP count=PROTECT(R_tryEval(lang2(install("length"),result),NULL,&errorOccurred)); // TODO: error checks if (*INTEGER(count)==0) qDebug() << "no result, so show nothing"; else Rf_PrintValue(result); UNPROTECT(1); } setCurrentExpression(0); //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); setStatus(Idle); // FIXME: Calling this every evaluation is probably ugly listSymbols(); } 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(); void initR(); void autoload(); void endR(); QString requestInput(const QString& prompt); void showFiles(const QStringList& files); Q_SIGNALS: void ready(); void statusChanged(int status); void expressionFinished(int returnCode, const QString& text); 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& functions); + 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; }; #endif /* _RSERVER_H */ diff --git a/src/backends/R/rsession.cpp b/src/backends/R/rsession.cpp index ce73fd92..81786f64 100644 --- a/src/backends/R/rsession.cpp +++ b/src/backends/R/rsession.cpp @@ -1,195 +1,205 @@ /* 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 #include #ifndef Q_OS_WIN #include #endif -RSession::RSession(Cantor::Backend* backend) : Session(backend), m_process(nullptr), m_rServer(nullptr) +RSession::RSession(Cantor::Backend* backend) : Session(backend), m_process(nullptr), m_rServer(nullptr), m_variableModel(new Cantor::DefaultVariableModel(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->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&))); + connect(m_rServer, SIGNAL(symbolList(const QStringList&, const QStringList&, const QStringList&)),this,SLOT(receiveSymbols(const QStringList&, 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) +void RSession::receiveSymbols(const QStringList& vars, const QStringList& values, const QStringList & funcs) { - m_variables=v; - m_functions=f; + m_variables = vars; + for (int i = 0; i < vars.count(); i++) + { + m_variableModel->addVariable(vars[i], values[i]); + } + m_functions = funcs; 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); } + +QAbstractItemModel* RSession::variableModel() +{ + return m_variableModel; +} \ No newline at end of file diff --git a/src/backends/R/rsession.h b/src/backends/R/rsession.h index 3f8f5afd..f76a790a 100644 --- a/src/backends/R/rsession.h +++ b/src/backends/R/rsession.h @@ -1,71 +1,77 @@ /* 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 QProcess; +namespace Cantor { +class DefaultVariableModel; +} + class RSession : public Cantor::Session { Q_OBJECT public: RSession( Cantor::Backend* backend); ~RSession(); void login() override; void logout() override; void interrupt() override; Cantor::Expression* evaluateExpression(const QString& command, Cantor::Expression::FinishingBehavior behave) override; Cantor::CompletionObject* completionFor(const QString& command, int index=-1) override; QSyntaxHighlighter* syntaxHighlighter(QObject* parent) override; + QAbstractItemModel* variableModel() Q_DECL_OVERRIDE; void queueExpression(RExpression* expr); void sendInputToServer(const QString& input); protected Q_SLOTS: void serverChangedStatus(int status); void runNextExpression(); - void receiveSymbols(const QStringList& v, const QStringList & f); + void receiveSymbols(const QStringList& vars, const QStringList& values, const QStringList & funcs); void fillSyntaxRegExps(QVector& v, QVector& f); Q_SIGNALS: void symbolsChanged(); private: QProcess* m_process; org::kde::Cantor::R* m_rServer; QList m_expressionQueue; /* Available variables and functions, TODO make full classes and type info */ + Cantor::DefaultVariableModel* m_variableModel; QStringList m_variables; QStringList m_functions; }; #endif /* _RSESSION_H */