View Source Owl.IO (Owl v0.12.0)

A set of functions for handling IO with support of Owl.Data.t/0.

Summary

Functions

Returns a width of a terminal.

Asks user to type a confirmation.

Reads a line from the stdio and casts a value to the given type.

Wrapper around IO.inspect/3 with changed defaults.

Select multiple values from the given nonempty list.

Wrapper around IO.puts/2 that accepts Owl.Data.t/0.

Returns a height of a terminal.

Selects one item from the given nonempty list.

Types

@type cast_input() :: (String.t() | nil ->
                   {:ok, value :: any()} | {:error, reason :: String.Chars.t()})
@type confirm_option() ::
  {:message, Owl.Data.t()}
  | {:default, boolean()}
  | {:answers,
     true: {primary_true_answer :: binary(), other_true_answers :: [binary()]},
     false:
       {primary_false_answer :: binary(), other_false_answers :: [binary()]}}
@type input_option() ::
  {:label, Owl.Data.t()}
  | {:cast, atom() | {atom(), Keyword.t()} | cast_input()}
  | {:optional, boolean()}
@type multiselect_option() ::
  {:label, Owl.Data.t() | nil}
  | {:render_as, (any() -> Owl.Data.t())}
  | {:min, non_neg_integer() | nil}
  | {:max, non_neg_integer() | nil}
@type select_option() ::
  {:label, Owl.Data.t() | nil} | {:render_as, (any() -> Owl.Data.t())}

Functions

Link to this function

columns(device \\ :stdio)

View Source
@spec columns(IO.device()) :: pos_integer() | nil

Returns a width of a terminal.

A wrapper around :io.columns/1, but returns nil if terminal is not found. This is useful for convenient falling back to other value using ||/2 operator.

Example

Owl.IO.columns() || 80
@spec confirm([confirm_option()]) :: boolean()

Asks user to type a confirmation.

Valid inputs are a blank string and values specified in :answers option. User will be asked to type a confirmation again on invalid input.

Options

  • :message - typically a question about performing operation. Defaults to "Are you sure?".
  • :default - a value that is used when user responds with a blank string. Defaults to false.
  • :answers - allows to specify alternative answers. Defaults to [true: {"y", ["yes"]}, false: {"n", ["no"]}].

Examples

Owl.IO.confirm()
#=> Are you sure? [yN] n
false

Owl.IO.confirm(message: Owl.Data.tag("Really?", :red), default: true)
#=> Really? [Yn]
true

Owl.IO.confirm(
  message: Owl.Data.tag("Справді?", :red),
  answers: [true: {"т", ["так", "y", "yes"]}, false: {"н", ["ні", "n", "no"]}]
)
#=> Справді? [тН] НІ
false
@spec input([input_option()]) :: any()

Reads a line from the stdio and casts a value to the given type.

After reading a line from stdio it will be automatically trimmed with String.trim/2. The end value will be returned when user types a valid value.

Options

  • :secret - set to true if you want to make input invisible. Defaults to false.
  • :label - a text label. Defaults to nil (no label).
  • :optional - a boolean that sets whether value is optional. Defaults to false.
  • :cast - casts a value after reading it from stdio. Defaults to :string. Possible values:
    • an anonymous function with arity 1 that is described by cast_input/0
    • a pair with built-in type represented as atom and a keyword-list with options. Built-in types:
      • :integer, options:
        • :min - a minimum allowed value. Defaults to nil (no lower bound).
        • :max - a maximum allowed value. Defaults to nil (no upper bound).
      • :string, options:
        • no options
    • an atom which is simply an alias to {atom(), []}

Examples

Owl.IO.input()
#=> > hello world
"hello world"

Owl.IO.input(secret: true)
#=> >
"password"

Owl.IO.input(optional: true)
#=> >
nil

Owl.IO.input(label: "Your age", cast: {:integer, min: 18, max: 100})
#=> Your age
#=> > 12
#=> must be greater than or equal to 18
#=> Your age
#=> > 102
#=> must be less than or equal to 100
#=> Your age
#=> > 18
18

Owl.IO.input(label: "Birth date in ISO 8601 format:", cast: &Date.from_iso8601/1)
#=> Birth date in ISO 8601 format:
#=> > 1 January
#=> invalid_format
#=> Birth date in ISO 8601 format:
#=> > 2021-01-01
~D[2021-01-01]
Link to this function

inspect(item, opts \\ [], device \\ :stdio)

View Source
@spec inspect(item, keyword(), IO.device()) :: item when item: var

Wrapper around IO.inspect/3 with changed defaults.

As in puts/2, device argument is moved to the end. Options are the same as for IO.inspect/3 with small changes:

  • :pretty is true by default.
  • :syntax_colors uses color schema from IEx by default.
  • :label is extended and accepts Owl.Data.t/0.

