1defmodule Alchemist.Helpers.CaptureIO do
2
3  def capture_io(fun) do
4    do_capture_io(:standard_io, [], fun)
5  end
6
7  defp do_capture_io(:standard_io, options, fun) do
8    prompt_config = Keyword.get(options, :capture_prompt, true)
9    input = Keyword.get(options, :input, "")
10
11    original_gl = Process.group_leader()
12    {:ok, capture_gl} = StringIO.open(input, capture_prompt: prompt_config)
13    try do
14      Process.group_leader(self(), capture_gl)
15      do_capture_io(capture_gl, fun)
16    after
17      Process.group_leader(self(), original_gl)
18    end
19  end
20
21  def do_capture_io(string_io, fun) do
22    try do
23       _ = fun.()
24      :ok
25    catch
26      kind, reason ->
27        stack = System.stacktrace()
28        _ = StringIO.close(string_io)
29        :erlang.raise(kind, reason, stack)
30    else
31      :ok ->
32        {:ok, output} = StringIO.close(string_io)
33        elem(output, 1)
34    end
35  end
36end
37