Commit 85d88cd1 authored by Rishabh Gupta's avatar Rishabh Gupta Committed by Filipe Saraiva

Port Lua backend to QProcess

* setup communication between Cantor and Lua interpreter through QProcess
* use Lua interpreter for all the calculations
* use Lua C Api for tab completion

Commit from https://phabricator.kde.org/R55:4b1142d556601b68968ffb78369282060bda6ecb
parent 6ad659fc
......@@ -32,8 +32,8 @@
#include <QString>
#include <QStringList>
LuaExpression::LuaExpression( Cantor::Session* session, lua_State* L)
: Cantor::Expression(session), m_L(L)
LuaExpression::LuaExpression( Cantor::Session* session)
: Cantor::Expression(session)
{
}
......@@ -43,58 +43,36 @@ LuaExpression::~LuaExpression()
void LuaExpression::evaluate()
{
QString ret;
Cantor::Expression::Status status;
execute(ret, status);
if(status == Cantor::Expression::Done)
{
QString cmd = command().simplified();
if( cmd.startsWith(QLatin1String("show(")) || cmd.startsWith(QLatin1String("show (")) )
setResult(new Cantor::ImageResult(QUrl::fromLocalFile(ret), ret));
else
setResult(new Cantor::TextResult(ret));
}
else
{
setErrorMessage(ret);
/*
* start evaluating the current expression
* set the status to computing
* decide what needs to be done if the user is trying to define a function etc
*/
setStatus(Cantor::Expression::Computing);
if (command().isEmpty()) {
setStatus(Cantor::Expression::Done);
return;
}
setStatus(status);
LuaSession* currentSession = dynamic_cast<LuaSession*>(session());
currentSession->runExpression(this);
}
void LuaExpression::interrupt()
void LuaExpression::parseOutput(QString &output)
{
setStatus(Cantor::Expression::Interrupted);
}
void LuaExpression::execute(QString& ret, Cantor::Expression::Status& status)
{
int top = lua_gettop(m_L);
// execute the command
QString err = luahelper_dostring(m_L, QLatin1String("return ") + command() ); // try to return values...
if( !err.isNull() ) err = luahelper_dostring(m_L, command() ); // try the original expression
output.replace(command(), QLatin1String(""));
output.replace(QLatin1String("return"), QLatin1String(""));
output.replace(QLatin1String(">"), QLatin1String(""));
output = output.trimmed();
if( err.isNull() )
{
QStringList list;
int n_out = lua_gettop(m_L) - top;
qDebug() << "final output of the command " << command() << ": " << output << endl;
for(int i = -n_out; i < 0; ++i)
list << luahelper_tostring(m_L, i);
setResult(new Cantor::TextResult(output));
ret = list.join(QLatin1String("\n")) + luahelper_getprinted(m_L);
status = Cantor::Expression::Done;
}
else
{
qDebug() << "error when executing" << command() << ":" << err;
ret = err;
status = Cantor::Expression::Error;
}
lua_settop(m_L, top);
setStatus(Cantor::Expression::Done);
}
void LuaExpression::interrupt()
{
setStatus(Cantor::Expression::Interrupted);
}
......@@ -30,17 +30,13 @@ class LuaExpression : public Cantor::Expression
Q_OBJECT
public:
LuaExpression( Cantor::Session* session, lua_State* L);
LuaExpression( Cantor::Session* session);
~LuaExpression();
void evaluate();
void interrupt();
void parseOutput(QString& output);
private:
// evaluates an expression, executing it on the Lua state and building an adequate response
void execute(QString& ret, Cantor::Expression::Status& status);
lua_State* m_L;
};
#endif /* _LUAEXPRESSION_H */
......@@ -26,7 +26,12 @@
#include <settings.h>
#include "ui_settings.h"
LuaSession::LuaSession( Cantor::Backend* backend) : Session(backend)
#include <QProcess>
LuaSession::LuaSession( Cantor::Backend* backend) :
Session(backend),
m_process(0),
m_currentExpression(0)
{
}
......@@ -38,45 +43,81 @@ void LuaSession::login()
{
emit loginStarted();
/*
* setup Qprocess here
* load the autoscripts
*/
m_process = new QProcess(this);
m_process->setProgram(QLatin1String("/usr/bin/lua"));
m_process->setArguments(QStringList() << QLatin1String("-i"));
m_process->setProcessChannelMode(QProcess::SeparateChannels);
connect(m_process, SIGNAL(readyReadStandardOutput()), this, SLOT(readIntroMessage()));
connect(m_process, SIGNAL(started()), this, SLOT(processStarted()));
m_process->start();
// we need this for tab completion
m_L = luaL_newstate();
luaL_openlibs(m_L);
QStringList errors;
errors << luahelper_dostring(m_L, QLatin1String("__cantor = {}"));
changeStatus(Cantor::Session::Done);
emit loginDone();
}
void LuaSession::readIntroMessage()
{
while(m_process->bytesAvailable()) {
m_output.append(QString::fromLocal8Bit(m_process->readLine()));
}
errors << luahelper_dostring(m_L,
QLatin1String("function print(...)\n"
"local t = {}\n"
"for i = 1, select('#',...) do\n"
"local a = select(i,...)\n"
"t[i] = tostring(a)\n"
"end\n"
"table.insert(__cantor, table.concat(t,'\t'))\n"
" end"));
if(!m_output.isEmpty() && m_output.trimmed().endsWith(QLatin1String(">"))) {
qDebug() << " reading the intro message " << m_output ;
m_output.clear();
errors << luahelper_dostring(m_L,
QLatin1String("function show(a)\n"
"assert(type(a) == 'string')\n"
"return a\n"
"end"));
disconnect(m_process, SIGNAL(readyReadStandardOutput()), this , SLOT(readIntroMessage()));
connect(m_process, SIGNAL(readyReadStandardOutput()), this, SLOT(readOutput()));
connect(m_process, SIGNAL(readyReadStandardError()), this, SLOT(readError()));
}
}
if(!errors.empty())
qDebug() << errors.join(QLatin1String("\n"));
void LuaSession::readOutput()
{
/*
* parse the output
* clear all the garbage
* set it as output
*/
// keep reading till the output ends with '>'.
// '>' marks the end of output for a particular command;
while(m_process->bytesAvailable()) {
m_output.append(QString::fromLocal8Bit(m_process->readLine()));
}
if(m_currentExpression && !m_output.isEmpty() && m_output.trimmed().endsWith(QLatin1String(">"))) {
// we have our complete output
// clean the output and parse it and clear m_output;
m_currentExpression->parseOutput(m_output);
m_output.clear();
foreach (const QString &str, LuaSettings::self()->autorunScripts())
evaluateExpression(QLatin1String("dofile('") + str + QLatin1String("')"), Cantor::Expression::DeleteOnFinish);
}
changeStatus(Cantor::Session::Done);
emit loginDone();
}
void LuaSession::readError()
{
qDebug() << m_process->readAllStandardError() << endl;
}
void LuaSession::processStarted()
{
qDebug() << m_process->program() << " pid " << m_process->processId() << " started " << endl;
}
void LuaSession::logout()
{
if(m_L)
{
lua_close(m_L);
m_L = 0;
}
if(m_process)
m_process->kill();
}
void LuaSession::interrupt()
......@@ -89,13 +130,28 @@ Cantor::Expression* LuaSession::evaluateExpression(const QString& cmd, Cantor::E
{
changeStatus(Cantor::Session::Running);
LuaExpression* expr = new LuaExpression(this, m_L);
connect(expr, &LuaExpression::statusChanged, this, &LuaSession::expressionFinished);
expr->setFinishingBehavior(behave);
expr->setCommand(cmd);
expr->evaluate();
m_currentExpression = new LuaExpression(this);
connect(m_currentExpression, SIGNAL(statusChanged(Cantor::Expression::Status)), this, SLOT(expressionFinished(Cantor::Expression::Status)));
m_currentExpression->setFinishingBehavior(behave);
m_currentExpression->setCommand(cmd);
m_currentExpression->evaluate();
return m_currentExpression;
}
void LuaSession::runExpression(LuaExpression *currentExpression)
{
/*
* get the current command
* format it and write to m_process
*/
QString command = currentExpression->command();
command += QLatin1String("\n");
return expr;
qDebug() << "final command to be executed " << command << endl;
m_process->write(command.toLocal8Bit());
}
Cantor::CompletionObject* LuaSession::completionFor(const QString& command, int index)
......@@ -103,10 +159,19 @@ Cantor::CompletionObject* LuaSession::completionFor(const QString& command, int
return new LuaCompletionObject(command, index, this);
}
void LuaSession::expressionFinished()
void LuaSession::expressionFinished(Cantor::Expression::Status status)
{
// synchronous
changeStatus(Cantor::Session::Done);
switch(status) {
case Cantor::Expression::Computing:
break;
case Cantor::Expression::Done:
case Cantor::Expression::Error:
case Cantor::Expression::Interrupted:
changeStatus(Cantor::Session::Done);
break;
}
}
QSyntaxHighlighter* LuaSession::syntaxHighlighter(QObject* parent)
......@@ -119,4 +184,3 @@ lua_State* LuaSession::getState() const
{
return m_L;
}
......@@ -25,6 +25,7 @@
#include <lua.hpp>
class LuaExpression;
class QProcess;
class LuaSession : public Cantor::Session
{
......@@ -38,16 +39,27 @@ public:
void interrupt();
void runExpression(LuaExpression* currentExpression);
Cantor::Expression* evaluateExpression(const QString& command, Cantor::Expression::FinishingBehavior behave);
Cantor::CompletionObject* completionFor(const QString& cmd, int index=-1);
virtual QSyntaxHighlighter* syntaxHighlighter(QObject* parent);
lua_State* getState() const;
public Q_SLOTS:
void readIntroMessage();
void readOutput();
void readError();
void processStarted();
private Q_SLOTS:
void expressionFinished();
void expressionFinished(Cantor::Expression::Status status);
private:
lua_State* m_L;
QProcess* m_process;
LuaExpression* m_currentExpression;
QString m_output;
};
#endif /* _LUASESSION_H */
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment