Properly move NbRuntime to its own thread
diff --git a/.dir-locals.el b/.dir-locals.el
new file mode 100644
index 0000000..e64b4d6
--- /dev/null
+++ b/.dir-locals.el
@@ -0,0 +1,2 @@
+((c++-mode
+  (indent-tabs-mode . nil)))
diff --git a/ide/IdeMain.cpp b/ide/IdeMain.cpp
index c8eae76..ec6627e 100644
--- a/ide/IdeMain.cpp
+++ b/ide/IdeMain.cpp
@@ -13,9 +13,6 @@
 
     QQmlApplicationEngine engine;
 
-    // This is done implicitly now.
-    // registerTypes(&engine);
-
     QQuickStyle::setStyle("Material");
 
     qRegisterMetaType<CellModel>();
diff --git a/ide/NbRuntime.cpp b/ide/NbRuntime.cpp
index 35df413..eeb9d0d 100644
--- a/ide/NbRuntime.cpp
+++ b/ide/NbRuntime.cpp
@@ -5,7 +5,7 @@
 #include "../StdLib.h"
 
 NbRuntime::NbRuntime(QObject *parent)
-    : QThread(parent)
+    : QObject(parent)
 {
     StdLib().load(_eval);
 }
@@ -65,7 +65,7 @@
             {
                 ParseResult ret;
                 Function func;
-                AstNode ast;
+                QList<AstNode> ast;
 
                 if ((ret = parser.parseFunctionDefinition(&func)))
                 {
@@ -76,14 +76,17 @@
                     emit cellFailedToParse(cell, ret);
                     goto endOfCell; // JANK!
                 }
-                else if ((ret = parser.parseOne(&ast)))
+                else if ((ret = parser.parseMany(&ast)) && !ast.empty())
                 {
-                    RuntimeResult nodeRes = _eval.evaluate(ast, _ctx);
-                    result += nodeRes;
-
-                    if (!nodeRes.success())
+                    for (const AstNode &node : ast)
                     {
-                        break;
+                        RuntimeResult nodeRes = _eval.evaluate(node, _ctx);
+                        result += nodeRes;
+
+                        if (!nodeRes.success())
+                        {
+                            goto endOfParseLoop;
+                        }
                     }
                 }
                 else if (ret.status() == ParseResult::INCOMPLETE)
@@ -105,6 +108,7 @@
                 }
             }
 
+        endOfParseLoop:
             emit cellFinishedRunning(cell, result);
 
         endOfCell:
diff --git a/ide/NbRuntime.h b/ide/NbRuntime.h
index 2f6a845..9d4c714 100644
--- a/ide/NbRuntime.h
+++ b/ide/NbRuntime.h
@@ -9,7 +9,7 @@
 #include "../Evaluator.h"
 #include "../Parser.h"
 
-class NbRuntime : public QThread
+class NbRuntime : public QObject
 {
     Q_OBJECT
 
diff --git a/ide/Notebook.cpp b/ide/Notebook.cpp
index 953e98b..3396779 100644
--- a/ide/Notebook.cpp
+++ b/ide/Notebook.cpp
@@ -4,17 +4,26 @@
 
 // TODO: avoid potential race condition if Cell is deleted, pass by value with same UUID instead
 
+Notebook::~Notebook()
+{
+    _rtThread->quit();
+    _rtThread->wait();
+}
+
 Notebook::Notebook(QObject *parent)
     : QObject(parent)
     , _cellModel(new CellModel(this))
+    , _rt(new NbRuntime(this))
+    , _rtThread(new QThread(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);
+    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();
+    _rt->moveToThread(_rtThread);
+    _rtThread->start();
 }
 
 Notebook::Notebook(const Notebook &other, QObject *parent)
@@ -34,12 +43,12 @@
 void Notebook::runCell(QUuid uuid)
 {
     qInfo() << "Running cell" << uuid;
-    _rt.queueCell(Cell::cellFromUuid(uuid));
+    _rt->queueCell(Cell::cellFromUuid(uuid));
 }
 
 void Notebook::quitCell(QUuid uuid)
 {
-    _rt.unqueueCell(Cell::cellFromUuid(uuid));
+    _rt->unqueueCell(Cell::cellFromUuid(uuid));
 }
 
 void Notebook::cellFinishedRunning(Cell *cell, RuntimeResult result)
diff --git a/ide/Notebook.h b/ide/Notebook.h
index 6a5d0cf..0dbe21e 100644
--- a/ide/Notebook.h
+++ b/ide/Notebook.h
@@ -14,6 +14,7 @@
     Q_PROPERTY(CellModel *cellModel READ cellModel NOTIFY cellModelChanged)
 
 public:
+    ~Notebook();
     explicit Notebook(QObject *parent = nullptr);
     Notebook(const Notebook &other, QObject *parent = nullptr);
 
@@ -37,7 +38,8 @@
 
     QList<Cell *> _cells;
     CellModel *_cellModel;
-    NbRuntime _rt;
+    NbRuntime *_rt;
+    QThread *_rtThread;
 };
 
 Q_DECLARE_METATYPE(Notebook)
diff --git a/ide/qml/NotebookCell.qml b/ide/qml/NotebookCell.qml
index 240e7f8..3c59393 100644
--- a/ide/qml/NotebookCell.qml
+++ b/ide/qml/NotebookCell.qml
@@ -22,7 +22,10 @@
 
     height: column.height
 
-    Keys.onEscapePressed: root.cellUnfocused()
+    Keys.onEscapePressed: {
+		root.cellUnfocused()
+		code.focus = false
+	}
 
     ColumnLayout {
         id: column
@@ -76,9 +79,11 @@
                     Layout.fillHeight: true
 
                     TextArea {
+                        id: code
+
                         Layout.fillWidth: true
                         Layout.fillHeight: true
-                        id: code
+
                         font.family: "monospace"
                         text: root.code
                         selectByMouse: true
@@ -115,6 +120,8 @@
                 }
 
                 RoundButton {
+					Layout.alignment: Qt.AlignTop
+
                     icon.source: "qrc:///icons/menu.svg"
                     icon.color: Constants.buttonGrey
                     flat: true
diff --git a/main.cpp b/main.cpp
index 0cb36e8..278f1d0 100644
--- a/main.cpp
+++ b/main.cpp
@@ -22,35 +22,35 @@
 
 void testEval(QString function, QString expression, QString expected)
 {
-	Evaluator eval;
-	Parser funcParser(function),
-		exprParser(expression),
-		resParser(expected);
+    Evaluator eval;
+    Parser funcParser(function),
+        exprParser(expression),
+        resParser(expected);
 
-	Function func;
+    Function func;
 
-	QList<AstNode> expr;
-	ParseResult exprRet = exprParser.parseMany<AstNode>(&expr);
-	QList<Token> res;
-	ParseResult resRet = resParser.parseMany<Token>(&res);
-	ParseResult funcRet;
+    QList<AstNode> expr;
+    ParseResult exprRet = exprParser.parseMany<AstNode>(&expr);
+    QList<Token> res;
+    ParseResult resRet = resParser.parseMany<Token>(&res);
+    ParseResult funcRet;
 
-	QList<Token> result;
+    QList<Token> result;
 
-	exprParser.skip();
-	resParser.skip();
-	while ((funcRet = funcParser.parseFunctionDefinition(&func)))
-	{
-		eval.addFunction(func);
-	}
+    exprParser.skip();
+    resParser.skip();
+    while ((funcRet = funcParser.parseFunctionDefinition(&func)))
+    {
+        eval.addFunction(func);
+    }
 
-	funcParser.skip();
+    funcParser.skip();
 
-	if (!exprRet || !resRet || funcRet.status() == ParseResult::INCOMPLETE)
-	{
+    if (!exprRet || !resRet || funcRet.status() == ParseResult::INCOMPLETE)
+    {
         g_numFailed++;
         qDebug() << "\n\033[31mTEST FAILS:\033[0m";
-		qDebug() << "Failed to fully parse expression, function or result";
+        qDebug() << "Failed to fully parse expression, function or result";
         qDebug() << "Function:";
         sout(pprint(funcRet, funcParser));
 
@@ -60,33 +60,33 @@
         qDebug() << "Result:";
         sout(pprint(resRet, resParser));
 
-		goto end;
-	}
+        goto end;
+    }
 
-	for (const AstNode &node : expr)
-	{
-		RuntimeResult rr = eval.evaluate(node, VarContext());
+    for (const AstNode &node : expr)
+    {
+        RuntimeResult rr = eval.evaluate(node, VarContext());
 
-		if (!rr.success())
-		{
-			g_numFailed++;
-			qDebug() << "\n\033[31mTEST FAILS:\033[0m";
-			qDebug() << "Runtime error while evaluating" << node;
-			qDebug() << rr;
+        if (!rr.success())
+        {
+            g_numFailed++;
+            qDebug() << "\n\033[31mTEST FAILS:\033[0m";
+            qDebug() << "Runtime error while evaluating" << node;
+            qDebug() << rr;
 
-			goto end;
-		}
+            goto end;
+        }
 
-		result.append(rr.result());
-	}
+        result.append(rr.result());
+    }
 
-	if (result != res)
-	{
-		g_numFailed++;
-		qDebug() << "\n\033[31mTEST FAILS:\033[0m";
-		qDebug() << "Expected result" << res;
-		qDebug() << "Got" << result;
-	}
+    if (result != res)
+    {
+        g_numFailed++;
+        qDebug() << "\n\033[31mTEST FAILS:\033[0m";
+        qDebug() << "Expected result" << res;
+        qDebug() << "Got" << result;
+    }
 
 end:
     qDebug() << "\033[36mEvaluate\033[0m" << function << expression << "->" << pprint(result);
@@ -94,7 +94,7 @@
 
 void testEval(QString function, QString expression, QList<Token> expected)
 {
-	testEval(function, expression, pprint(expected));
+    testEval(function, expression, pprint(expected));
 }
 
 void testEval(QString expression, QString expected)
@@ -124,13 +124,13 @@
     Parser dataParser(data),
         patternParser(pattern);
 
-	QList<Token> parsedData, parsedPattern;
-	
-	dataParser.parseMany<Token>(&parsedData);
-	patternParser.parseMany<Token>(&parsedPattern);
+    QList<Token> parsedData, parsedPattern;
+    
+    dataParser.parseMany<Token>(&parsedData);
+    patternParser.parseMany<Token>(&parsedPattern);
 
     testMatch(pattern + " = " + data, shouldBe,
-			  match(parsedData, parsedPattern, VarContext()));
+              match(parsedData, parsedPattern, VarContext()));
 }
 
 void testParseAst(QString string, QList<AstNode> equals = {})
@@ -138,14 +138,14 @@
     Parser parser{string};
 
     QList<AstNode> result;
-	parser.parseMany<AstNode>(&result);
+    parser.parseMany<AstNode>(&result);
 
-	if (!equals.empty() && result != equals)
-	{
+    if (!equals.empty() && result != equals)
+    {
         g_numFailed++;
         qDebug() << "\n\033[31mTEST FAILS:\033[0m";
         qDebug() << "Expected" << pprint(equals);
-	}
+    }
 
     qDebug() << "\033[36mParse\033[0m" << string << pprint(result);
 }
