commander is a marionette renderer that aims to unite the best of both worlds: declarative user interfaces and terminal applications.

Visually and logically a commander program is split up horizontally into two sections:

  • output section

    arbitrary size, just text output rendered to the screen

  • input section

    It typically consists of two lines:

    • prompt line that prompts the user for input (e.g. "Press the 's' key to start" or "Enter your name")
    • command line that holds the cursor an receives user input

One characteristic is that the cursor will always stay in the lowermost line. You'll not find the cursor in some input fields scattered around the screen.

#CliSurface Source

data CliSurface msg

The rendered surface in the terminal. Equivalent to Html msg types in Web frameworks.

It's responsible for both

  • render output to the console
  • handle user input


#Completions Source

data Completions

Text input can optionally define a completer function


#Config Source

type Config = { clearScreen :: Boolean, noPrompt :: String, prompt :: String -> String, separator :: Maybe String }

Main configuration options for the commander renderer

  • clearScreen defines weather the terminal screen should be cleared before each render. If not, subsequent views are rendered below each other in the terminal.
  • separator optionally render a separator between the output and the input section. E.g. ------------
  • prompt sets the rendering of the prompt line. E.g. \text -> "> " <> text
  • noPrompt defines what should be rendered if there is no user input prompt.

#KeyPrompt Source

newtype KeyPrompt

The prompt text used when the user should enter a key


#KeyboardUserInput Source

data KeyboardUserInput msg

In a commander program the way user input is received is constrained to the following options


#NativeNodeKey Source

type NativeNodeKey = { ctrl :: Boolean, meta :: Boolean, name :: String, sequence :: String, shift :: Boolean }

When a key event is received the following native nodejs key event can be handled. In the future this may change in favor of a parsed representation. Unfortunately there seems to be no official listing of possible key names,

So here are some common ones: up/down/right/left/a/b/c/1/2/3/space/f1/f2/f3/backspace/return

You can use node -e 'readline.emitKeypressEvents(process.stdin); process.stdin.setRawMode(true).on("keypress", console.log)' to investigate more.

#Output Source

newtype Output

Text output printed to the console



#TextPrompt Source

data TextPrompt

The prompt text used when the user should enter some text


#View Source

type View msg sta = sta -> CliSurface msg

The actual high level view function that the user will provide

#defaultConfig Source

defaultConfig :: Config

Some defaults for the Config type

#mkRenderer Source

mkRenderer :: forall msg sta. View msg sta -> Config -> Renderer msg sta

Creates an commander renderer from a view function with configuration

#mkRenderer_ Source

mkRenderer_ :: forall msg sta. View msg sta -> Renderer msg sta

Creates an commander renderer from a view function

#noCliSurface Source

noCliSurface :: forall msg. CliSurface msg

Shorthand for an empty and eventless surface