Skip to content

Commit 865608b

Browse files
committed
Add initial support for .iex files
1 parent 26640e3 commit 865608b

File tree

3 files changed

+92
-20
lines changed

3 files changed

+92
-20
lines changed

lib/iex/lib/iex.ex

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -90,6 +90,8 @@ defmodule IEx do
9090
9191
"""
9292

93+
alias IEx.Util
94+
9395
@doc """
9496
Registers a function to be invoked after IEx process is spawned.
9597
"""
@@ -150,6 +152,7 @@ defmodule IEx do
150152
151153
set_expand_fun()
152154
run_after_spawn()
155+
config = load_dot_iex(config)
153156
IEx.Server.start(config)
154157
end
155158
end
@@ -201,4 +204,56 @@ defmodule IEx do
201204
defp run_after_spawn do
202205
lc fun inlist Enum.reverse(after_spawn), do: fun.()
203206
end
207+
208+
# Locates and loads an .iex file from one of predefined locations
209+
#
210+
# Sample contents of a local .iex file:
211+
#
212+
# IEx.source "~/.iex" # source another .iex file
213+
# IO.puts "hello world" # print something before the shell starts
214+
# value = 13 # bind a variable that'll be accessible in the shell
215+
#
216+
# Running the shell then results in
217+
#
218+
# $ iex
219+
# Erlang R15B03 (erts-5.9.3.1) ...
220+
#
221+
# hello world
222+
# Interactive Elixir (0.8.3.dev) - press Ctrl+C to exit (type h() ENTER for help)
223+
# iex(1)> value
224+
# 13
225+
#
226+
defp load_dot_iex(config) do
227+
path = Enum.find [".iex", "~/.iex"], File.regular?(&1)
228+
if nil?(path) do
229+
config
230+
else
231+
try do
232+
code = File.read!(path)
233+
234+
# Evaluate the contents in the same environment IEx.Server will run in
235+
{ _result, binding, scope } = :elixir.eval(:unicode.characters_to_list(code), config.binding, 0, config.scope)
236+
config.binding(binding).scope(scope)
237+
rescue
238+
exception ->
239+
Util.print_exception(exception)
240+
:erlang.halt()
241+
catch
242+
kind, error ->
243+
Util.print_error(kind, error)
244+
:erlang.halt()
245+
end
246+
end
247+
end
248+
249+
@doc """
250+
Convenience function for use in .iex files. Converts `path` to an absolute
251+
path (also expanding ~ if present) and requires the file at resulting path.
252+
253+
In case of an error, prints exception info to stdout and terminates the shell.
254+
"""
255+
def source(path) do
256+
p = Path.expand(path)
257+
Code.require_file(p)
258+
end
204259
end

lib/iex/lib/iex/server.ex

Lines changed: 4 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
defmodule IEx.Server do
22
@moduledoc false
33

4+
alias IEx.Util
5+
46
@doc """
57
Eval loop for an IEx session. Its responsibilities include:
68
@@ -26,15 +28,11 @@ defmodule IEx.Server do
2628
eval(code, line, counter, config)
2729
rescue
2830
exception ->
29-
print_stacktrace System.stacktrace, fn ->
30-
"** (#{inspect exception.__record__(:name)}) #{exception.message}"
31-
end
31+
Util.print_exception(exception)
3232
config.cache('')
3333
catch
3434
kind, error ->
35-
print_stacktrace System.stacktrace, fn ->
36-
"** (#{kind}) #{inspect(error)}"
37-
end
35+
Util.print_error(kind, error)
3836
config.cache('')
3937
end
4038

@@ -90,16 +88,6 @@ defmodule IEx.Server do
9088
end
9189
end
9290

93-
defp print_stacktrace(trace, callback) do
94-
try do
95-
io_error callback.()
96-
io_error Exception.format_stacktrace(trace)
97-
catch
98-
_, _ ->
99-
io_error "** (IEx.Error) error when printing exception message and stacktrace"
100-
end
101-
end
102-
10391
defp update_history(config) do
10492
current = Process.get :iex_history
10593
Process.put :iex_history, [config|current]
@@ -125,10 +113,6 @@ defmodule IEx.Server do
125113
IO.puts :stdio, IO.ANSI.escape("%{yellow}#{inspect(result, IEx.inspect_opts)}")
126114
end
127115

128-
defp io_error(result) do
129-
IO.puts :stdio, result
130-
end
131-
132116
defp remote_prefix do
133117
if node == node(:erlang.group_leader), do: "iex", else: "rem"
134118
end

lib/iex/lib/iex/util.ex

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,33 @@
1+
defmodule IEx.Util do
2+
@moduledoc false
3+
4+
# Private functions used by several IEx.* modules.
5+
6+
@doc false
7+
def print_exception(exception) do
8+
print_stacktrace System.stacktrace, fn ->
9+
"** (#{inspect exception.__record__(:name)}) #{exception.message}"
10+
end
11+
end
12+
13+
@doc false
14+
def print_error(kind, reason) do
15+
print_stacktrace System.stacktrace, fn ->
16+
"** (#{kind}) #{inspect(reason)}"
17+
end
18+
end
19+
20+
defp print_stacktrace(trace, callback) do
21+
try do
22+
io_error callback.()
23+
io_error Exception.format_stacktrace(trace)
24+
catch
25+
_, _ ->
26+
io_error "** (IEx.Error) error when printing exception message and stacktrace"
27+
end
28+
end
29+
30+
defp io_error(result) do
31+
IO.puts :stdio, result
32+
end
33+
end

0 commit comments

Comments
 (0)