@@ -153,7 +153,7 @@
 void testParseFunc(QString string)
 {
     Parser parser{string};
-	ParseResult ret;
+    ParseResult ret;
 
     Function func;
 
@@ -200,13 +200,13 @@
         Token('e', "middle"),
         Token('s', "a")};
     testMatch("s.a e.middle s.a = aea", true,
-                match({Token('a'), Token('e'), Token('a')}, sameStartEnd, VarContext()));
+              match({Token('a'), Token('e'), Token('a')}, sameStartEnd, VarContext()));
 
     testMatch("s.a e.middle s.a = aef Hi a", true,
-                match({Token('a'), Token('e'), Token('f'), Token("Hi"), Token('a')}, sameStartEnd, VarContext()));
+              match({Token('a'), Token('e'), Token('f'), Token("Hi"), Token('a')}, sameStartEnd, VarContext()));
 
     testMatch("s.a e.middle s.a = aef Hi c", false,
-                match({Token('a'), Token('e'), Token('f'), Token("Hi"), Token('c')}, sameStartEnd, VarContext()));
+              match({Token('a'), Token('e'), Token('f'), Token("Hi"), Token('c')}, sameStartEnd, VarContext()));
 
     LTok parenthesized = {
         Token(LTok({Token('s', "a")})),
@@ -220,14 +220,14 @@
         Token('y')};
 
     testMatch("(s.a) e.Middle s.a = (y)f MiddleStuff y", true,
-                match(parenTest1, parenthesized, VarContext()));
+              match(parenTest1, parenthesized, VarContext()));
     // testMatch("(y)f Middle-stuff y", "(s.a) e.Middle s.a");
 
     testMatch("(a)", "(a)");
