IEx v1.1.1 IEx

Elixir’s interactive shell.

This module is the main entry point for Interactive Elixir and in this documentation we will talk a bit about how IEx works.

Notice that some of the functionalities described here will not be available depending on your terminal. In particular, if you get a message saying that the smart terminal could not be run, some of the features described here won’t work.

Helpers

IEx provides a bunch of helpers. They can be accessed by typing h() into the shell or as a documentation for the IEx.Helpers module.

The Break command

Inside IEx, hitting Ctrl+C will open up the BREAK menu. In this menu you can quit the shell, see process and ets tables information and much more.

The User Switch command

Besides the break command, one can type Ctrl+G to get to the user switch command menu. When reached, you can type h to get more information.

In this menu, developers are able to start new shells and alternate between them. Let’s give it a try:

User switch command
 --> s 'Elixir.IEx'
 --> c

The command above will start a new shell and connect to it. Create a new variable called hello and assign some value to it:

hello = :world

Now, let’s roll back to the first shell:

User switch command
 --> c 1

Now, try to access the hello variable again:

hello
** (UndefinedFunctionError) undefined function: hello/0

The command above fails because we have switched shells. Since shells are isolated from each other, you can’t access the variables defined in one shell from the other one.

The user switch command menu also allows developers to connect to remote shells using the r command. A topic which we will discuss next.

Remote shells

IEx allows you to connect to another node in two fashions. First of all, we can only connect to a shell if we give names both to the current shell and the shell we want to connect to.

Let’s give it a try. First start a new shell:

$ iex --sname foo
iex(foo@HOST)1>

The string between the parentheses in the prompt is the name of your node. We can retrieve it by calling the node() function:

iex(foo@HOST)1> node()
:"foo@HOST"
iex(foo@HOST)2> Node.alive?()
true

For fun, let’s define a simple module in this shell too:

iex(foo@HOST)3> defmodule Hello do
...(foo@HOST)3>   def world, do: "it works!"
...(foo@HOST)3> end

Now, let’s start another shell, giving it a name as well:

$ iex --sname bar
iex(bar@HOST)1>

If we try to dispatch to Hello.world, it won’t be available as it was defined only in the other shell:

iex(bar@HOST)1> Hello.world
** (UndefinedFunctionError) undefined function: Hello.world/0

However, we can connect to the other shell remotely. Open up the User Switch prompt (Ctrl+G) and type:

User switch command
 --> r 'foo@HOST' 'Elixir.IEx'
 --> c

Now we are connected into the remote node, as the prompt shows us, and we can access the information and modules defined over there:

rem(foo@macbook)1> Hello.world
"it works"

In fact, connecting to remote shells is so common that we provide a shortcut via the command line as well:

$ iex --sname baz --remsh foo@HOST

Where “remsh” means “remote shell”. In general, Elixir supports:

  • remsh from an Elixir node to an Elixir node
  • remsh from a plain Erlang node to an Elixir node (through the ^G menu)
  • remsh from an Elixir node to a plain Erlang node (and get an erl shell there)

Connecting an Elixir shell to a remote node without Elixir is not supported.

The .iex.exs file

When starting IEx, it will look for a local .iex.exs file (located in the current working directory), then a global one (located at ~/.iex.exs) and will load the first one it finds (if any). The code in the chosen .iex.exs file will be evaluated in the shell’s context. So, for instance, any modules that are loaded or variables that are bound in the .iex.exs file will be available in the shell after it has booted.

Sample contents of a local .iex.exs file:

# source another ".iex.exs" file
import_file "~/.iex.exs"

# print something before the shell starts
IO.puts "hello world"

# bind a variable that'll be accessible in the shell
value = 13

Running the shell in the directory where the above .iex.exs file is located results in:

$ iex
Erlang 17 [...]

hello world
Interactive Elixir - press Ctrl+C to exit (type h() ENTER for help)
iex(1)> value
13

It is possible to load another file by supplying the --dot-iex option to iex. See iex --help.

Configuring the shell

There are a number of customization options provided by the shell. Take a look at the docs for the IEx.configure/1 function by typing h IEx.configure/1.

Those options can be configured in your project configuration file or globally by calling IEx.configure/1 from your ~/.iex.exs file like this:

# .iex.exs
IEx.configure(inspect: [limit: 3])

### now run the shell ###

$ iex
Erlang 17 (erts-5.10.1) [...]

Interactive Elixir - press Ctrl+C to exit (type h() ENTER for help)
iex(1)> [1, 2, 3, 4, 5]
[1, 2, 3, ...]

Expressions in IEx

As an interactive shell, IEx evaluates expressions. This has some interesting consequences that are worth discussing.

The first one is that the code is truly evaluated and not compiled. This means that any benchmarking done in the shell is going to have skewed results. So never run any profiling nor benchmarks in the shell.

Second, IEx allows you to break an expression into many lines, since this is common in Elixir. For example:

