Customizing IEx: Personalizing Your Elixir Shell Environment
João Paulo Abreu

João Paulo Abreu @abreujp

About: 👨‍💻 Web Developer | Elixir, Phoenix, LiveView | Functional programming enthusiast | Always learning and sharing knowledge.

Location:
Brazil
Joined:
Apr 11, 2024

Customizing IEx: Personalizing Your Elixir Shell Environment

Publish Date: Dec 8 '24
10 5

In this article, we'll explore how to customize the Interactive Elixir (IEx) shell to enhance your development workflow. We'll cover everything from basic configuration to advanced customization techniques that can make your IEx sessions more productive and enjoyable.

Note: The examples in this article use Elixir 1.17.3. While most features should work across different versions, some functionality might vary.

Table of Contents

Understanding IEx Configuration

IEx configuration can be set up in multiple ways:

  • Through the .iex.exs file in your home directory (~/.iex.exs)
  • Through a project-specific .iex.exs file
  • Via runtime configuration in your IEx session

The configuration files are loaded in the following order:

  1. User's home directory configuration (~/.iex.exs)
  2. Current directory configuration (./.iex.exs)
  3. Project-specific configuration (if present)

Basic Shell Customization

Let's start with basic shell configurations. Create a .iex.exs file in your home directory:

# Configure IEx basic settings
IEx.configure(
  history_size: 100,
  inspect: [
    limit: 5_000,
    pretty: true,
    width: 80
  ],
  colors: [enabled: true]
)

# Common imports that you use frequently
import Enum, only: [map: 2, reduce: 3]
import String, only: [upcase: 1, downcase: 1]

# Default aliases
alias MyApp.Repo
alias MyApp.User
Enter fullscreen mode Exit fullscreen mode

You can verify if these configurations are working correctly by running the following tests in your IEx session:

# Test history_size configuration
iex(1)> IEx.configuration()[:history_size]
100  # Should return 100

# Test inspect configurations
iex(2)> list = Enum.to_list(1..10_000)
iex(3)> IO.inspect(list, width: 30)  # Compare with your width: 80 setting

# Test Enum imports
iex(4)> map([1, 2, 3], fn x -> x * 2 end)  # Should work without Enum.
[2, 4, 6]
iex(5)> reduce([1, 2, 3], 0, fn x, acc -> x + acc end)
6

# Test String imports
iex(6)> upcase("hello")  # Should work without String.
"HELLO"
iex(7)> downcase("WORLD")
"world"

# Test if colors are enabled
iex(8)> IO.ANSI.enabled?()
true

# Test aliases (will show error if modules don't exist, confirming alias setup)
iex(9)> Repo  # Should show MyApp.Repo module or error if not exists
iex(10)> User # Should show MyApp.User module or error if not exists

# Show complete current configuration
iex(11)> IEx.configuration()
# Displays all current IEx configurations
Enter fullscreen mode Exit fullscreen mode

Configuring the IEx Prompt

Customize your prompt to make it more informative and visually appealing:

# Custom prompt configuration
IEx.configure(
  default_prompt:
    "#{IO.ANSI.green}%prefix#{IO.ANSI.reset}" <>
    "(#{IO.ANSI.cyan}%counter#{IO.ANSI.reset}) >",
  alive_prompt:
    "#{IO.ANSI.green}%prefix#{IO.ANSI.reset}" <>
    "(#{IO.ANSI.cyan}%node#{IO.ANSI.reset}) " <>
    "(#{IO.ANSI.cyan}%counter#{IO.ANSI.reset}) >"
)

# Available prompt variables:
# %counter - command counter
# %prefix  - iex
# %node    - node name (when running distributed)
Enter fullscreen mode Exit fullscreen mode

Creating Custom Helpers

Custom helpers can significantly improve your workflow. Here are some useful examples:

# ~/.iex.exs

defmodule IExHelpers do
  def reload! do
    Mix.Task.reenable("compile.elixir")
    Application.stop(Mix.Project.config()[:app])
    Mix.Task.run("compile.elixir")
    Application.start(Mix.Project.config()[:app])
  end

  def list_app_modules(app) do
    case :application.get_key(app, :modules) do
      {:ok, modules} -> 
        modules 
        |> Enum.sort() 
        |> IO.inspect(pretty: true)
      :undefined -> 
        IO.puts "Application #{app} not found or has no modules"
    end
  end
