Back to Text UI

Mikhail Davydov

____ _ _ | __ ) __ _ ___| | __ | |_ ___ | _ \ / _` |/ __| |/ / | __/ _ \ | |_) | (_| | (__| < | || (_) | |____/ \__,_|\___|_|\_\ \__\___/ |_ _|____ _| |_ | | | |_ _| | |/ _ \ \/ / __| | | | || | | | __/> <| |_ | |_| || | |_|\___/_/\_\\__| \___/|___|

Writing, 3200 BCE

Woodblock printing, 200 AE

Printing press, 1440

Typewriter, 1860

Terminal, 70-80th

  1. Render texts

...and for ASCII Art

                                            ====
                                            o o~~
         /~\                               _\- /_
        ( oo|                  ___        / \ /  \
        _\=/_                 / ()\      //| |  |\\
       /  _  \              _|_____|_   // | |  |//
 ===================       | | === | | //  | |  //
 |                 |       |_|  O  |_|('   |===(|
 |_________________|        ||  O  ||      | || |
 |                 |        ||__*__||      (_)(_)
 |                 |       |~ \___/ ~|     |_||_|
 |                 |       /=\ /=\ /=\     |_||_|
_|_________________|_______[_]_[_]_[_]____/__][__\__
        

Text UI of Dired, 1974

Graphic UI, 1985

Window Art

GUI

  1. Text UI – step in GUI evolution
    • PC for non-technical users

Developers <3 Terminal

  1. Faster to type than click

> wget -qO- file | bsdtar -xvf-

Post GUI Text UI

  1. Toolchain is not limited
    • 1-2 good libraries for every language

DSV – Domain Specific Vocabulary

Blessed.js Demo

Blessed.js

            var box = blessed.box({
              style: {
                fg: 'white',
                bg: 'magenta'
              },
              border: {type: 'line'},
              tags: true
            });
        

Simple lib – simple DSV

            inquirer.prompt([{
              type: 'rawlist',
              name: 'tui',
              message: 'Are TUIs cool?',
              choices: ['Yup', 'Why do you ask?']
            }], (answers) => {
            });
        

Inquirer.js Demo

Creating UI engine is challenging

  1. Layout Math
    • Relative positioning
    • Dynamic box dimensions

__ __ _______ __ __ ___ | | | || || |_| || | | |_| ||_ _|| || | | | | | | || | | | | | | || |___ | _ | | | | ||_|| || | |__| |__| |___| |_| |_||_______| _______ __ __ ___ | || | | || | |_ _|| | | || | | | | |_| || | | | | || | | | | || | |___| |_______||___|

<div style="..."> Content </div>

┌---------┐ | Content| └---------┘

<div style="..."> Advanced </div> <div style="..."> Layout </div>

┌--------┐┌------┐ |Advanced||Layout| └--------┘└------┘

            <div className="mc">
                <ul className="menu">
                    <li className="menu__item"><span className="menu__item-shortcut">L</span>eft</li>
                    <li className="menu__item"><span className="menu__item-shortcut">F</span>ile</li>
                    <li className="menu__item"><span className="menu__item-shortcut">C</span>ommand</li>
                    <li className="menu__item"><span className="menu__item-shortcut">O</span>ptions</li>
                    <li className="menu__item"><span className="menu__item-shortcut">R</span>ight</li>
                </ul>
                <div className="content">
                    {this.props.leftPanel ? this._renderPanel(this.props.leftPanel.toJS()) : null}
                    {this.props.rightPanel ? this._renderPanel(this.props.rightPanel.toJS()) : null}
                </div>
                <div className="console">
                    <input className="console__input" type="text" defaultValue="~/Documents/html-cli$ node index.js" autofocus />
                </div>
                <ul className="controls">
                    <li className="control">
                        <div className="control__number">1</div>
                        <div className="control__name">Help</div>
                    </li>
                    <li className="control">
                        <div className="control__number">2</div>
                        <div className="control__name">Menu</div>
                    </li>
                    <li className="control">
                        <div className="control__number">3</div>
                        <div className="control__name">View</div>
                    </li>
                    <li className="control">
                        <div className="control__number">4</div>
                        <div className="control__name">Edit</div>
                    </li>
        

React Midnight Commander

Borrow from DOM API/CSSOM

<div style="..."> Content </div>

9 Pixel
Content
3px

Translating <div> to TUI

            let styles = window.getComputedStyle(div);
            let rect = div.getClientRects();
            let box = renderBox(rect, styles);
        

9 Symbols
3s

Translating textNode to TUI

            let styles = window.getComputedStyle(div);
            let text = div.firstChild;
            let range = document.createRange();
                        range.selectNodeContents(text);
            let rect = range.getClientRects();
            let textBox = renderText(rect, styles);
        

9 Symbols
3s
┌-------┐ | | └-------┘

┌-------┐ | | └-------┘
Content

DOMSTDOUT

STDINDOM

Forwarding Input events

  1. Read from STDIN
  2. Serialize Event
  3. Transmit to Browser
  4. Replay on DOM
  5. GOTO 1

Ways of repainting

  1. addEventListener('MozAfterPaint')

componentDidUpdate event bubbling?

No such thing!

Let's hack React!

ReactReconcileTransaction in a nutshell

ON_DOM_READY_QUEUEING Transaction

            // A queue for collecting `componentDidMount` and
            // `componentDidUpdate` callbacks during transaction
            var ON_DOM_READY_QUEUEING = {
              close: function() {
                this.reactMountReady.notifyAll();
              } // ...
            };
        

Hacking CallbackQueue

            class MyCQ extends CallbackQueue {
              notifyAll() {
                super.notifyAll();
                console.log('update');
              }
            }
            PooledClass.addPoolingTo(MyCQ);
        

Hacking ReactReconcileTransaction

            class MyRRT extends ReactReconcileTransaction {
              constructor() {
                super();
                this.reactMountReady = MyCQ.getPooled(null);
              }
            }
            PooledClass.addPoolingTo(MyRRT);
            ReactUpdates.injection
                       .injectReconcileTransaction(MyRRT);
        

Hacking ReactReconcileTransaction

  1. Global React Tree changes
    • Close enough to AfterPaint
  2. Requires onWheel event hack
  3. Doesn't help with stylesheet injections

Full Text UI Application Cycle

  1. Measure DOM & generate Text UI

Conclusion: Back to Text UI

  1. Text UI toolchain is not limited

Questions?

See more on GitHub

http://goo.gl/Ehwpa2 goo.gl/Ehwpa2

Fork me on Github