Examples

"Hello"
|> Owl.IO.inspect(label: "Greeting")
|> String.upcase()
|> Owl.IO.inspect(label: Owl.Data.tag("GREETING", :cyan))
#=> Greeting: "Hello"
#=> GREETING: "HELLO"

# inspect data above rendered live blocks
Owl.IO.inspect("Hello", [], Owl.LiveScreen)
#=> "Hello"
Link to this function

multiselect(list, opts \\ [])

View Source
@spec multiselect([item, ...], [multiselect_option()]) :: [item] when item: any()

Select multiple values from the given nonempty list.

Input item numbers must be separated by any non-digit character. Most likely you'd want to use spaces or commas. It is possible to specify a range of numbers using hyphen.

Options

  • :label - a text label. Defaults to nil (no label).
  • :render_as - a function that renders given item. Defaults to Function.identity/1.
  • :min - a minimum output list length. Defaults to nil (no lower bound).
  • :max - a maximum output list length. Defaults to nil (no upper bound).

Examples

Owl.IO.multiselect(["one", "two", "three"], min: 2, label: "Select 2 numbers:", render_as: &String.upcase/1)
#=> 1. ONE
#=> 2. TWO
#=> 3. THREE
#=>
#=> Select 2 numbers:
#=> > 1
#=> the number of elements must be greater than or equal to 2
#=> Select 2 numbers:
#=> > 1 3
#=>
["one", "three"]

Owl.IO.multiselect(Enum.to_list(1..5), render_as: &to_string/1)
#=> 1. 1
#=> 2. 2
#=> 3. 3
#=> 4. 4
#=> 5. 5
#=>
#=> > 1-3 5
#=>
[1, 2, 3, 5]
Link to this function

open_in_editor(data, elixir_editor \\ System.fetch_env!("ELIXIR_EDITOR"))

View Source

Opens data in editor for editing.

Returns updated data when file is saved and editor is closed. Similarly to IEx.Helpers.open/1, this function uses ELIXIR_EDITOR environment variable by default. __FILE__ notation is supported as well.

Example

# use neovim in alacritty terminal emulator as an editor
$ export ELIXIR_EDITOR="alacritty -e nvim"

# open editor from Elixir code
Owl.IO.open_in_editor("hello\nworld")

# specify editor explicitly
Owl.IO.open_in_editor("hello\nworld", "alacritty -e nvim")
Link to this function

puts(data, device \\ :stdio)

View Source
@spec puts(Owl.Data.t(), device :: IO.device()) :: :ok

Wrapper around IO.puts/2 that accepts Owl.Data.t/0.

The other difference is that device argument is moved to second argument.

Examples

Owl.IO.puts(["Hello ", Owl.Data.tag("world", :green)])
#=> Hello world

# specify Owl.LiveScreen as a device in order to print data above rendered live blocks
Owl.IO.puts(["Hello ", Owl.Data.tag("world", :green)], Owl.LiveScreen)
#=> Hello world
@spec rows(IO.device()) :: pos_integer() | nil

Returns a height of a terminal.

A wrapper around :io.rows/1, but returns nil if terminal is not found. This is useful for convenient falling back to other value using ||/2 operator.

Example

Owl.IO.rows() || 20
Link to this function

select(list, opts \\ [])

View Source
@spec select([item, ...], [select_option()]) :: item when item: any()

Selects one item from the given nonempty list.

Returns value immediately if list contains only 1 element.

Options

  • :label - a text label. Defaults to nil (no label).
  • :render_as - a function that renders given item. Defaults to Function.identity/1.

Examples

Owl.IO.select(["one", "two", "three"])
#=> 1. one
#=> 2. two
#=> 3. three
#=>
#=> > 1
#=>
"one"


~D[2001-01-01]
|> Date.range(~D[2001-01-03])
|> Enum.to_list()
|> Owl.IO.select(render_as: &Date.to_iso8601/1, label: "Please select a date")
#=> 1. 2001-01-01
#=> 2. 2001-01-02
#=> 3. 2001-01-03
#=>
#=> Please select a date
#=> > 2
#=>
~D[2001-01-02]


packages = [
  %{name: "elixir", description: "programming language"},
  %{name: "asdf", description: "version manager"},
  %{name: "neovim", description: "fork of vim"}
]
Owl.IO.select(packages,
  render_as: fn %{name: name, description: description} ->
    [Owl.Data.tag(name, :cyan), "\n  ", Owl.Data.tag(description, :light_black)]
  end
)
#=> 1. elixir
#=>      programming language
#=> 2. asdf
#=>      version manager
#=> 3. neovim
#=>      fork of vim
#=>
#=> > 3
#=>
%{description: "fork of vim", name: "neovim"}