Prompt (prompt v0.12.0)
View SourcePrompt provides a complete solution for building interactive command line applications.
It's very flexible and can be used just to provide helpers for taking input from the user and displaying output.
Basic Usage
import Prompt includes utilities for:
- printing to the screen ->
display/1 - printing tables to the screen ->
table/1 - asking for confirmation ->
confirm/1 - picking from a list of choices ->
select/2 - asking for passwords ->
password/1 - free form text input ->
text/1
Advanced usage
See Prompt.Router
Examples
Building for Distribution
There are a couple of different options for building a binary ready for distributing. Which ever approach you decide to use, you'll probably want to keep the docs instead of stripping them. For escripts, you'll add the following to the escript key in mix.exs, if using Bakeware, you'll add it to the releases key.
:strip_beams: [keep: ["Docs"]]Escript
An escript is the most straightforward approach, but requires that erlang is already installed on the system.
Bakeware
This has been my preferred approach recently. Bakeware uses releases to build a single executable binary that can be run on the system without the dependency on erlang or elixir.
For Bakeware, I also set export RELEASE_DISTRIBUTION=none in rel/env.sh.eex and rel/env.bat.eex - unless you need erlang distribution in your CLI.
For a complete example see Genex
Run MIX_ENV=prod mix release to build the binary. This will output the usual release messages for a mix release command, but in the case of a CLI, it's a bit of a red herring. The binary you want to run as a CLI will be in _build/prod/rel/bakeware/<your_app>.
Burrito
Burrito is another option for building a single binary artifact. It is unique because you can build binaries for windows, mac and linux all from one machine.
For a complete example see Genex
Run MIX_ENV=prod mix release to build the binary. This will output the usual release messages for a mix release command, but in the case of a CLI, it's a bit of a red herring. The binary you want to run as a CLI will be in burrito_out/<your_app>.
Summary
Input Functions
Display a choice prompt with custom answers.
Display a Y/n prompt.
Can someone type an answer on device?
Prompt the user for input, but conceal the users typing.
Displays options to the user to choose from - single and multi select is supported.
Display text on the screen and wait for the users text imput.
Output Functions
Writes text to the screen.
Print an ASCII table of data. Requires a list of lists as input.
Types
The list of strings coming from the commmand-line arguments
A keyword list of commands and implementations of Prompt.Command
Input Functions
Display a choice prompt with custom answers.
Takes a keyword list of answers in the form of atom to return and string to display.
[yes: "y", no: "n"]
will show "(y/n)" and return :yes or :no based on the choice.
Supported options:
:color- The text color. One of[:black, :blue, :cyan, :green, :light_black, :light_blue, :light_cyan, :light_green, :light_magneta, :light_red, :light_white, :light_yellow, :magenta, :red, :white, :yellow].:background_color- The background color. One of[:black, :blue, :cyan, :green, :light_black, :light_blue, :light_cyan, :light_green, :light_magneta, :light_red, :light_white, :light_yellow, :magenta, :red, :white, :yellow].:default_answer(atom/0) - The default answer for the choices. Defaults to the first choice.
Examples
iex> Prompt.choice("Save password?",
...> [yes: "y", no: "n", regenerate: "r"],
...> default_answer: :regenerate
...> )
"Save Password? (y/n/R):" [enter]
iex> :regenerate
Display a Y/n prompt.
Sets 'Y' as the the default answer, allowing the user to just press the enter key. To make 'n' the default answer pass the option default_answer: :no
Supported options:
:color- The text color. One of[:black, :blue, :cyan, :green, :light_black, :light_blue, :light_cyan, :light_green, :light_magneta, :light_red, :light_white, :light_yellow, :magenta, :red, :white, :yellow].:background_color- The background color. One of[:black, :blue, :cyan, :green, :light_black, :light_blue, :light_cyan, :light_green, :light_magneta, :light_red, :light_white, :light_yellow, :magenta, :red, :white, :yellow].:default_answer- The default answer to the confirmation. The default value is:yes.:mask_line(boolean/0) - If set to true, this will mask the current line by replacing it with#####. Useful when showing passwords in the terminal. The default value isfalse.
Examples
iex> Prompt.confirm("Send the email?")
"Send the email? (Y/n):" Y
iex> :yes
iex> Prompt.confirm("Send the email?", default_answer: :no)
"Send the email? (y/N):" [enter]
iex> :no
Can someone type an answer on device?
Returns true when both the input and the output of device are
terminals: the answer is read from stdin and the question is written to
stdout. When input is piped, output is redirected (app > log.txt, where
the question would land in the file unseen), or the program runs without a
terminal, e.g. from cron, nobody can answer, so fall back to a default:
timeout = if Prompt.interactive?(), do: Prompt.text("Timeout"), else: "30"This is the same rule OTP applies to raw mode, so it is also when
select/3 uses the arrow-key picker.
Defaults to standard I/O. It checks the :stdin and :stdout options that
standard I/O reports, or :terminal on a device without them.
interactive?(:standard_error) tells whether stderr is a terminal. Returns
false if the device cannot be queried.
Prompt the user for input, but conceal the users typing.
Supported options:
:color- The text color. One of[:black, :blue, :cyan, :green, :light_black, :light_blue, :light_cyan, :light_green, :light_magneta, :light_red, :light_white, :light_yellow, :magenta, :red, :white, :yellow]. Defaults to the terminal default.:background_color- The background color. One of[:black, :blue, :cyan, :green, :light_black, :light_blue, :light_cyan, :light_green, :light_magneta, :light_red, :light_white, :light_yellow, :magenta, :red, :white, :yellow]. Defaults to the terminal default.
Examples
iex> Prompt.password("Enter your passsword")
"Enter your password:"
iex> "super_secret_passphrase"
@spec select(String.t(), [String.t()] | [{String.t(), any()}], keyword()) :: binary() | any() | list() | {:other, String.t()} | :error
Displays options to the user to choose from - single and multi select is supported.
Allows for a list of 2 tuples where the first value is what is displayed and the second value is what is returned to the caller.
Supported options:
:color- The text color. One of[:black, :blue, :cyan, :green, :light_black, :light_blue, :light_cyan, :light_green, :light_magneta, :light_red, :light_white, :light_yellow, :magenta, :red, :white, :yellow]. Defaults to the terminal default.:background_color- The background color. One of[:black, :blue, :cyan, :green, :light_black, :light_blue, :light_cyan, :light_green, :light_magneta, :light_red, :light_white, :light_yellow, :magenta, :red, :white, :yellow]. Defaults to the terminal default.:multi(boolean/0) - Allows multiple selections from the options presented. The default value isfalse.:select_keys(a list of keyboard keys or escape sequences) - Erlang >= 28 only - determines which keyboard keys are used to mark a selection withmulti: true. Defaults to["\t", " "](tab and space), or["\t"]withfilter: true, where space is typed into the filter.:filter(boolean/0) - Arrow-key picker only - typing narrows the choices to those whose displayed text contains what was typed, ignoring case. Backspace removes a character and escape clears the filter. The arrow keys still move, butjandkare typed instead of moving. Theallow_otherchoice always stays visible. Ignored by the numbered prompt. The default value isfalse.:suggested(list ofterm/0) - Choices to list first, above a divider, in the given order; the rest follow in their usual order. Name each likedefault: a plain string choice, or the value of a{display, value}choice. A value that is not one of the choices makesselect/3write an error to stderr and return:error.:select_indicator(String.t/0) - The default value is">".:default(term/0) - The choice that starts selected: a plain string choice, or the value of a{display, value}choice. Pressing enter right away returns it (in the numbered prompt, an empty line does). A default that is not one of the choices makesselect/3write an error to stderr and return:error. Not supported withmulti: true.:allow_other(String.t/0) - A label added as the last choice. Choosing it asks for free text and returns{:other, text}. Cannot be combined withmulti: true.:other_prompt(String.t/0) - The question asked when theallow_otherchoice is picked. The default value is"Enter a value".
Examples
iex> Prompt.select("Choose One", ["Choice A", "Choice B"])
"Choose One"
" > Choice A"
" Choice B"
iex> Prompt.select("Choose One", [{"Choice A", 1000}, {"Choice B", 1001}])
"Choose One"
" > Choice A"
" Choice B"
iex> Prompt.select("Choose as many as you want", ["Choice A", "Choice B"], multi: true)
"Choose as many as you want (<tab> marks selection, <enter> submits choices)
" > Choice A"
" > Choice B"The numbered prompt
The arrow-key picker needs Erlang 28 or newer, for its raw input mode, and
both standard input and output must be terminals. Otherwise, for example on
Erlang 27, in IEx, when input is piped, when output is redirected to a file, or in
ExUnit.CaptureIO, the select falls back to asking the user to type the
number of the choice and press <enter>. With multi: true they type the
numbers separated by spaces. It looks like:
Prompt.select("Choose One", ["Choice A", "Choice B"])
[1] Choice A
[2] Choice B
Choose One [1-2]:
iex> Prompt.select("Choose One", [{"Choice A", 1000}, {"Choice B", 1001}])
[1] Choice A
[2] Choice B
Choose One [1-2]:
iex> Prompt.select("Choose as many as you want", ["Choice A", "Choice B"], multi: true)
[1] Choice A
[2] Choice B
Choose as many as you want [1-2]:Display text on the screen and wait for the users text imput.
Supported options:
:color- The text color. One of[:black, :blue, :cyan, :green, :light_black, :light_blue, :light_cyan, :light_green, :light_magneta, :light_red, :light_white, :light_yellow, :magenta, :red, :white, :yellow]. Defaults to the terminal default.:background_color- The background color. One of[:black, :blue, :cyan, :green, :light_black, :light_blue, :light_cyan, :light_green, :light_magneta, :light_red, :light_white, :light_yellow, :magenta, :red, :white, :yellow]. Defaults to the terminal default.:min(integer/0) - The minimum charactors required for input The default value is0.:max(integer/0) - The maximum charactors required for input The default value is0.
Examples
iex> Prompt.text("Enter your email")
"Enter your email:" t@t.com
iex> t@t.com
Output Functions
Writes text to the screen.
Takes a single string argument or a list of strings where each item in the list will be displayed on a new line.
Supported options:
:color- The text color. One of[:black, :blue, :cyan, :green, :light_black, :light_blue, :light_cyan, :light_green, :light_magneta, :light_red, :light_white, :light_yellow, :magenta, :red, :white, :yellow]. Defaults to the terminal default.:background_color- The background color. One of[:black, :blue, :cyan, :green, :light_black, :light_blue, :light_cyan, :light_green, :light_magneta, :light_red, :light_white, :light_yellow, :magenta, :red, :white, :yellow]. Defaults to the terminal default.:device- The IO device to write to, one of:stdioor:stderr. The default value is:stdio.:position- Print the content starting from the leftmost position or the rightmost position The default value is:left.:mask_line(boolean/0) - If set to true, this will mask the current line by replacing it with#####. Useful when showing passwords in the terminal. The default value isfalse.:alt_buffer(boolean/0) - Should the display on an alternative buffer? The default value isfalse.
Examples
iex> Prompt.display("Hello from the terminal!")
"Hello from the terminal!"
iex> Prompt.display(["Hello", "from", "the", "terminal"])
"Hellofromtheterminal"
iex> Prompt.display(["Hello", " from", " the", " terminal"])
"Hellofromtheterminal"
Print an ASCII table of data. Requires a list of lists as input.
Supported options:
:header(boolean/0) - Use the first element as the header for the table. The default value isfalse.:align- Alignment of each column, a list of:leftor:right. Columns beyond the list are:left. The default value is[].:footer(boolean/0) - Draw a row delimiter above the last row, to set it apart as a footer. The default value isfalse.:max_width- Cut a cell wider than its column's maximum, ending it with…. Either one positive integer for every column, or a list with a positive integer ornil(no limit) for each column. Columns past the end of the list have no limit.:border- Determine how the border is displayed, one of :normal (default), :markdown, or :none The default value is:normal.:color- The text color. One of[:black, :blue, :cyan, :green, :light_black, :light_blue, :light_cyan, :light_green, :light_magneta, :light_red, :light_white, :light_yellow, :magenta, :red, :white, :yellow]. Defaults to the terminal default.:device- The IO device to write to, one of:stdioor:stderr. The default value is:stdio.
Examples
iex> Prompt.table([["Hello", "from", "the", "terminal!"],["this", "is", "another", "row"]])
"
+-------+------+---------+----------+
| Hello | from | the | terminal |
| this | is | another | row |
+-------+------+---------+----------+
"
iex> Prompt.table([["One", "Two", "Three", "Four"], ["Hello", "from", "the", "terminal!"],["this", "is", "another", "row"]], header: true)
"
+-------+------+---------+----------+
| One | Two | Three | Four |
+-------+------+---------+----------+
| Hello | from | the | terminal |
| this | is | another | row |
+-------+------+---------+----------+
"
iex> Prompt.table([["One", "Two", "Three", "Four"], ["Hello", "from", "the", "terminal!"],["this", "is", "another", "row"]], header: true, border: :markdown)
"
| One | Two | Three | Four |
|-------|------|---------|----------|
| Hello | from | the | terminal |
| this | is | another | row |
"
iex> Prompt.table([["Hello", "from", "the", "terminal!"],["this", "is", "another", "row"]], border: :none)
"
Hello from the terminal
this is another row
"
Types
@type argv() :: [String.t()]
The list of strings coming from the commmand-line arguments
@type command_list() :: keyword(Prompt.Command)
A keyword list of commands and implementations of Prompt.Command
Examples
iex> commands = [help: CLI.Commands.Help, version: CLI.Commands.Version]