Tui

Model/View/Update for the command line.

Use this module to define a command-line program that uses the elm architecture. See defineProgram for details, or one of the examples.

Defining your program

defineProgram :
{ init : Environment -> Task { model : model, command : Cmd msg }
, update : msg -> model -> { model : model, command : Cmd msg }
, subscriptions : model -> Sub msg
, view : model -> Element
, onInput : Input -> msg
}
-> Program model msg

Define your Tui program.

Very similar to a normal Node.defineProgram, except for two special functions:

view: Takes your Model and returns a UI element. gren-tui will print this to the screen, keeping track of how many lines are output so it can clear only those lines and print again when the output changes. This lets you do things like render progress bars, move characters around the screen, offer menu selections, etc.

onInput: Whenever a key is pressed, a message is sent to your app with an Input value. This lets you capture text, trigger events on certain key presses, etc.

type alias Program model msg = Program (Model model msg) (Msg msg)

Type alias for Tui programs.

type alias Environment =
{ platform : Platform
, cpuArchitecture : CpuArchitecture
, applicationPath : Path
, args : Array String
, stdout : Stream
, stderr : Stream
, stdin : Stream
, colorDepth : Int
, columns : Int
, rows : Int
}

Holds information about the environment your program is running in.

This will be passed to your init function. For example:

init env =
    Node.startProgram
        { model = 
            { maxWidth = env.columns
            , maxHeight = env.rows
            }
        , command =
            Cmd.none
        }

User Input

type Input
= KeyChar String
| Tab
| Space
| Return
| Escape
| ArrowUp
| ArrowDown
| ArrowLeft
| ArrowRight
| CursorReport Int Int
| CtrlC
| UnknownInput

Value sent to your onInput message when the program receives input (a key is pressed, a signal is received, etc.)

Your program will receive keyboard input as the keys are pressed, as opposed to getting a bunch of characters after Enter is pressed (under the hood your terminal program is running in "raw mode"). For example, if someone types "hi" after starting your program, it will receive a message with KeyChar "h" and then another message with KeyChar "i".

CursorReport is a special input type you will receive if you include Ansi.getCursorReport in your output. Use this to get the current row and column position of the cursor in the terminal (where the upper-left corner of the window is row 1 column 1).

CtrlC is the "abort" signal and gets intercepted by gren-tui to exit your program. For now you can't depend on receiving this in your app.

Helpers

exit : Stream -> Task Never {}

Task that exits the program.

The Stream argument should be the stdout value you get from Environment. This is needed to clean things up (e.g. restore cursor, unset styles, etc).

The program will exit with a 0 status code. If you want something other than zero, use exitWithCode.

Here's an example of using it in your update function to exit when the user presses the escape key:

case input of
    Tui.Escape ->
        { model = model
        , command = 
            Tui.exit model.stdout
                |> Task.execute
        }
exitWithCode : Stream -> Int -> Task Never {}

Task that exits the program with a specific exit code.

The Stream argument should be the stdout value you get from Environment. This is needed to clean things up (e.g. restore cursor, unset styles, etc).

Here's an example of using it in your update function to exit if there was a failure:

case result of
    Error e ->
        { model = model
        , command = 
            Stream.sendString model.stderr "Failed!"
                |> Task.andThen (\_ -> Tui.exitWithCode model.stdout 1)
                |> Task.execute
        }
hideCursor : Stream -> Task Never {}

Task to hide the cursor.

Here's an example of using it in init to hide the cursor as soon as the program starts:

init env =
    Node.startProgram
        { model = {}
        , command = 
            Tui.hideCursor env.stdout
                |> Task.execute
        }