Prompt behaviour (prompt v0.5.14) View Source

Helpers for building interactive command line interfaces.

Basic Usage

import Prompt includes utilities for printing to the screen (including support for tables), asking for confirmation, picking from a list of choices, asking for passwords and other free form text. See each function for example usage.

Subcommands

To build a cli app that has sub-commands, define a module and use Prompt, otp_app: :your_app then build a list of Prompt.Command that represent your commands and pass them to process/2.

--version will pull your app version from mix.exs --help will print your @moduledoc for help.

Example

defmodule MyApp.CLI do
  @moduledoc "This will print when a user types `myapp --help` in the commandline"
  use Prompt, otp_app: :my_app

  # the entry point to your app, takes the command line args
  def main(argv) do
    commands = [
      {"first", MyApp.CLI.FirstCommand}
    ]
    process(argv, commands)
  end
end


defmodule MyApp.CLI.FirstCommand do
  @moduledoc "This prints when the help() command is called"
  use Prompt.Command

  @impl true
  def init(argv) do
    argv
    |> OptionParser.parse(
      strict: [help: :boolean, switch1: :boolean, swtich2: :boolean],
      aliases: [h: :help]
    )
    |> parse() #whatever you return from init will be what is passed to `process/1`
  end

  @impl true
  def process(%{help: true}, do: help()
  def process(%{switch1: switch1, switch2: switch2} do
    # do something based on the command and switches
    display("command output")
  end

  defp parse({[help: true], _, _}, do: %{help: true}
  defp parse({opts, _, _}) do
    switch1 = Keyword.get(opts, :switch1, false)
    switch2 = Keyword.get(opts, :switch2, false)  
    %{help: false, switch1: switch1, switch2: switch2}
  end
end

The first element in the command tuple is what you expect the user to use as a command, the second is the Prompt.Command module that will process the command.

Once built, your command will be able to take a first subcommand.

>>> my_app first --switch1
command output
...
>>> my_app --version
0.0.1

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 [Slim](https://github.com/silbermm/slim_pickens]

Link to this section Summary

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.

Display a Y/n prompt.

Writes text to the screen.

Prompt the user for input, but conceal the users typing.

Displays options to the user denoted by numbers.

Print an ASCII table of data. Requires a list of lists as input.

Display text on the screen and wait for the users text imput.

Callbacks

Process the command line arguments based on the defined commands

Link to this section Functions

Link to this function

choice(question, custom, opts \\ [])

View Source

Specs

choice(String.t(), keyword(), keyword()) :: atom()

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.

Available options:

  • default_answer: the default answer. If default isn't passed, the first is the default.
  • color: A color from the IO.ANSI module

Examples

iex> Prompt.choice("Save password?",
...>   [yes: "y", no: "n", regenerate: "r"],
...>   default_answer: :regenerate
...> )
"Save Password? (y/n/R):" [enter]
iex> :regenerate
Link to this function

confirm(question, opts \\ [])

View Source

Specs

confirm(String.t(), keyword()) :: :yes | :no | :error

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

Available options:

  • color: A color from the IO.ANSI module
  • default_answer: :yes or :no
  • mask_line: should the line be erased after the confirm

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
Link to this function

display(text, opts \\ [])

View Source

Specs

display(String.t() | [String.t()], keyword()) :: :ok

Writes text to the screen.

Takes a single string argument or a list of strings where each item in the list will be diplayed on a new line.

Available options:

  • color: A color from the IO.ANSI module
  • trim: true | false --- Defaults to false (will put a at the end of the text
  • position: :left | :right --- Print the content starting from the leftmost position or the rightmost position
  • mask_line: true | false --- Prompts the user to press enter and afterwards masks the line just printed
    • the main use case here is a password that you may want to show the user but hide after the user has a chance to write it down, or copy it.

Examples

iex> Prompt.display("Hello from the terminal!")
"Hello from the terminal!"

iex> Prompt.display(["Hello", "from", "the", "terminal"])
"Hello"
"from"
"the"
"terminal"
Link to this function

password(display, opts \\ [])

View Source

Specs

password(String.t(), keyword()) :: String.t()

Prompt the user for input, but conceal the users typing.

Available options:

  • color: A color from the IO.ANSI module

Examples

iex> Prompt.password("Enter your passsword")
"Enter your password:"
iex> "super_secret_passphrase"
Link to this function

select(display, choices, opts \\ [])

View Source

Specs

select(String.t(), [String.t()] | [{String.t(), any()}], keyword()) ::
  any() | :error

Displays options to the user denoted by numbers.

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.

Available options:

  • color: A color from the IO.ANSI module
  • multi: true | false (default) - allow for the user to select multiple values?

Examples

iex> Prompt.select("Choose One", ["Choice A", "Choice B"])
"  [1] Choice A"
"  [2] Choice B"
"Choose One [1-2]:" 1
iex> "Choice A"

iex> Prompt.select("Choose One", [{"Choice A", 1000}, {"Choice B", 1001}])
"  [1] Choice A"
"  [2] Choice B"
"Choose One [1-2]:" 2
iex> 1001

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]:" 1 2
iex> ["Choice A", "Choice B"]
Link to this function

table(matrix, opts \\ [])

View Source

Specs

table([list()], keyword()) :: :ok

Print an ASCII table of data. Requires a list of lists as input.

Available Options

  • header: true | false (default) --- use the first element as a header of the table
  • TODO: title: "TITLE" --- Create a title for the table
  • TODO: border: :normal
  • TODO: borer_color:

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      |
 +-------+------+---------+----------+
"
Link to this function

text(display, opts \\ [])

View Source

Specs

text(String.t(), keyword()) :: String.t()

Display text on the screen and wait for the users text imput.

Available options:

  • color: A color from the IO.ANSI module

Examples

iex> Prompt.text("Enter your email")
"Enter your email:" t@t.com
iex> t@t.com

Link to this section Callbacks

Specs

process(list(), [{String.t(), Process.Command}]) :: non_neg_integer()

Process the command line arguments based on the defined commands