Changeset View
Changeset View
Standalone View
Standalone View
src/backends/lua/luasession.cpp
Show All 20 Lines | |||||
21 | #include "luasession.h" | 21 | #include "luasession.h" | ||
22 | #include "luaexpression.h" | 22 | #include "luaexpression.h" | ||
23 | #include "luacompletionobject.h" | 23 | #include "luacompletionobject.h" | ||
24 | #include "luahighlighter.h" | 24 | #include "luahighlighter.h" | ||
25 | #include "luahelper.h" | 25 | #include "luahelper.h" | ||
26 | #include <settings.h> | 26 | #include <settings.h> | ||
27 | #include "ui_settings.h" | 27 | #include "ui_settings.h" | ||
28 | 28 | | |||
29 | LuaSession::LuaSession( Cantor::Backend* backend) : Session(backend) | 29 | #include <QProcess> | ||
30 | | ||||
31 | LuaSession::LuaSession( Cantor::Backend* backend) : | ||||
32 | Session(backend), | ||||
33 | m_process(0), | ||||
34 | m_currentExpression(0) | ||||
30 | { | 35 | { | ||
31 | } | 36 | } | ||
32 | 37 | | |||
33 | LuaSession::~LuaSession() | 38 | LuaSession::~LuaSession() | ||
34 | { | 39 | { | ||
35 | } | 40 | } | ||
36 | 41 | | |||
37 | void LuaSession::login() | 42 | void LuaSession::login() | ||
38 | { | 43 | { | ||
44 | /* | ||||
45 | * setup Qprocess here | ||||
46 | * load the autoscripts | ||||
47 | */ | ||||
48 | | ||||
49 | m_process = new QProcess(this); | ||||
50 | m_process->setProgram(QLatin1String("/usr/bin/lua")); | ||||
filipesaraiva: I must ask to Lucas Negri (the original author of this backend) if it is more interesting to… | |||||
51 | m_process->setArguments(QStringList() << QLatin1String("-i")); | ||||
52 | | ||||
53 | m_process->setProcessChannelMode(QProcess::SeparateChannels); | ||||
54 | | ||||
55 | connect(m_process, SIGNAL(readyReadStandardOutput()), this, SLOT(readIntroMessage())); | ||||
56 | connect(m_process, SIGNAL(started()), this, SLOT(processStarted())); | ||||
57 | m_process->start(); | ||||
58 | | ||||
59 | // we need this for tab completion | ||||
39 | m_L = luaL_newstate(); | 60 | m_L = luaL_newstate(); | ||
40 | luaL_openlibs(m_L); | 61 | luaL_openlibs(m_L); | ||
62 | } | ||||
63 | | ||||
64 | void LuaSession::readIntroMessage() | ||||
65 | { | ||||
66 | while(m_process->bytesAvailable()) { | ||||
67 | m_output.append(QString::fromLocal8Bit(m_process->readLine())); | ||||
68 | } | ||||
41 | 69 | | |||
42 | QStringList errors; | 70 | if(!m_output.isEmpty() && m_output.trimmed().endsWith(QLatin1String(">"))) { | ||
43 | errors << luahelper_dostring(m_L, QLatin1String("__cantor = {}")); | 71 | qDebug() << " reading the intro message " << m_output ; | ||
72 | m_output.clear(); | ||||
filipesaraiva: Do you have an example where `readIntroMessage` will be used? | |||||
'Lua 5.2.4 Copyright (C) 1994-2015 Lua.org, PUC-Rio', this is the initial message produced when Lua is started. rishabhg: 'Lua 5.2.4 Copyright (C) 1994-2015 Lua.org, PUC-Rio', this is the initial message produced… | |||||
filipesaraiva: Ah ok! :) | |||||
44 | 73 | | |||
45 | errors << luahelper_dostring(m_L, | 74 | disconnect(m_process, SIGNAL(readyReadStandardOutput()), this , SLOT(readIntroMessage())); | ||
46 | QLatin1String("function print(...)\n" | 75 | connect(m_process, SIGNAL(readyReadStandardOutput()), this, SLOT(readOutput())); | ||
47 | "local t = {}\n" | 76 | connect(m_process, SIGNAL(readyReadStandardError()), this, SLOT(readError())); | ||
48 | "for i = 1, select('#',...) do\n" | 77 | } | ||
49 | "local a = select(i,...)\n" | | |||
50 | "t[i] = tostring(a)\n" | | |||
51 | "end\n" | | |||
52 | "table.insert(__cantor, table.concat(t,'\t'))\n" | | |||
53 | " end")); | | |||
54 | | ||||
55 | errors << luahelper_dostring(m_L, | | |||
56 | QLatin1String("function show(a)\n" | | |||
57 | "assert(type(a) == 'string')\n" | | |||
58 | "return a\n" | | |||
59 | "end")); | | |||
60 | 78 | | |||
61 | if(!errors.empty()) | | |||
62 | qDebug() << errors.join(QLatin1String("\n")); | | |||
63 | 79 | | |||
64 | foreach (const QString &str, LuaSettings::self()->autorunScripts()) | 80 | } | ||
65 | evaluateExpression(QLatin1String("dofile('") + str + QLatin1String("')"), Cantor::Expression::DeleteOnFinish); | | |||
66 | 81 | | |||
67 | changeStatus(Cantor::Session::Done); | 82 | void LuaSession::readOutput() | ||
68 | emit ready(); | 83 | { | ||
84 | /* | ||||
85 | * parse the output | ||||
86 | * clear all the garbage | ||||
87 | * set it as output | ||||
88 | */ | ||||
89 | // keep reading till the output ends with '>'. | ||||
90 | // '>' marks the end of output for a particular command; | ||||
91 | while(m_process->bytesAvailable()) { | ||||
92 | m_output.append(QString::fromLocal8Bit(m_process->readLine())); | ||||
69 | } | 93 | } | ||
94 | if(m_currentExpression && !m_output.isEmpty() && m_output.trimmed().endsWith(QLatin1String(">"))) { | ||||
95 | // we have our complete output | ||||
96 | // clean the output and parse it and clear m_output; | ||||
97 | m_currentExpression->parseOutput(m_output); | ||||
98 | m_output.clear(); | ||||
70 | 99 | | |||
71 | void LuaSession::logout() | 100 | } | ||
101 | | ||||
102 | } | ||||
103 | | ||||
104 | void LuaSession::readError() | ||||
72 | { | 105 | { | ||
73 | if(m_L) | 106 | qDebug() << m_process->readAllStandardError() << endl; | ||
107 | } | ||||
108 | | ||||
109 | void LuaSession::processStarted() | ||||
74 | { | 110 | { | ||
75 | lua_close(m_L); | 111 | qDebug() << m_process->program() << " pid " << m_process->processId() << " started " << endl; | ||
76 | m_L = 0; | 112 | emit ready(); | ||
77 | } | 113 | } | ||
114 | | ||||
115 | void LuaSession::logout() | ||||
116 | { | ||||
117 | if(m_process) | ||||
118 | m_process->kill(); | ||||
78 | } | 119 | } | ||
79 | 120 | | |||
80 | void LuaSession::interrupt() | 121 | void LuaSession::interrupt() | ||
81 | { | 122 | { | ||
82 | // Lua backend is synchronous, there is no way to currently interrupt an expression (in a clean way) | 123 | // Lua backend is synchronous, there is no way to currently interrupt an expression (in a clean way) | ||
83 | changeStatus(Cantor::Session::Done); | 124 | changeStatus(Cantor::Session::Done); | ||
84 | } | 125 | } | ||
85 | 126 | | |||
86 | Cantor::Expression* LuaSession::evaluateExpression(const QString& cmd, Cantor::Expression::FinishingBehavior behave) | 127 | Cantor::Expression* LuaSession::evaluateExpression(const QString& cmd, Cantor::Expression::FinishingBehavior behave) | ||
87 | { | 128 | { | ||
88 | changeStatus(Cantor::Session::Running); | 129 | changeStatus(Cantor::Session::Running); | ||
89 | 130 | | |||
90 | LuaExpression* expr = new LuaExpression(this, m_L); | 131 | m_currentExpression = new LuaExpression(this); | ||
91 | connect(expr, &LuaExpression::statusChanged, this, &LuaSession::expressionFinished); | 132 | connect(m_currentExpression, SIGNAL(statusChanged(Cantor::Expression::Status)), this, SLOT(expressionFinished(Cantor::Expression::Status))); | ||
92 | expr->setFinishingBehavior(behave); | 133 | m_currentExpression->setFinishingBehavior(behave); | ||
93 | expr->setCommand(cmd); | 134 | m_currentExpression->setCommand(cmd); | ||
94 | expr->evaluate(); | 135 | m_currentExpression->evaluate(); | ||
136 | | ||||
137 | return m_currentExpression; | ||||
138 | } | ||||
139 | | ||||
140 | void LuaSession::runExpression(LuaExpression *currentExpression) | ||||
141 | { | ||||
142 | /* | ||||
143 | * get the current command | ||||
144 | * format it and write to m_process | ||||
145 | */ | ||||
146 | QString command = currentExpression->command(); | ||||
95 | 147 | | |||
96 | return expr; | 148 | command += QLatin1String("\n"); | ||
149 | | ||||
150 | qDebug() << "final command to be executed " << command << endl; | ||||
151 | | ||||
152 | m_process->write(command.toLocal8Bit()); | ||||
97 | } | 153 | } | ||
98 | 154 | | |||
99 | Cantor::CompletionObject* LuaSession::completionFor(const QString& command, int index) | 155 | Cantor::CompletionObject* LuaSession::completionFor(const QString& command, int index) | ||
100 | { | 156 | { | ||
101 | return new LuaCompletionObject(command, index, this); | 157 | return new LuaCompletionObject(command, index, this); | ||
102 | } | 158 | } | ||
103 | 159 | | |||
104 | void LuaSession::expressionFinished() | 160 | void LuaSession::expressionFinished(Cantor::Expression::Status status) | ||
105 | { | 161 | { | ||
106 | // synchronous | 162 | switch(status) { | ||
163 | | ||||
164 | case Cantor::Expression::Computing: | ||||
165 | break; | ||||
166 | | ||||
167 | case Cantor::Expression::Done: | ||||
168 | case Cantor::Expression::Error: | ||||
169 | case Cantor::Expression::Interrupted: | ||||
107 | changeStatus(Cantor::Session::Done); | 170 | changeStatus(Cantor::Session::Done); | ||
171 | break; | ||||
172 | } | ||||
108 | } | 173 | } | ||
109 | 174 | | |||
110 | QSyntaxHighlighter* LuaSession::syntaxHighlighter(QObject* parent) | 175 | QSyntaxHighlighter* LuaSession::syntaxHighlighter(QObject* parent) | ||
111 | { | 176 | { | ||
112 | LuaHighlighter* highlighter = new LuaHighlighter(parent); | 177 | LuaHighlighter* highlighter = new LuaHighlighter(parent); | ||
113 | return highlighter; | 178 | return highlighter; | ||
114 | } | 179 | } | ||
115 | 180 | | |||
116 | lua_State* LuaSession::getState() const | 181 | lua_State* LuaSession::getState() const | ||
117 | { | 182 | { | ||
118 | return m_L; | 183 | return m_L; | ||
119 | } | 184 | } | ||
120 | 185 | | |||
121 | #include "luasession.moc" | 186 | #include "luasession.moc" |
I must ask to Lucas Negri (the original author of this backend) if it is more interesting to use Lua or Luajit.