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
Callback for IEx.pry/1
Returns true
if IEx was started
Gets the IEx width for printing
Macros
Pries into the process environment
Functions
Returns string
escaped using the specified color
.
ANSI escapes in string
are not processed in any way.
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 whenNode.alive?
returnsfalse
:alive_prompt
- used whenNode.alive?
returnstrue
The following values in the prompt string will be replaced appropriately:
%counter
- the index of the history%prefix
- a prefix given byIEx.Server
%node
- the name of the local node
Macros
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
).