Gren TUI

Write purely functional, type-safe terminal apps using The Elm Architecture. Easily create complex, responsive UIs with an interface inspired by elm-ui. All in the very pleasant Gren programming language.

Example

A full program showing a running clock with a border in the terminal:

module Main exposing (main)


import Init
import Node
import Stream exposing (Stream)
import Task
import Time
import Tui
import UI
import UI.Border


main : Tui.Program Model Msg
main =
    Tui.defineProgram
        { init = init
        , update = update
        , view = view
        , subscriptions = subscriptions
        , onInput = GotInput
        }


-- MODEL


type alias Model =
    { time : Time.Posix
    , stdout : Stream
    }


init : Tui.Environment -> Init.Task { model : Model, command : Cmd Msg }
init env =
    Node.startProgram
        { model = 
            { time = Time.millisToPosix 0
            , stdout = env.stdout
            }
        , command =
            Tui.hideCursor env.stdout
                |> Task.execute
        }


-- VIEW


view : Model -> UI.Element
view model =
    let
        hour = String.fromInt (Time.toHour Time.utc model.time)
        minute = String.fromInt (Time.toMinute Time.utc model.time)
        second = String.fromInt (Time.toSecond Time.utc model.time)
    in
    UI.bordered [] UI.Border.rounded <|
        UI.text [] (hour ++ ":" ++ minute ++ ":" ++ second)


-- UPDATE


type Msg
    = Tick Time.Posix
    | GotInput Tui.Input


update : Msg -> Model -> { model : Model, command : Cmd Msg }
update msg model =
    case msg of
        Tick time ->
            { model = { model | time = time }
            , command = Cmd.none
            }

        GotInput input ->
            case input of
                Tui.Escape ->
                    { model = model
                    , command = 
                        Tui.exit model.stdout
                            |> Task.execute
                    }

                _ ->
                    { model = model
                    , command = Cmd.none
                    }


subscriptions : Model -> Sub Msg
subscriptions model =
    Time.every 1000 Tick

Usage

If you haven't already, install node, install gren, and take a look at the book if you want to get up to speed with the language.

Then create a gren node application:

mkdir myapp
cd myapp
gren init --platform=node

Install the gren-tui package:

gren package install blaix/gren-tui

Then create a src/Main.gren file. For a starting point, see:

Then compile and run with:

gren make src/Main.gren
node app

Getting Help or Updates

If you have questions, suggestions, find a bug, or want to follow updates to the package, you can: