diff --git a/recipes/pkg/terminal_editor/README b/recipes/pkg/terminal_editor/README
new file mode 100644
index 0000000..1aa1b38
--- /dev/null
+++ b/recipes/pkg/terminal_editor/README
@@ -0,0 +1,6 @@
+
+ A simple text editor for reading and writing to a Terminal session
+
+
+This editor is intended for interacting with a intepreter,
+input and output is written in chunks, not byte-by-byte.
diff --git a/recipes/pkg/terminal_editor/archives b/recipes/pkg/terminal_editor/archives
new file mode 100644
index 0000000..0e0fe6c
--- /dev/null
+++ b/recipes/pkg/terminal_editor/archives
@@ -0,0 +1,19 @@
+genodelabs/raw/qt5_dejavusans/2018-09-06
+genodelabs/src/expat/2018-11-26
+genodelabs/src/freetype/2018-11-26
+genodelabs/src/jpeg/2018-11-26
+genodelabs/src/libc/2018-11-27
+genodelabs/src/libpng/2018-11-26
+genodelabs/src/mesa/2018-11-27
+genodelabs/src/pcre16/2018-11-26
+genodelabs/src/qt5_component/2018-11-27
+genodelabs/src/qt5_core/2018-11-27
+genodelabs/src/qt5_gui/2018-11-26
+genodelabs/src/qt5_printsupport/2018-11-26
+genodelabs/src/qt5_qjpeg/2018-11-26
+genodelabs/src/qt5_qpa_nitpicker/2018-11-27
+genodelabs/src/qt5_widgets/2018-11-26
+genodelabs/src/stdcxx/2018-11-26
+genodelabs/src/vfs/2018-11-27
+genodelabs/src/zlib/2018-11-26
+_/src/io_editor
diff --git a/recipes/pkg/terminal_editor/hash b/recipes/pkg/terminal_editor/hash
new file mode 100644
index 0000000..1f39d89
--- /dev/null
+++ b/recipes/pkg/terminal_editor/hash
@@ -0,0 +1 @@
+2019-01-05 b363069b287c6dae54c52fd9f12f01c3c0d8c345
diff --git a/recipes/pkg/terminal_editor/runtime b/recipes/pkg/terminal_editor/runtime
new file mode 100644
index 0000000..ed43885
--- /dev/null
+++ b/recipes/pkg/terminal_editor/runtime
@@ -0,0 +1,52 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/recipes/src/io_editor/content.mk b/recipes/src/io_editor/content.mk
new file mode 100644
index 0000000..5a05179
--- /dev/null
+++ b/recipes/src/io_editor/content.mk
@@ -0,0 +1,15 @@
+MIRROR_FROM_LIBPORTS = src/app/qt5/tmpl
+
+MIRROR_FROM_REP_DIR := src/app/io_editor
+
+content: $(MIRROR_FROM_LIBPORTS) $(MIRROR_FROM_REP_DIR) LICENSE
+
+$(MIRROR_FROM_REP_DIR):
+ $(mirror_from_rep_dir)
+
+$(MIRROR_FROM_LIBPORTS):
+ mkdir -p $(@)
+ cp $(GENODE_DIR)/repos/libports/$@/* $@
+
+LICENSE:
+ cp $(GENODE_DIR)/LICENSE $@
diff --git a/recipes/src/io_editor/hash b/recipes/src/io_editor/hash
new file mode 100644
index 0000000..35d0c4a
--- /dev/null
+++ b/recipes/src/io_editor/hash
@@ -0,0 +1 @@
+2019-01-04 70c1fea117ab4315889afb0d6821037187667496
diff --git a/recipes/src/io_editor/used_apis b/recipes/src/io_editor/used_apis
new file mode 100644
index 0000000..f80e668
--- /dev/null
+++ b/recipes/src/io_editor/used_apis
@@ -0,0 +1,11 @@
+base
+libc
+mesa
+qt5_component
+qt5_core
+qt5_gui
+qt5_printsupport
+qt5_qjpeg
+qt5_qpa_nitpicker
+qt5_widgets
+stdcxx
diff --git a/src/app/io_editor/highlighter.cpp b/src/app/io_editor/highlighter.cpp
new file mode 100644
index 0000000..183708b
--- /dev/null
+++ b/src/app/io_editor/highlighter.cpp
@@ -0,0 +1,155 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the examples of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** BSD License Usage
+** Alternatively, you may use this file under the terms of the BSD license
+** as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#include "highlighter.h"
+
+//! [0]
+Highlighter::Highlighter(QTextDocument *parent)
+ : QSyntaxHighlighter(parent)
+{
+ HighlightingRule rule;
+
+ keywordFormat.setForeground(Qt::darkBlue);
+ keywordFormat.setFontWeight(QFont::Bold);
+ QStringList keywordPatterns;
+ keywordPatterns << "\\bchar\\b" << "\\bclass\\b" << "\\bconst\\b"
+ << "\\bdouble\\b" << "\\benum\\b" << "\\bexplicit\\b"
+ << "\\bfriend\\b" << "\\binline\\b" << "\\bint\\b"
+ << "\\blong\\b" << "\\bnamespace\\b" << "\\boperator\\b"
+ << "\\bprivate\\b" << "\\bprotected\\b" << "\\bpublic\\b"
+ << "\\bshort\\b" << "\\bsignals\\b" << "\\bsigned\\b"
+ << "\\bslots\\b" << "\\bstatic\\b" << "\\bstruct\\b"
+ << "\\btemplate\\b" << "\\btypedef\\b" << "\\btypename\\b"
+ << "\\bunion\\b" << "\\bunsigned\\b" << "\\bvirtual\\b"
+ << "\\bvoid\\b" << "\\bvolatile\\b";
+ foreach (const QString &pattern, keywordPatterns) {
+ rule.pattern = QRegExp(pattern);
+ rule.format = keywordFormat;
+ highlightingRules.append(rule);
+//! [0] //! [1]
+ }
+//! [1]
+
+//! [2]
+ classFormat.setFontWeight(QFont::Bold);
+ classFormat.setForeground(Qt::darkMagenta);
+ rule.pattern = QRegExp("\\bQ[A-Za-z]+\\b");
+ rule.format = classFormat;
+ highlightingRules.append(rule);
+//! [2]
+
+//! [3]
+ singleLineCommentFormat.setForeground(Qt::red);
+ rule.pattern = QRegExp("//[^\n]*");
+ rule.format = singleLineCommentFormat;
+ highlightingRules.append(rule);
+
+ multiLineCommentFormat.setForeground(Qt::red);
+//! [3]
+
+//! [4]
+ quotationFormat.setForeground(Qt::darkGreen);
+ rule.pattern = QRegExp("\".*\"");
+ rule.format = quotationFormat;
+ highlightingRules.append(rule);
+//! [4]
+
+//! [5]
+ functionFormat.setFontItalic(true);
+ functionFormat.setForeground(Qt::blue);
+ rule.pattern = QRegExp("\\b[A-Za-z0-9_]+(?=\\()");
+ rule.format = functionFormat;
+ highlightingRules.append(rule);
+//! [5]
+
+//! [6]
+ commentStartExpression = QRegExp("/\\*");
+ commentEndExpression = QRegExp("\\*/");
+}
+//! [6]
+
+//! [7]
+void Highlighter::highlightBlock(const QString &text)
+{
+ foreach (const HighlightingRule &rule, highlightingRules) {
+ QRegExp expression(rule.pattern);
+ int index = expression.indexIn(text);
+ while (index >= 0) {
+ int length = expression.matchedLength();
+ setFormat(index, length, rule.format);
+ index = expression.indexIn(text, index + length);
+ }
+ }
+//! [7] //! [8]
+ setCurrentBlockState(0);
+//! [8]
+
+//! [9]
+ int startIndex = 0;
+ if (previousBlockState() != 1)
+ startIndex = commentStartExpression.indexIn(text);
+
+//! [9] //! [10]
+ while (startIndex >= 0) {
+//! [10] //! [11]
+ int endIndex = commentEndExpression.indexIn(text, startIndex);
+ int commentLength;
+ if (endIndex == -1) {
+ setCurrentBlockState(1);
+ commentLength = text.length() - startIndex;
+ } else {
+ commentLength = endIndex - startIndex
+ + commentEndExpression.matchedLength();
+ }
+ setFormat(startIndex, commentLength, multiLineCommentFormat);
+ startIndex = commentStartExpression.indexIn(text, startIndex + commentLength);
+ }
+}
+//! [11]
diff --git a/src/app/io_editor/highlighter.h b/src/app/io_editor/highlighter.h
new file mode 100644
index 0000000..3914161
--- /dev/null
+++ b/src/app/io_editor/highlighter.h
@@ -0,0 +1,92 @@
+/****************************************************************************
+**
+** Copyright (C) 2016 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of the examples of the Qt Toolkit.
+**
+** $QT_BEGIN_LICENSE:BSD$
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** BSD License Usage
+** Alternatively, you may use this file under the terms of the BSD license
+** as follows:
+**
+** "Redistribution and use in source and binary forms, with or without
+** modification, are permitted provided that the following conditions are
+** met:
+** * Redistributions of source code must retain the above copyright
+** notice, this list of conditions and the following disclaimer.
+** * Redistributions in binary form must reproduce the above copyright
+** notice, this list of conditions and the following disclaimer in
+** the documentation and/or other materials provided with the
+** distribution.
+** * Neither the name of The Qt Company Ltd nor the names of its
+** contributors may be used to endorse or promote products derived
+** from this software without specific prior written permission.
+**
+**
+** THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+** "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+** LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+** A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+** OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+** SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+** LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+** DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+** THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+** (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+** OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE."
+**
+** $QT_END_LICENSE$
+**
+****************************************************************************/
+
+#ifndef HIGHLIGHTER_H
+#define HIGHLIGHTER_H
+
+#include
+#include
+
+QT_BEGIN_NAMESPACE
+class QTextDocument;
+QT_END_NAMESPACE
+
+//! [0]
+class Highlighter : public QSyntaxHighlighter
+{
+ Q_OBJECT
+
+public:
+ Highlighter(QTextDocument *parent = 0);
+
+protected:
+ void highlightBlock(const QString &text) override;
+
+private:
+ struct HighlightingRule
+ {
+ QRegExp pattern;
+ QTextCharFormat format;
+ };
+ QVector highlightingRules;
+
+ QRegExp commentStartExpression;
+ QRegExp commentEndExpression;
+
+ QTextCharFormat keywordFormat;
+ QTextCharFormat classFormat;
+ QTextCharFormat singleLineCommentFormat;
+ QTextCharFormat multiLineCommentFormat;
+ QTextCharFormat quotationFormat;
+ QTextCharFormat functionFormat;
+};
+//! [0]
+
+#endif // HIGHLIGHTER_H
diff --git a/src/app/io_editor/io_editor.pro b/src/app/io_editor/io_editor.pro
new file mode 100644
index 0000000..e637191
--- /dev/null
+++ b/src/app/io_editor/io_editor.pro
@@ -0,0 +1,13 @@
+QT += widgets
+
+HEADERS = \
+ highlighter.h \
+ mainwindow.h
+SOURCES = \
+ highlighter.cpp \
+ mainwindow.cpp \
+ main.cpp
+
+# install
+#target.path = $$[QT_INSTALL_EXAMPLES]/widgets/richtext/syntaxhighlighter
+INSTALLS += target
diff --git a/src/app/io_editor/main.cpp b/src/app/io_editor/main.cpp
new file mode 100644
index 0000000..a9706cb
--- /dev/null
+++ b/src/app/io_editor/main.cpp
@@ -0,0 +1,12 @@
+#include "mainwindow.h"
+
+#include
+
+int main(int argc, char *argv[])
+{
+ QApplication app(argc, argv);
+ MainWindow window;
+ window.resize(640, 512);
+ window.show();
+ return app.exec();
+}
diff --git a/src/app/io_editor/mainwindow.cpp b/src/app/io_editor/mainwindow.cpp
new file mode 100644
index 0000000..02d186f
--- /dev/null
+++ b/src/app/io_editor/mainwindow.cpp
@@ -0,0 +1,62 @@
+#include
+#include
+
+#include "mainwindow.h"
+
+/* Libc includes */
+#include
+
+MainWindow::MainWindow(QWidget *parent)
+ : QMainWindow(parent)
+{
+ remote_editor = new QTextEdit;
+ local_editor = new QTextEdit;
+
+ setupEditor(remote_editor);
+ setupEditor(local_editor);
+ remote_editor->setReadOnly(true);
+
+ QPushButton *button = new QPushButton("Submit", this);
+ connect(button, &QAbstractButton::clicked, this, &MainWindow::submit);
+
+ QVBoxLayout *layout = new QVBoxLayout;
+ layout->addWidget(remote_editor);
+ layout->addWidget(local_editor);
+ layout->addWidget(button);
+
+ QWidget *centralWidget = new QWidget;
+ centralWidget->setLayout(layout);
+ setCentralWidget(centralWidget);
+
+ new QShortcut(QKeySequence(Qt::CTRL + Qt::Key_Enter), this, SLOT(submit()));
+ new QShortcut(QKeySequence(Qt::CTRL + Qt::Key_Return), this, SLOT(submit()));
+}
+
+void MainWindow::setupEditor(QTextEdit *editor)
+{
+ QFont font;
+ font.setFamily("Courier");
+ font.setFixedPitch(true);
+ font.setPointSize(10);
+
+ editor->setFont(font);
+
+ //highlighter = new Highlighter(editor->document());
+}
+
+void MainWindow::load()
+{
+ char buf[4096];
+
+ ssize_t n = read(0, buf, sizeof(buf)-1);
+ buf[n] = 0;
+ remote_editor->setPlainText(QString(buf));
+}
+
+void MainWindow::submit()
+{
+ QByteArray b = local_editor->toPlainText().toLocal8Bit();
+ if (b.size() > 0)
+ write(1, b.data(), b.size());
+ load();
+}
diff --git a/src/app/io_editor/mainwindow.h b/src/app/io_editor/mainwindow.h
new file mode 100644
index 0000000..accce5c
--- /dev/null
+++ b/src/app/io_editor/mainwindow.h
@@ -0,0 +1,33 @@
+
+#ifndef MAINWINDOW_H
+#define MAINWINDOW_H
+
+#include "highlighter.h"
+
+#include
+#include
+
+QT_BEGIN_NAMESPACE
+class QTextEdit;
+QT_END_NAMESPACE
+
+class MainWindow : public QMainWindow
+{
+ Q_OBJECT
+
+public:
+ MainWindow(QWidget *parent = 0);
+
+public slots:
+ void submit();
+
+private:
+ void setupEditor(QTextEdit *editor);
+ void load();
+
+ QTextEdit *remote_editor;
+ QTextEdit *local_editor;
+ //Highlighter *highlighter;
+};
+
+#endif // MAINWINDOW_H
diff --git a/src/app/io_editor/target.mk b/src/app/io_editor/target.mk
new file mode 100644
index 0000000..2db2a8d
--- /dev/null
+++ b/src/app/io_editor/target.mk
@@ -0,0 +1,15 @@
+QT5_PORT_DIR := $(call select_from_ports,qt5)
+QT5_CONTRIB_DIR := $(QT5_PORT_DIR)/src/lib/qt5/qt5
+
+QMAKE_PROJECT_PATH = $(REP_DIR)/src/app/io_editor
+QMAKE_PROJECT_FILE = $(QMAKE_PROJECT_PATH)/io_editor.pro
+
+vpath % $(QMAKE_PROJECT_PATH)
+
+include $(call select_from_repositories,src/app/qt5/tmpl/target_defaults.inc)
+
+include $(call select_from_repositories,src/app/qt5/tmpl/target_final.inc)
+
+LIBS += qt5_component qt5_printsupport
+
+CC_CXX_WARN_STRICT =