iex(1)> "ab
...(1)> c"
"ab\nc"

In the example above, the shell will be expecting more input until it finds the closing quote. Sometimes it is not obvious which character the shell is expecting, and the user may find themselves trapped in the state of incomplete expression with no ability to terminate it other than by exiting the shell.

For such cases, there is a special break-trigger (#iex:break) that when encountered on a line by itself will force the shell to break out of any pending expression and return to its normal state:

iex(1)> ["ab
...(1)> c"
...(1)> "
...(1)> ]
...(1)> #iex:break
** (TokenMissingError) iex:1: incomplete expression

Summary

Functions

Returns registered after_spawn callbacks

Registers a function to be invoked after the IEx process is spawned

Returns string escaped using the specified color

Returns IEx configuration

Configures IEx

Gets the options used for inspecting

Returns true if IEx was started

Gets the IEx width for printing

Macros

Pries into the process environment

Functions

after_spawn()

Returns registered after_spawn callbacks.

after_spawn(fun)

Registers a function to be invoked after the IEx process is spawned.

color(color, string)

Returns string escaped using the specified color.

ANSI escapes in string are not processed in any way.

configuration()

Returns IEx configuration.

configure(options)

Configures IEx.

The supported options are: :colors, :inspect, :default_prompt, :alive_prompt and :history_size.

Colors

A keyword list that encapsulates all color settings used by the shell. See documentation for the IO.ANSI module for the list of supported colors and attributes.

The value is a keyword list. List of supported keys:

  • :enabled - boolean value that allows for switching the coloring on and off
  • :eval_result - color for an expression’s resulting value
  • :eval_info - … various informational messages
  • :eval_error - … error messages
  • :stack_app - … the app in stack traces
  • :stack_info - … the remaining info in stacktraces
  • :ls_directory - … for directory entries (ls helper)
  • :ls_device - … device entries (ls helper)

When printing documentation, IEx will convert the markdown documentation to ANSI as well. Those can be configured via:

  • :doc_code - the attributes for code blocks (cyan, bright)
  • :doc_inline_code - inline code (cyan)
  • :doc_headings - h1 and h2 (yellow, bright)
  • :doc_title - the overall heading for the output (reverse, yellow, bright)
  • :doc_bold - (bright)
  • :doc_underline - (underline)

Inspect

A keyword list containing inspect options used by the shell when printing results of expression evaluation. Default to pretty formatting with a limit of 50 entries.

See Inspect.Opts for the full list of options.

History size

Number of expressions and their results to keep in the history. The value is an integer. When it is negative, the history is unlimited.

Prompt

This is an option determining the prompt displayed to the user when awaiting input.

The value is a keyword list. Two prompt types:

  • :default_prompt - used when Node.alive? returns false
  • :alive_prompt - used when Node.alive? returns true

The following values in the prompt string will be replaced appropriately:

  • %counter - the index of the history
  • %prefix - a prefix given by IEx.Server
  • %node - the name of the local node
inspect_opts()

Gets the options used for inspecting.

pry(binding, env, timeout)

Callback for IEx.pry/1.

You can invoke this function directly when you are not able to invoke IEx.pry/1 as a macro. This function expects the binding (from Kernel.binding/0), the environment (from __ENV__) and the timeout (a sensible default is 5000).

started?()

Returns true if IEx was started.

width()

Gets the IEx width for printing.

Used by helpers and it has a maximum cap of 80 chars.

Macros

pry(timeout \\ 5000)

Pries into the process environment.

This is useful for debugging a particular chunk of code and inspect the state of a particular process. The process is temporarily changed to trap exits (i.e. the process flag :trap_exit is set to true) and has the group_leader changed to support ANSI escape codes. Those values are reverted by calling respawn, which starts a new IEx shell, freeing up the pried one.

When a process is pried, all code runs inside IEx and, as such, it is evaluated and cannot access private functions of the module being pried. Module functions still need to be accessed via Mod.fun(args).

Examples

Let’s suppose you want to investigate what is happening with some particular function. By invoking IEx.pry/1 from the function, IEx will allow you to access its binding (variables), verify its lexical information and access the process information. Let’s see an example:

import Enum, only: [map: 2]
require IEx

defmodule Adder do
  def add(a, b) do
    c = a + b
    IEx.pry
  end
end

When invoking Adder.add(1, 2), you will receive a message in your shell to pry the given environment. By allowing it, the shell will be reset and you gain access to all variables and the lexical scope from above:

pry(1)> map([a, b, c], &IO.inspect(&1))
1
2
3

Keep in mind that IEx.pry/1 runs in the caller process, blocking the caller during the evaluation cycle. The caller process can be freed by calling respawn, which starts a new IEx evaluation cycle, letting this one go:

pry(2)> respawn
true

Interactive Elixir - press Ctrl+C to exit (type h() ENTER for help)

Setting variables or importing modules in IEx does not affect the caller the environment (hence it is called pry).