Add evaluator
diff --git a/Evaluator.cpp b/Evaluator.cpp
index 5177fe5..56685ec 100644
--- a/Evaluator.cpp
+++ b/Evaluator.cpp
@@ -5,6 +5,7 @@
#include "PPrint.h"
#include <QDebug>
+#include <QCoreApplication>
RuntimeResult::RuntimeResult(QList<Token> result)
{
@@ -14,7 +15,41 @@
RuntimeResult::RuntimeResult(QString message)
{
_errorMessage = message;
- _success = false;
+ _success = false;
+}
+
+RuntimeResult &RuntimeResult::operator =(const RuntimeResult &other)
+{
+ _errorMessage = other._errorMessage;
+ _success = other._success;
+ _result = other._result;
+
+ return *this;
+}
+
+RuntimeResult RuntimeResult::operator +(const RuntimeResult &other)
+{
+ RuntimeResult res;
+
+ if (_success)
+ {
+ res._success = other._success;
+ res._result = _result;
+ res._result.append(other._result);
+ res._errorMessage = other._errorMessage;
+ }
+ else
+ {
+ res = *this;
+ }
+
+ return res;
+}
+
+RuntimeResult &RuntimeResult::operator +=(const RuntimeResult &other)
+{
+ *this = *this + other;
+ return *this;
}
bool RuntimeResult::success() const
@@ -34,7 +69,7 @@
RuntimeResult::operator QString() const
{
- return QString(_success) + " " + _errorMessage;
+ return _errorMessage + pprint(_result);
}
Evaluator::Evaluator()
@@ -73,6 +108,19 @@
return copy(name.name());
});
addFunction(copyFn);
+
+ Function undefFn("Undef");
+ undefFn.addNativeSentence("s.Name", [this](VarContext args)
+ {
+ Token name = args.singleVar("Name");
+ if (name.type() != Token::IDENT)
+ rtError("Invalid argument", "First argument to <Undef> must be an identifier, received " + pprint(name));
+
+ clearFunction(name.name());
+
+ return QList<Token>();
+ });
+ addFunction(undefFn);
}
void Evaluator::addFunction(Function func)
@@ -85,8 +133,13 @@
_functions.remove(name);
}
-RuntimeResult Evaluator::evaluate(AstNode node, VarContext ctx)
+RuntimeResult Evaluator::evaluate(AstNode node, VarContext ctx, int recursionDepth)
{
+ if (recursionDepth > _recursionLimit)
+ {
+ throw StackOverflowException(node);
+ }
+
if (node.isSym())
{
return RuntimeResult(QList<Token>{Token(node.symbol())});
@@ -138,20 +191,20 @@
for (const AstNode &arg : node.funcArgs())
{
- RuntimeResult internalResult = evaluate(arg, ctx);
+ RuntimeResult internalResult = evaluate(arg, ctx, recursionDepth + 1);
if (!internalResult.success())
return internalResult;
args.append(internalResult.result());
}
- return callFunction(node.name(), args);
+ return callFunction(node.name(), args, recursionDepth + 1);
}
return RuntimeResult("#TYPE_ERROR");
}
-RuntimeResult Evaluator::callFunction(QString name, QList<Token> args)
+RuntimeResult Evaluator::callFunction(QString name, QList<Token> args, int recursionDepth)
{
if (!_functions.contains(name))
return RuntimeResult("Function " + name + " is not defined.");
@@ -173,7 +226,7 @@
QList<Token> final;
for (const AstNode &node : sentence.result())
{
- RuntimeResult argRes = evaluate(node, res.context);
+ RuntimeResult argRes = evaluate(node, res.context, recursionDepth);
if (!argRes.success())
return argRes;
@@ -186,6 +239,11 @@
return RuntimeResult("Function " + name + " had no matching sentences for input");
}
+void Evaluator::quit()
+{
+ throw EvalQuitException();
+}
+
QList<Token> Evaluator::dig(QString name)
{
if (_vars.contains(name))
@@ -232,3 +290,39 @@
eout("Runtime Error: " + brief);
eout(details);
}
+
+void EvalQuitException::raise() const
+{
+ throw *this;
+}
+
+EvalQuitException *EvalQuitException::clone() const
+{
+ return new EvalQuitException(*this);
+}
+
+StackOverflowException::StackOverflowException(AstNode failedAt)
+ : QException()
+{
+ _failedAt = failedAt;
+}
+
+AstNode StackOverflowException::failedAt() const
+{
+ return _failedAt;
+}
+
+void StackOverflowException::raise() const
+{
+ throw *this;
+}
+
+StackOverflowException *StackOverflowException::clone() const
+{
+ return new StackOverflowException(*this);
+}
+
+StackOverflowException::operator QString() const
+{
+ return "StackOverflowException: at " + pprint(_failedAt);
+}
diff --git a/Evaluator.h b/Evaluator.h
index afda18f..47ea941 100644
--- a/Evaluator.h
+++ b/Evaluator.h
@@ -2,6 +2,7 @@
#include <QMap>
#include <QStack>
+#include <QException>
#include "Token.h"
#include "AstNode.h"
@@ -11,9 +12,14 @@
class RuntimeResult
{
public:
- RuntimeResult(QList<Token> result);
+ RuntimeResult(const RuntimeResult &other) = default;
+ RuntimeResult(QList<Token> result = {});
RuntimeResult(QString message);
+ RuntimeResult &operator =(const RuntimeResult &other);
+ RuntimeResult operator +(const RuntimeResult &other);
+ RuntimeResult &operator +=(const RuntimeResult &other);
+
bool success() const;
QString message() const;
QList<Token> result() const;
@@ -26,18 +32,50 @@
QList<Token> _result;
};
+class EvalQuitException : public QException
+{
+public:
+ EvalQuitException() = default;
+ EvalQuitException(const EvalQuitException &other) = default;
+
+ void raise() const override;
+ EvalQuitException *clone() const override;
+};
+
+class StackOverflowException : public QException
+{
+public:
+ StackOverflowException(AstNode failedAt = AstNode());
+ StackOverflowException(const StackOverflowException &other) = default;
+
+ AstNode failedAt() const;
+
+ void raise() const override;
+ StackOverflowException *clone() const override;
+
+ operator QString() const;
+
+private:
+ AstNode _failedAt;
+};
+
class Evaluator {
public:
Evaluator();
void addFunction(Function func);
void clearFunction(QString name);
- RuntimeResult evaluate(AstNode node, VarContext ctx);
- RuntimeResult callFunction(QString name, QList<Token> args);
+ RuntimeResult evaluate(AstNode node, VarContext ctx, int recursionDepth = 0);
+ RuntimeResult callFunction(QString name, QList<Token> args, int recursionDepth);
+
+ // Throws an EvalQuitException
+ void quit();
private:
QMap<QString, Function> _functions;
QMap<QString, QStack<QList<Token>>> _vars;
+ bool _shouldContinue = true;
+ int _recursionLimit = 1024;
protected:
QList<Token> dig(QString name);
diff --git a/Parser.cpp b/Parser.cpp
index 6ce62fa..9679b4c 100644
--- a/Parser.cpp
+++ b/Parser.cpp
@@ -1,4 +1,5 @@
#include "Parser.h"
+#include "PPrint.h"
#include <QDebug>
@@ -34,7 +35,12 @@
int ParseResult::status() const
{
- return _status;
+ return _status;
+}
+
+ParseResult::operator QString() const
+{
+ return pprint(pos()) + "\n" + message();
}
Parser::Parser(QString input)
diff --git a/Parser.h b/Parser.h
index 102a3c3..d0a348d 100644
--- a/Parser.h
+++ b/Parser.h
@@ -36,6 +36,8 @@
QString message() const;
int status() const;
+ operator QString() const;
+
private:
int _status = COMPLETE;
QString _message = "";
diff --git a/ide/Cell.cpp b/ide/Cell.cpp
index 2fd964b..c49466d 100644
--- a/ide/Cell.cpp
+++ b/ide/Cell.cpp
@@ -1,8 +1,15 @@
#include "Cell.h"
+QHash<QUuid, Cell *> Cell::_cellUuids = QHash<QUuid, Cell*>();
+
+Cell::~Cell()
+{
+ _cellUuids.remove(_uuid);
+}
+
Cell::Cell(QObject *parent) : QObject(parent)
{
-
+ _cellUuids[_uuid] = this;
}
Cell::Cell(const Cell ©, QObject *parent)
@@ -36,6 +43,16 @@
return _result;
}
+QUuid Cell::uuid() const
+{
+ return _uuid;
+}
+
+int Cell::status() const
+{
+ return _status;
+}
+
void Cell::setCode(QString code)
{
_code = code;
@@ -47,3 +64,17 @@
_result = result;
emit resultChanged(result);
}
+
+void Cell::setStatus(int status)
+{
+ _status = status;
+ emit statusChanged(status);
+}
+
+Cell *Cell::cellFromUuid(QUuid uuid)
+{
+ if (_cellUuids.contains(uuid))
+ return _cellUuids[uuid];
+ else
+ return nullptr;
+}
diff --git a/ide/Cell.h b/ide/Cell.h
index e3d1f9d..fb5bc42 100644
--- a/ide/Cell.h
+++ b/ide/Cell.h
@@ -2,6 +2,8 @@
#include <QObject>
#include <qqml.h>
+#include <QUuid>
+#include <QHash>
class Cell : public QObject
{
@@ -10,8 +12,11 @@
Q_PROPERTY(QString code READ code WRITE setCode NOTIFY codeChanged)
Q_PROPERTY(QString result READ result WRITE setResult NOTIFY resultChanged)
+ Q_PROPERTY(QUuid uuid READ uuid NOTIFY uuidChanged)
+ Q_PROPERTY(int status READ status WRITE setStatus NOTIFY statusChanged)
public:
+ ~Cell();
explicit Cell(QObject *parent = nullptr);
Cell(const Cell ©, QObject *parent = nullptr);
Cell(QString code, QString result, QObject *parent = nullptr);
@@ -20,16 +25,36 @@
QString code() const;
QString result() const;
+ QUuid uuid() const;
+ int status() const;
void setCode(QString code);
void setResult(QString result);
+ void setStatus(int status);
+
+ Q_INVOKABLE static Cell *cellFromUuid(QUuid uuid);
+
+ enum Status
+ {
+ RUNNING,
+ IDLE,
+ WAITING,
+ };
+
+ Q_ENUM(Status);
signals:
void codeChanged(QString code);
void resultChanged(QString result);
+ void uuidChanged(QUuid uuid);
+ void statusChanged(int status);
private:
+ int _status = IDLE;
QString _code, _result;
+ QUuid _uuid = QUuid::createUuid();
+
+ static QHash<QUuid, Cell *> _cellUuids;
};
Q_DECLARE_METATYPE(Cell)
diff --git a/ide/CellModel.cpp b/ide/CellModel.cpp
index 41acbe7..8271c87 100644
--- a/ide/CellModel.cpp
+++ b/ide/CellModel.cpp
@@ -29,9 +29,13 @@
switch (role)
{
case CodeRole:
- return _notebook->_cells[index.row()].code();
+ return _notebook->_cells[index.row()]->code();
case ResultRole:
- return _notebook->_cells[index.row()].result();
+ return _notebook->_cells[index.row()]->result();
+ case UuidRole:
+ return _notebook->_cells[index.row()]->uuid();
+ case StatusRole:
+ return _notebook->_cells[index.row()]->status();
default:
return QVariant();
}
@@ -44,10 +48,13 @@
switch (role)
{
case CodeRole:
- _notebook->_cells[index.row()].setCode(value.toString());
+ _notebook->_cells[index.row()]->setCode(value.toString());
break;
case ResultRole:
- _notebook->_cells[index.row()].setResult(value.toString());
+ _notebook->_cells[index.row()]->setResult(value.toString());
+ break;
+ case StatusRole:
+ _notebook->_cells[index.row()]->setStatus(value.toInt());
break;
default:
return false;
@@ -66,7 +73,7 @@
if (!index.isValid())
return Qt::NoItemFlags;
- return Qt::ItemIsEditable; // FIXME: Implement me!
+ return Qt::ItemIsEditable;
}
bool CellModel::insertRows(int row, int count, const QModelIndex &parent)
@@ -74,7 +81,26 @@
beginInsertRows(parent, row, row + count - 1);
for (int i = 0; i < count; i++)
- _notebook->_cells.insert(row, Cell());
+ {
+ Cell *cell = new Cell(this);
+
+ connect(cell, &Cell::codeChanged, this, [this, cell](QString)
+ {
+ announceCellChange(cell, CodeRole);
+ });
+
+ connect(cell, &Cell::resultChanged, this, [this, cell](QString)
+ {
+ announceCellChange(cell, ResultRole);
+ });
+
+ connect(cell, &Cell::statusChanged, this, [this, cell](int)
+ {
+ announceCellChange(cell, StatusRole);
+ });
+
+ _notebook->_cells.insert(row, cell);
+ }
endInsertRows();
@@ -86,7 +112,10 @@
beginRemoveRows(parent, row, row + count - 1);
for (int i = 0; i < count; i++)
+ {
+ delete _notebook->_cells[row];
_notebook->_cells.removeAt(row);
+ }
endRemoveRows();
@@ -98,6 +127,8 @@
return {
{CodeRole, "code"},
{ResultRole, "result"},
+ {UuidRole, "uuid"},
+ {StatusRole, "status"},
};
}
@@ -107,7 +138,7 @@
insertRows(i, 1, QModelIndex());
- _notebook->_cells[i] = cell;
+ *_notebook->_cells[i] = cell;
emit dataChanged(index(i), index(i), {CodeRole, ResultRole});
}
@@ -115,3 +146,17 @@
{
addCell(Cell(code, result));
}
+
+void CellModel::announceCellChange(Cell *cell, int role)
+{
+ // TODO: Optimize
+
+ for (int i = 0; i < rowCount(); i++)
+ {
+ if (_notebook->_cells[i] == cell)
+ {
+ emit dataChanged(index(i), index(i), QVector<int>() << role);
+ break;
+ }
+ }
+}
diff --git a/ide/CellModel.h b/ide/CellModel.h
index 16bfee5..1f56056 100644
--- a/ide/CellModel.h
+++ b/ide/CellModel.h
@@ -17,7 +17,9 @@
enum CellRoles
{
CodeRole = Qt::UserRole + 1,
- ResultRole
+ ResultRole,
+ UuidRole,
+ StatusRole,
};
// Basic functionality:
@@ -44,6 +46,7 @@
private:
Notebook *_notebook;
+ void announceCellChange(Cell *cell, int role);
};
Q_DECLARE_METATYPE(CellModel)
diff --git a/ide/IDE.pri b/ide/IDE.pri
index f656fd1..0341a0b 100644
--- a/ide/IDE.pri
+++ b/ide/IDE.pri
@@ -17,12 +17,14 @@
$$PWD/Cell.cpp \
$$PWD/CellModel.cpp \
$$PWD/IdeMain.cpp \
+ $$PWD/NbRuntime.cpp \
$$PWD/Notebook.cpp
HEADERS += \
$$PWD/Cell.h \
$$PWD/CellModel.h \
$$PWD/IdeMain.h \
+ $$PWD/NbRuntime.h \
$$PWD/Notebook.h
RESOURCES += \
diff --git a/ide/NbRuntime.cpp b/ide/NbRuntime.cpp
new file mode 100644
index 0000000..8454597
--- /dev/null
+++ b/ide/NbRuntime.cpp
@@ -0,0 +1,122 @@
+#include <QCoreApplication>
+
+#include "NbRuntime.h"
+#include "../Parser.h"
+
+NbRuntime::NbRuntime(QObject *parent)
+ : QThread(parent)
+{
+}
+
+void NbRuntime::queueCell(Cell *cell)
+{
+ if (!_cells.contains(cell))
+ {
+ qInfo() << "Queueing cell";
+
+ _cells.append(cell);
+
+ emit cellWaiting(cell);
+
+ if (!_running)
+ evalRemaining();
+ }
+}
+
+void NbRuntime::unqueueCell(Cell *cell)
+{
+ if (cell == _running)
+ {
+ // Exception should propagate back up to evalRemaining()
+ _eval.quit();
+ }
+ else
+ {
+ _cells.removeOne(cell);
+ }
+}
+
+void NbRuntime::evalRemaining()
+{
+ qInfo() << "evalRemaining";
+
+ while (!_cells.empty())
+ {
+ QCoreApplication::processEvents();
+
+ Cell *cell = _cells.first();
+ _cells.removeFirst();
+
+ _running = cell;
+
+ Parser parser(cell->code());
+ RuntimeResult result;
+
+ emit cellRunning(cell);
+
+ try
+ {
+ // Allow this cell to be quit
+ QCoreApplication::processEvents();
+
+ while (true)
+ {
+ ParseResult ret;
+ Function func;
+ AstNode ast;
+
+ if ((ret = parser.parseFunctionDefinition(&func)))
+ {
+ _eval.addFunction(func);
+ }
+ else if (ret.status() == ParseResult::INCOMPLETE)
+ {
+ emit cellFailedToParse(cell, ret);
+ goto endOfCell; // JANK!
+ }
+ else if ((ret = parser.parseOne(&ast)))
+ {
+ RuntimeResult nodeRes = _eval.evaluate(ast, _ctx);
+ result += nodeRes;
+
+ if (!nodeRes.success())
+ {
+ break;
+ }
+ }
+ else if (ret.status() == ParseResult::INCOMPLETE)
+ {
+ emit cellFailedToParse(cell, ret);
+ break;
+ }
+ else
+ {
+ parser.skip();
+
+ if (!parser.atEnd())
+ {
+ emit cellFailedToParse(cell, ParseResult(ParseResult::NO_MATCH, "Garbage at end of input", parser.save()));
+ goto endOfCell;
+ }
+
+ break;
+ }
+ }
+
+ emit cellFinishedRunning(cell, result);
+
+ endOfCell:
+ _running = nullptr;
+ }
+ catch (EvalQuitException &ex)
+ {
+ _running = nullptr;
+ emit cellQuit(cell);
+ }
+ catch (StackOverflowException &ex)
+ {
+ _running = nullptr;
+ emit cellFinishedRunning(cell, RuntimeResult(ex));
+ }
+ }
+}
diff --git a/ide/NbRuntime.h b/ide/NbRuntime.h
new file mode 100644
index 0000000..2f6a845
--- /dev/null
+++ b/ide/NbRuntime.h
@@ -0,0 +1,37 @@
+#pragma once
+
+#include <QObject>
+#include <QThread>
+#include <QQueue>
+
+#include "Cell.h"
+#include "../Token.h"
+#include "../Evaluator.h"
+#include "../Parser.h"
+
+class NbRuntime : public QThread
+{
+ Q_OBJECT
+
+public:
+ explicit NbRuntime(QObject *parent = nullptr);
+
+public slots:
+ void queueCell(Cell *cell);
+ void unqueueCell(Cell *cell);
+
+signals:
+ void cellFinishedRunning(Cell *cell, RuntimeResult result);
+ void cellFailedToParse(Cell *cell, ParseResult result);
+ void cellWaiting(Cell *cell);
+ void cellRunning(Cell *cell);
+ void cellQuit(Cell *cell);
+
+protected:
+ void evalRemaining();
+
+ Evaluator _eval;
+ QQueue<Cell *> _cells;
+ Cell *_running = nullptr;
+ VarContext _ctx;
+};
diff --git a/ide/Notebook.cpp b/ide/Notebook.cpp
index 9beb332..82bee7e 100644
--- a/ide/Notebook.cpp
+++ b/ide/Notebook.cpp
@@ -1,21 +1,74 @@
#include "Notebook.h"
#include "CellModel.h"
+#include "../PPrint.h"
Notebook::Notebook(QObject *parent)
: QObject(parent)
, _cellModel(new CellModel(this))
{
+ connect(&_rt, &NbRuntime::cellFailedToParse, this, &Notebook::cellFailedToParse);
+ connect(&_rt, &NbRuntime::cellFinishedRunning, this, &Notebook::cellFinishedRunning);
+ connect(&_rt, &NbRuntime::cellQuit, this, &Notebook::cellQuit);
+ connect(&_rt, &NbRuntime::cellRunning, this, &Notebook::cellRunning);
+ connect(&_rt, &NbRuntime::cellWaiting, this, &Notebook::cellWaiting);
+ _rt.start();
}
Notebook::Notebook(const Notebook &other, QObject *parent)
- : QObject(parent)
- , _cells(other._cells)
- , _cellModel(new CellModel(this))
+ : Notebook(parent)
{
+ for (const Cell *cell : other._cells)
+ {
+ _cells.append(new Cell(*cell, this));
+ }
}
CellModel *Notebook::cellModel()
{
return _cellModel;
}
+
+void Notebook::runCell(QUuid uuid)
+{
+ qInfo() << "Running cell" << uuid;
+ _rt.queueCell(Cell::cellFromUuid(uuid));
+}
+
+void Notebook::quitCell(QUuid uuid)
+{
+ _rt.unqueueCell(Cell::cellFromUuid(uuid));
+}
+
+void Notebook::cellFinishedRunning(Cell *cell, RuntimeResult result)
+{
+ qInfo() << "cellFinishedRunning" << cell->uuid() << pprint(result);
+ cell->setResult(pprint(result));
+ cell->setStatus(Cell::IDLE);
+}
+
+void Notebook::cellFailedToParse(Cell *cell, ParseResult result)
+{
+ qInfo() << "cellFailedToParse" << cell->uuid() << pprint(result);
+ cell->setResult(pprint(result));
+ cell->setStatus(Cell::IDLE);
+}
+
+void Notebook::cellWaiting(Cell *cell)
+{
+ qInfo() << "cellWaiting" << cell->uuid();
+ cell->setStatus(Cell::WAITING);
+}
+
+void Notebook::cellRunning(Cell *cell)
+{
+ qInfo() << "cellRunning" << cell->uuid();
+ cell->setStatus(Cell::RUNNING);
+}
+
+void Notebook::cellQuit(Cell *cell)
+{
+ qInfo() << "cellQuit" << cell->uuid();
+ cell->setResult("");
+ cell->setStatus(Cell::IDLE);
+}
diff --git a/ide/Notebook.h b/ide/Notebook.h
index 0bd84ec..867c2e9 100644
--- a/ide/Notebook.h
+++ b/ide/Notebook.h
@@ -3,6 +3,7 @@
#include <QObject>
#include "Cell.h"
+#include "NbRuntime.h"
class CellModel;
@@ -19,14 +20,25 @@
CellModel *cellModel();
+ Q_INVOKABLE void runCell(QUuid uuid);
+ Q_INVOKABLE void quitCell(QUuid uuid);
+
signals:
void cellModelChanged();
+protected slots:
+ void cellFinishedRunning(Cell *cell, RuntimeResult result);
+ void cellFailedToParse(Cell *cell, ParseResult result);
+ void cellWaiting(Cell *cell);
+ void cellRunning(Cell *cell);
+ void cellQuit(Cell *cell);
+
protected:
friend class CellModel;
- QList<Cell> _cells;
+ QList<Cell *> _cells;
CellModel *_cellModel;
+ NbRuntime _rt;
};
Q_DECLARE_METATYPE(Notebook)
diff --git a/ide/icons/square.svg b/ide/icons/square.svg
new file mode 100644
index 0000000..3a4587b
--- /dev/null
+++ b/ide/icons/square.svg
@@ -0,0 +1 @@
+<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 512 512"><path d="M405.333 64H106.667C83.198 64 64 83.198 64 106.667v298.666C64 428.802 83.198 448 106.667 448h298.666C428.802 448 448 428.802 448 405.333V106.667C448 83.198 428.802 64 405.333 64z"/></svg>
\ No newline at end of file
diff --git a/ide/qml/DocumentPadding.qml b/ide/qml/DocumentPadding.qml
new file mode 100644
index 0000000..3c47413
--- /dev/null
+++ b/ide/qml/DocumentPadding.qml
@@ -0,0 +1,9 @@
+import QtQuick 2.0
+import QtQuick.Layouts 1.3
+
+ColumnLayout {
+ Layout.topMargin: 10
+ Layout.bottomMargin: 10
+ Layout.leftMargin: 12
+ Layout.rightMargin: 12
+}
diff --git a/ide/qml/NotebookCell.qml b/ide/qml/NotebookCell.qml
index 3466d05..f51ffaa 100644
--- a/ide/qml/NotebookCell.qml
+++ b/ide/qml/NotebookCell.qml
@@ -3,15 +3,19 @@
import QtQuick.Controls.Material 2.0
import QtQuick.Layouts 1.0
+import sh.swisschili.REFAL 1.0
+
Item {
id: root
required property string code
required property string result
+ property int status: Cell.IDLE
signal insertBelowClicked()
signal codeEditingFinished(string code)
signal cellFocused()
+ signal runClicked()
height: column.height
@@ -34,9 +38,18 @@
RoundButton {
Layout.alignment: Qt.AlignTop
- icon.source: "qrc:///icons/play-circle.svg"
+ icon.source: iconForState(root.state)
icon.color: Material.color(Material.Grey, Material.Shade600)
flat: true
+
+ onClicked: root.runClicked()
+
+ function iconForState(state) {
+ if (state === Cell.RUNNING)
+ return "qrc:///icons/square.svg"
+
+ return "qrc:///icons/play-circle.svg"
+ }
}
ColumnLayout {
diff --git a/ide/qml/main.qml b/ide/qml/main.qml
index a28d47d..bf99a8d 100644
--- a/ide/qml/main.qml
+++ b/ide/qml/main.qml
@@ -63,22 +63,47 @@
model: notebook.cellModel
clip: true
+ header: ColumnLayout {
+ width: codeEditor.width
+
+ DocumentPadding {
+ Layout.bottomMargin: 0
+
+ Label {
+ font.pointSize: 18
+ text: "Notebook"
+ }
+ }
+
+ InsertRow {
+ onInsertClicked: notebook.cellModel.insertRows(notebook.cellModel.index(0, 0), 1);
+ }
+ }
+
delegate: NotebookCell {
id: notebookCell
required property var model
required property var index
+ required property var uuid
+ required property int status
width: codeEditor.width - 5
code: model.code
- result: model.result
+ result: model.result.trim()
+ status: model.status
onCodeEditingFinished: model.code = code
onInsertBelowClicked: {
- console.info(index)
- cellModel.insertRows(cellModel.index(0, index), 1)
+ console.info(index);
+ notebook.cellModel.insertRows(notebook.cellModel.index(index + 1, 0), 1);
+ }
+
+ onRunClicked: {
+ console.info("Cell run clicked")
+ notebook.runCell(uuid)
}
}
}
diff --git a/ide/resources.qrc b/ide/resources.qrc
index a77a977..23ecdd0 100644
--- a/ide/resources.qrc
+++ b/ide/resources.qrc
@@ -6,5 +6,7 @@
<file>icons/add.svg</file>
<file>qml/InsertRow.qml</file>
<file>icons/trash.svg</file>
+ <file>qml/DocumentPadding.qml</file>
+ <file>icons/square.svg</file>
</qresource>
</RCC>