-	testMatch("hello", "s.A e.Rest");
-	testMatch("123", "123");
-	testMatch("(123)", "t.a");
-	testMatch("(123)", "(s.a)");
+    testMatch("hello", "s.A e.Rest");
+    testMatch("123", "123");
+    testMatch("(123)", "t.a");
+    testMatch("(123)", "(s.a)");
 }
 
 void testAllParses()
@@ -244,8 +244,8 @@
     testParseAst("(s.a) e.Middle s.a");
     testParseAst("Hello; Goodbye");
     testParseAst("Key = Value");
-	testParseAst("123", {AstNode("123", 10)});
-	testParseAst("12 00", {AstNode::fromInteger(12), AstNode::fromInteger(0)});
+    testParseAst("123", {AstNode("123", 10)});
+    testParseAst("12 00", {AstNode::fromInteger(12), AstNode::fromInteger(0)});
     testParseAst("s.A s.B", {AstNode('s', "A"), AstNode('s', "B")});
     testParseAst("a '=' b", {AstNode('a'), AstNode('='), AstNode('b')});
     testParseAst("'This\\'<>#$@#^%\\n' 'another $3543543'");
@@ -259,8 +259,8 @@
 
 void testAllEvals()
 {
-	testEval("First {s.A e.Rest = s.A;}", "<First hello>", "h");
-	testEval("Number { = 123; }", "<Number>", QList<Token>{Token::fromInteger(123)});
+    testEval("First {s.A e.Rest = s.A;}", "<First hello>", "h");
+    testEval("Number { = 123; }", "<Number>", QList<Token>{Token::fromInteger(123)});
     testEval("<Br Name '=' Jim> <Dg Name>", "Jim");
     testEval("<Br A '=' hello> <Br A '=' 'good bye'> <Dg A> <Dg A>", "'good byehello'");
 }
@@ -273,43 +273,43 @@
     a.setApplicationName("REFAL");
     a.setApplicationVersion("1.0-a1");
 
-	QCommandLineParser cli;
-	cli.setApplicationDescription("REFAL interpreter");
-	cli.addHelpOption();
-	cli.addVersionOption();
+    QCommandLineParser cli;
+    cli.setApplicationDescription("REFAL interpreter");
+    cli.addHelpOption();
+    cli.addVersionOption();
 
     cli.addPositionalArgument("script", "REFAL script to run");
 
-	QCommandLineOption testOption(QStringList{"t", "test"}, "Run test suite.");
-	cli.addOption(testOption);
+    QCommandLineOption testOption(QStringList{"t", "test"}, "Run test suite.");
+    cli.addOption(testOption);
     QCommandLineOption replOption(QStringList({"r", "repl"}), "Start CLI REPL");
     cli.addOption(replOption);
 
-	cli.process(a);
+    cli.process(a);
 
     if (cli.positionalArguments().length() > 0)
     {
         qDebug() << "Running script" << cli.positionalArguments()[0];
     }
     else if (cli.isSet(testOption))
-	{
-		testAllMatches();
-		qDebug() << "";
-		testAllParses();
-		qDebug() << "";
-		testAllFunctionDefs();
-		qDebug() << "";
-		testAllEvals();
+    {
+        testAllMatches();
+        qDebug() << "";
+        testAllParses();
+        qDebug() << "";
+        testAllFunctionDefs();
+        qDebug() << "";
+        testAllEvals();
 
-		qDebug() << "";
+        qDebug() << "";
 
-		return testResults();
-	}
+        return testResults();
+    }
     else if (cli.isSet(replOption))
-	{
-		Repl repl;
-		repl.start();
-	}
+    {
+        Repl repl;
+        repl.start();
+    }
     else
     {
         return ideMain(&a);