end

import IExHelpers
Enter fullscreen mode Exit fullscreen mode

You can use these functions in IEx like this:

iex> reload!  # Recompiles and restarts your application for code changes
iex> list_app_modules(:phoenix)  # Lists all available modules in the Phoenix application
Enter fullscreen mode Exit fullscreen mode

Setting Up .iex.exs

Here's a complete example of a .iex.exs configuration file:

# ~/.iex.exs
# Configure IEx basic settings

# Common imports that you use frequently
import Enum, only: [map: 2, reduce: 3]
import String, only: [upcase: 1, downcase: 1]

# Set up aliases
alias MyApp.Repo
alias MyApp.User

# Configure shell appearance
Application.put_env(:elixir, :ansi_enabled, true)

IEx.configure(
  history_size: 100,
  inspect: [
    limit: 5_000,
    pretty: true,
    width: 80
  ],
  colors: [
    syntax_colors: [
      number: :yellow,
      atom: :cyan,
      string: :green,
      boolean: :red,
      nil: :red
    ],
    eval_result: [:green, :bright],
    eval_error: [:red, :bright],
    eval_info: [:blue, :bright]
  ],
  default_prompt:
    "#{IO.ANSI.green()}%prefix#{IO.ANSI.reset()}" <>
      "(#{IO.ANSI.cyan()}%counter#{IO.ANSI.reset()}) >"
)

defmodule IExHelpers do
  def reload! do
    Mix.Task.reenable("compile.elixir")
    Application.stop(Mix.Project.config()[:app])
    Mix.Task.run("compile.elixir")
    Application.start(Mix.Project.config()[:app])
  end

  def list_app_modules(app) do
     case :application.get_key(app, :modules) do
       {:ok, modules} -> 
         modules 
         |> Enum.sort() 
         |> IO.inspect(pretty: true)
       :undefined -> 
         IO.puts("Application #{app} not found or has no modules")
     end
  end
end

# Import helper functions into IEx session scope
import IExHelpers
Enter fullscreen mode Exit fullscreen mode

Color Schemes and Styling

IEx supports ANSI colors for various elements. Here's how to configure them:

# Color configuration
IEx.configure(
  colors: [
    enabled: true,
    syntax_colors: [
      number: :yellow,
      atom: :cyan,
      string: :green,
      boolean: :red,
      nil: :red,
    ],
    ls_directory: :cyan,
    ls_device: :yellow,
    doc_code: :green,
    doc_inline_code: :magenta,
    doc_headings: [:cyan, :underline],
    doc_title: [:cyan, :bright, :underline],
  ]
)
Enter fullscreen mode Exit fullscreen mode

Best Practices

  1. Organization

    • Keep your .iex.exs file organized and well-commented
    • Group related configurations together
    • Document custom helpers
  2. Project-Specific Configuration

    • Use project-level .iex.exs for project-specific settings
    • Keep general configurations in your home directory's .iex.exs
  3. Performance

    • Avoid loading unnecessary modules or making expensive computations
    • Use lazy loading when possible
    • Keep helper functions simple and focused
  4. Maintenance

    • Regularly review and update your configurations
    • Remove unused helpers and aliases
    • Keep configurations in version control

Conclusion

Customizing IEx can significantly improve your Elixir development experience. By properly configuring your shell environment, you can work more efficiently and effectively. Remember that the best configuration is one that suits your specific needs and workflow.

Next Steps

In the upcoming articles, we'll explore:

  • Numbers in Elixir
  • Integer, floats, and mathematical operations

Comments 5 total

  • Paweł Świątkowski
    Paweł ŚwiątkowskiDec 9, 2024

    Thanks! This was a great inspiration to tune my iex.exs further.

  • Luiz Cezer
    Luiz CezerDec 10, 2024

    Thanks for sharing, very helpful!

  • Alex Sinelnikov
    Alex SinelnikovDec 12, 2024

    Will my global ~/.iex.exs gets merged with project specific iex.exs?

    • João Paulo Abreu
      João Paulo AbreuDec 12, 2024

      Yes, they get merged in sequence: global config loads first, then project-specific one on top of it.

  • Muzhawir Amri
    Muzhawir AmriDec 26, 2024

    Thank you! I didn't know that we can customize IEx

Add comment