Add Inspect.List.printable?/1 back

Add Inspect.List.printable?/1 back

import Kernel, except: [inspect: 1]
import Inspect.Algebra

defprotocol Inspect do
  @moduledoc """
  The `Inspect` protocol is responsible for converting any Elixir
  data structure into an algebra document. This document is then
  formatted, either in pretty printing format or a regular one.

  The `inspect/2` function receives the entity to be inspected
  followed by the inspecting options, represented by the struct
  `Inspect.Opts`.

  Inspection is done using the functions available in `Inspect.Algebra`.

  ## Examples

  Many times, inspecting a structure can be implemented in function
  of existing entities. For example, here is `MapSet`'s `inspect`
  implementation:

      defimpl Inspect, for: MapSet do
        import Inspect.Algebra

        def inspect(dict, opts) do
          concat ["#MapSet<", to_doc(MapSet.to_list(dict), opts), ">"]
        end
      end

  The `concat/1` function comes from `Inspect.Algebra` and it
  concatenates algebra documents together. In the example above,
  it is concatenating the string `"MapSet<"` (all strings are
  valid algebra documents that keep their formatting when pretty
  printed), the document returned by `Inspect.Algebra.to_doc/2` and the
  other string `">"`.

  Since regular strings are valid entities in an algebra document,
  an implementation of inspect may simply return a string,
  although that will devoid it of any pretty-printing.

  ## Error handling

  In case there is an error while your structure is being inspected,
  Elixir will raise an `ArgumentError` error and will automatically fall back
  to a raw representation for printing the structure.

  You can however access the underlying error by invoking the Inspect
  implementation directly. For example, to test Inspect.MapSet above,
  you can invoke it as:

      Inspect.MapSet.inspect(MapSet.new, %Inspect.Opts{})

  """

  # Handle structs in Any
  @fallback_to_any true

  def inspect(term, opts)
end

defimpl Inspect, for: Atom do
  require Macro

  def inspect(atom, opts) do
    color(inspect(atom), color_key(atom), opts)
  end

  defp color_key(atom) when is_boolean(atom), do: :boolean
  defp color_key(nil), do: :nil
  defp color_key(_), do: :atom

  def inspect(atom) when is_nil(atom) or is_boolean(atom) do
    Atom.to_string(atom)
  end

  def inspect(atom) do
    binary = Atom.to_string(atom)

    case Macro.classify_identifier(binary) do
      :alias ->
        case binary do
          binary when binary in ["Elixir", "Elixir.Elixir"] ->
            binary
          "Elixir.Elixir." <> _rest ->
            binary
          "Elixir." <> rest ->
            rest
        end
      type when type in [:callable, :not_callable] ->
        ":" <> binary
      :other ->
        {escaped, _} = Inspect.BitString.escape(binary, ?")
        IO.iodata_to_binary [?:, ?", escaped, ?"]
    end
  end
end

defimpl Inspect, for: BitString do
  def inspect(term, opts) when is_binary(term) do
    %Inspect.Opts{binaries: bins, base: base, printable_limit: printable_limit} = opts

    if base == :decimal and
       (bins == :as_strings or (bins == :infer and String.printable?(term, printable_limit))) do
      inspected =
        case escape(term, ?", printable_limit) do
          {escaped, ""} -> [?", escaped, ?"]
          {escaped, _} -> [?", escaped, ?", " <> ..."]
        end
      color(IO.iodata_to_binary(inspected), :string, opts)
    else
      inspect_bitstring(term, opts)
    end
  end

  def inspect(term, opts) do
    inspect_bitstring(term, opts)
  end

  ## Escaping

  @doc false
  def escape(other, char) do
    escape(other, char, :infinity, [])
  end

  @doc false
  def escape(other, char, count) do
    escape(other, char, count, [])
  end

  defp escape(<<_, _::binary>> = binary, _char, 0, acc) do
    {acc, binary}
  end
  defp escape(<<char, t::binary>>, char, count, acc) do
    escape(t, char, decrement(count), [acc | [?\\, char]])
  end
  defp escape(<<?#, ?{, t::binary>>, char, count, acc) do
    escape(t, char, decrement(count), [acc | '\\\#{'])
  end
  defp escape(<<?\a, t::binary>>, char, count, acc) do
    escape(t, char, decrement(count), [acc | '\\a'])
  end
  defp escape(<<?\b, t::binary>>, char, count, acc) do
    escape(t, char, decrement(count), [acc | '\\b'])
  end
  defp escape(<<?\d, t::binary>>, char, count, acc) do
    escape(t, char, decrement(count), [acc | '\\d'])
  end
  defp escape(<<?\e, t::binary>>, char, count, acc) do
    escape(t, char, decrement(count), [acc | '\\e'])
  end
  defp escape(<<?\f, t::binary>>, char, count, acc) do
    escape(t, char, decrement(count), [acc | '\\f'])
  end
  defp escape(<<?\n, t::binary>>, char, count, acc) do
    escape(t, char, decrement(count), [acc | '\\n'])
  end
  defp escape(<<?\r, t::binary>>, char, count, acc) do
    escape(t, char, decrement(count), [acc | '\\r'])
  end
  defp escape(<<?\\, t::binary>>, char, count, acc) do
    escape(t, char, decrement(count), [acc | '\\\\'])
  end
  defp escape(<<?\t, t::binary>>, char, count, acc) do
    escape(t, char, decrement(count), [acc | '\\t'])
  end
  defp escape(<<?\v, t::binary>>, char, count, acc) do
    escape(t, char, decrement(count), [acc | '\\v'])
  end
  defp escape(<<h::utf8, t::binary>>, char, count, acc)
       when h in 0x20..0x7E
       when h in 0xA0..0xD7FF
       when h in 0xE000..0xFFFD
       when h in 0x10000..0x10FFFF do
    escape(t, char, decrement(count), [acc | <<h::utf8>>])
  end
  defp escape(<<h, t::binary>>, char, count, acc) do
    escape(t, char, decrement(count), [acc | escape_char(h)])
  end
  defp escape(<<>>, _char, _count, acc) do
    {acc, <<>>}
  end

  @doc false
  # Also used by Regex
  def escape_char(0) do
    '\\0'
  end

  def escape_char(char) when char < 0x100 do
    <<a::4, b::4>> = <<char::8>>
    ['\\x', to_hex(a), to_hex(b)]
  end

  def escape_char(char) when char < 0x10000 do
    <<a::4, b::4, c::4, d::4>> = <<char::16>>
    ['\\x{', to_hex(a), to_hex(b), to_hex(c), to_hex(d), ?}]
  end

  def escape_char(char) when char < 0x1000000 do
    <<a::4, b::4, c::4, d::4, e::4, f::4>> = <<char::24>>
    ['\\x{', to_hex(a), to_hex(b), to_hex(c),
             to_hex(d), to_hex(e), to_hex(f), ?}]
  end

  defp to_hex(c) when c in 0..9, do: ?0 + c
  defp to_hex(c) when c in 10..15, do: ?A + c - 10

  ## Bitstrings

  defp inspect_bitstring("", opts) do
    color("<<>>", :binary, opts)
  end

  defp inspect_bitstring(bitstring, opts) do
    left = color("<<", :binary, opts)
    right = color(">>", :binary, opts)
    nest surround(left, each_bit(bitstring, opts.limit, opts), right), 1
  end

  defp each_bit(_, 0, _) do
    "..."
  end

  defp each_bit(<<>>, _counter, _opts) do
    :doc_nil
  end

  defp each_bit(<<h::8>>, _counter, opts) do
    Inspect.Integer.inspect(h, opts)
  end

  defp each_bit(<<h, t::bitstring>>, counter, opts) do
    glue(concat(Inspect.Integer.inspect(h, opts), ","),
         each_bit(t, decrement(counter), opts))
  end

  defp each_bit(bitstring, _counter, opts) do
    size = bit_size(bitstring)
    <<h::size(size)>> = bitstring
    Inspect.Integer.inspect(h, opts) <> "::size(" <> Integer.to_string(size) <> ")"
  end

  @compile {:inline, decrement: 1}
  defp decrement(:infinity), do: :infinity
  defp decrement(counter),   do: counter - 1
end

defimpl Inspect, for: List do
  def inspect([], opts) do
    color("[]", :list, opts)
  end

  # TODO: Remove :char_list and :as_char_lists handling in 2.0
  def inspect(term, opts) do
    %Inspect.Opts{charlists: lists, char_lists: lists_deprecated, printable_limit: printable_limit} = opts
    lists =
      if lists == :infer and lists_deprecated != :infer do
        case lists_deprecated do
          :as_char_lists ->
            IO.warn "the :char_lists inspect option and its :as_char_lists " <>
              "value are deprecated, use the :charlists option and its " <>
              ":as_charlists value instead"
            :as_charlists
          _ ->
            IO.warn "the :char_lists inspect option is deprecated, use :charlists instead"
            lists_deprecated
        end
      else
        lists
      end

    open = color("[", :list, opts)
    sep = color(",", :list, opts)
    close = color("]", :list, opts)

    cond do
      lists == :as_charlists or (lists == :infer and printable?(term, printable_limit)) ->
        inspected =
          case Inspect.BitString.escape(IO.chardata_to_string(term), ?', printable_limit) do
            {escaped, ""} -> [?', escaped, ?']
            {escaped, _} -> [?', escaped, ?', " ++ ..."]
          end
        IO.iodata_to_binary inspected
      keyword?(term) ->
        surround_many(open, term, close, opts, &keyword/2, sep)
      true ->
        surround_many(open, term, close, opts, &to_doc/2, sep)
    end
  end

  @doc false
  def keyword({key, value}, opts) do
    key = color(key_to_binary(key) <> ": ", :atom, opts)
    concat(key, to_doc(value, opts))
  end

  @doc false
  def keyword?([{key, _value} | rest]) when is_atom(key) do
    case Atom.to_charlist(key) do
      'Elixir.' ++ _ -> false
      _ -> keyword?(rest)
    end
  end

  def keyword?([]),     do: true
  def keyword?(_other), do: false

  @doc false
  def printable?(list), do: printable?(list, :infinity)

  @doc false
  def printable?(_, 0), do: true
  def printable?([char | rest], counter) when char in 32..126, do: printable?(rest, decrement(counter))
  def printable?([?\n | rest], counter), do: printable?(rest, decrement(counter))
  def printable?([?\r | rest], counter), do: printable?(rest, decrement(counter))
  def printable?([?\t | rest], counter), do: printable?(rest, decrement(counter))
  def printable?([?\v | rest], counter), do: printable?(rest, decrement(counter))
  def printable?([?\b | rest], counter), do: printable?(rest, decrement(counter))
  def printable?([?\f | rest], counter), do: printable?(rest, decrement(counter))
  def printable?([?\e | rest], counter), do: printable?(rest, decrement(counter))
  def printable?([?\a | rest], counter), do: printable?(rest, decrement(counter))
  def printable?([], counter), do: true
  def printable?(_, counter), do: false

  @compile {:inline, decrement: 1}
  defp decrement(:infinity), do: :infinity
  defp decrement(counter),   do: counter - 1

  ## Private

  defp key_to_binary(key) do
    case Inspect.Atom.inspect(key) do
      ":" <> right -> right
      other -> other
    end
  end
end

defimpl Inspect, for: Tuple do
  def inspect(tuple, opts) do
    open = color("{", :tuple, opts)
    sep = color(",", :tuple, opts)
    close = color("}", :tuple, opts)
    surround_many(open, Tuple.to_list(tuple), close, opts, &to_doc/2, sep)
  end
end

defimpl Inspect, for: Map do
  def inspect(map, opts) do
    nest inspect(map, "", opts), 1
  end

  def inspect(map, name, opts) do
    map = :maps.to_list(map)
    open = color("%" <> name <> "{", :map, opts)
    sep = color(",", :map, opts)
    close = color("}", :map, opts)
    surround_many(open, map, close, opts, traverse_fun(map), sep)
  end

  defp traverse_fun(list) do
    if Inspect.List.keyword?(list) do
      &Inspect.List.keyword/2
    else
      &to_map/2
    end
  end

  defp to_map({key, value}, opts) do
    concat(
      concat(to_doc(key, opts), " => "),
      to_doc(value, opts)
    )
  end
end

defimpl Inspect, for: Integer do
  def inspect(term, %Inspect.Opts{base: base} = opts) do
    inspected = Integer.to_string(term, base_to_value(base)) |> prepend_prefix(base)
    color(inspected, :number, opts)
  end

  defp base_to_value(base) do
    case base do
      :binary  -> 2
      :decimal -> 10
      :octal   -> 8
      :hex     -> 16
    end
  end

  defp prepend_prefix(value, :decimal), do: value
  defp prepend_prefix(value, base) do
    prefix = case base do
      :binary -> "0b"
      :octal  -> "0o"
      :hex    -> "0x"
    end
    prefix <> value
  end
end

defimpl Inspect, for: Float do
  def inspect(term, opts) do
    inspected = IO.iodata_to_binary(:io_lib_format.fwrite_g(term))
    color(inspected, :number, opts)
  end
end

defimpl Inspect, for: Regex do
  def inspect(regex, opts) do
    source = IO.iodata_to_binary(['~r/', escape(regex.source, ?/), ?/, regex.opts])
    color(source, :regex, opts)
  end

  defp escape(bin, term),
    do: escape(bin, [], term)

  defp escape(<<?\\, term>> <> rest, buf, term),
    do: escape(rest, [buf | [?\\, term]], term)

  defp escape(<<term>> <> rest, buf, term),
    do: escape(rest, [buf | [?\\, term]], term)

  # The list of characters is from 'String.printable?' implementation
  # minus characters treated specially by regex: \s, \d, \b, \e

  defp escape(<<?\n>> <> rest, buf, term),
    do: escape(rest, [buf | '\\n'], term)

  defp escape(<<?\r>> <> rest, buf, term),
    do: escape(rest, [buf | '\\r'], term)

  defp escape(<<?\t>> <> rest, buf, term),
    do: escape(rest, [buf | '\\t'], term)

  defp escape(<<?\v>> <> rest, buf, term),
    do: escape(rest, [buf | '\\v'], term)

  defp escape(<<?\f>> <> rest, buf, term),
    do: escape(rest, [buf | '\\f'], term)

  defp escape(<<?\a>> <> rest, buf, term),
    do: escape(rest, [buf | '\\a'], term)

  defp escape(<<char::utf8, rest::binary>>, buf, term)
       when char in 0x20..0x7E
       when char in 0xA0..0xD7FF
       when char in 0xE000..0xFFFD
       when char in 0x10000..0x10FFFF,
    do: escape(rest, [buf | <<char::utf8>>], term)

  defp escape(<<char, rest::binary>>, buf, term),
    do: escape(rest, [buf | Inspect.BitString.escape_char(char)], term)

  defp escape(<<>>, buf, _), do: buf
end

defimpl Inspect, for: Function do
  def inspect(function, _opts) do
    fun_info = :erlang.fun_info(function)
    mod = fun_info[:module]
    name = fun_info[:name]

    if fun_info[:type] == :external and fun_info[:env] == [] do
      "&#{Inspect.Atom.inspect(mod)}.#{escape_name(name)}/#{fun_info[:arity]}"
    else
      case Atom.to_charlist(mod) do
        'elixir_compiler_' ++ _ ->
          if function_exported?(mod, :__RELATIVE__, 0) do
            "#Function<#{uniq(fun_info)} in file:#{mod.__RELATIVE__}>"
          else
            default_inspect(mod, fun_info)
          end
        _ ->
          default_inspect(mod, fun_info)
      end
    end
  end

  def escape_name(name) when is_atom(name) do
    escape_name(Atom.to_string(name))
  end

  def escape_name(name) when is_binary(name) do
    case Macro.classify_identifier(name) do
      :callable ->
        name
      type when type in [:not_callable, :alias] ->
        "\"" <> name <> "\""
      :other ->
        {escaped, _} = Inspect.BitString.escape(name, ?")
        IO.iodata_to_binary [?", escaped, ?"]
    end
  end

  # Example of this format: -func/arity-fun-count-
  def extract_anonymous_fun_parent("-" <> rest) do
    # We use :re instead of String.split/3 because we want to keep the "/"s and
    # "-"s (this is what the "(" and ")" in the regex do). We want to keep them
    # because we want to rebuild part of this split list (the function name)
    # later on.
    result =
      rest
      |> :re.split("([/-])")
      |> Enum.reject(&(&1 == ""))
      |> Enum.reverse()

    case result do
      ["-", _count, "-", _inner, "-", arity, "/" | reversed_function] ->
        {Enum.join(Enum.reverse(reversed_function)), arity}
      _other ->
        :error
    end
  end

  def extract_anonymous_fun_parent(other) when is_binary(other), do: :error

  defp default_inspect(mod, fun_info) do
    "#Function<#{uniq(fun_info)}/#{fun_info[:arity]} in " <>
      "#{Inspect.Atom.inspect(mod)}#{extract_name(fun_info[:name])}>"
  end

  defp extract_name([]) do
    ""
  end

  defp extract_name(name) do
    name = Atom.to_string(name)
    case extract_anonymous_fun_parent(name) do
      {name, arity} ->
        "." <> escape_name(name) <> "/" <> arity
      :error ->
        "." <> escape_name(name)
    end
  end

  defp uniq(fun_info) do
    Integer.to_string(fun_info[:new_index]) <> "." <>
      Integer.to_string(fun_info[:uniq])
  end
end

defimpl Inspect, for: PID do
  def inspect(pid, _opts) do
    "#PID" <> IO.iodata_to_binary(:erlang.pid_to_list(pid))
  end
end

defimpl Inspect, for: Port do
  def inspect(port, _opts) do
    IO.iodata_to_binary(:erlang.port_to_list(port))
  end
end

defimpl Inspect, for: Reference do
  def inspect(ref, _opts) do
    '#Ref' ++ rest = :erlang.ref_to_list(ref)
    "#Reference" <> IO.iodata_to_binary(rest)
  end
end

defimpl Inspect, for: Any do
  def inspect(%{__struct__: struct} = map, opts) do
    try do
      struct.__struct__
    rescue
      _ -> Inspect.Map.inspect(map, opts)
    else
      dunder ->
        if :maps.keys(dunder) == :maps.keys(map) do
          pruned = :maps.remove(:__exception__, :maps.remove(:__struct__, map))
          colorless_opts = %{opts | syntax_colors: []}
          Inspect.Map.inspect(pruned, Inspect.Atom.inspect(struct, colorless_opts), opts)
        else
          Inspect.Map.inspect(map, opts)
        end
    end
  end
end

import Kernel, except: [inspect: 1]
import Inspect.Algebra

defprotocol Inspect do
  @moduledoc """
  The `Inspect` protocol is responsible for converting any Elixir
  data structure into an algebra document. This document is then
  formatted, either in pretty printing format or a regular one.

  The `inspect/2` function receives the entity to be inspected
  followed by the inspecting options, represented by the struct
  `Inspect.Opts`.

  Inspection is done using the functions available in `Inspect.Algebra`.

  ## Examples

  Many times, inspecting a structure can be implemented in function
  of existing entities. For example, here is `MapSet`'s `inspect`
  implementation:

      defimpl Inspect, for: MapSet do
        import Inspect.Algebra

        def inspect(dict, opts) do
          concat ["#MapSet<", to_doc(MapSet.to_list(dict), opts), ">"]
        end
      end

  The `concat/1` function comes from `Inspect.Algebra` and it
  concatenates algebra documents together. In the example above,
  it is concatenating the string `"MapSet<"` (all strings are
  valid algebra documents that keep their formatting when pretty
  printed), the document returned by `Inspect.Algebra.to_doc/2` and the
  other string `">"`.

  Since regular strings are valid entities in an algebra document,
  an implementation of inspect may simply return a string,
  although that will devoid it of any pretty-printing.

  ## Error handling

  In case there is an error while your structure is being inspected,
  Elixir will raise an `ArgumentError` error and will automatically fall back
  to a raw representation for printing the structure.

  You can however access the underlying error by invoking the Inspect
  implementation directly. For example, to test Inspect.MapSet above,
  you can invoke it as:

      Inspect.MapSet.inspect(MapSet.new, %Inspect.Opts{})

  """

  # Handle structs in Any
  @fallback_to_any true

  def inspect(term, opts)
end

defimpl Inspect, for: Atom do
  require Macro

  def inspect(atom, opts) do
    color(inspect(atom), color_key(atom), opts)
  end

  defp color_key(atom) when is_boolean(atom), do: :boolean
  defp color_key(nil), do: :nil
  defp color_key(_), do: :atom

  def inspect(atom) when is_nil(atom) or is_boolean(atom) do
    Atom.to_string(atom)
  end

  def inspect(atom) do
    binary = Atom.to_string(atom)

    case Macro.classify_identifier(binary) do
      :alias ->
        case binary do
          binary when binary in ["Elixir", "Elixir.Elixir"] ->
            binary
          "Elixir.Elixir." <> _rest ->
            binary
          "Elixir." <> rest ->
            rest
        end
      type when type in [:callable, :not_callable] ->
        ":" <> binary
      :other ->
        {escaped, _} = Inspect.BitString.escape(binary, ?")
        IO.iodata_to_binary [?:, ?", escaped, ?"]
    end
  end
end

defimpl Inspect, for: BitString do
  def inspect(term, opts) when is_binary(term) do
    %Inspect.Opts{binaries: bins, base: base, printable_limit: printable_limit} = opts

    if base == :decimal and
       (bins == :as_strings or (bins == :infer and String.printable?(term, printable_limit))) do
      inspected =
        case escape(term, ?", printable_limit) do
          {escaped, ""} -> [?", escaped, ?"]
          {escaped, _} -> [?", escaped, ?", " <> ..."]
        end
      color(IO.iodata_to_binary(inspected), :string, opts)
    else
      inspect_bitstring(term, opts)
    end
  end

  def inspect(term, opts) do
    inspect_bitstring(term, opts)
  end

  ## Escaping

  @doc false
  def escape(other, char) do
    escape(other, char, :infinity, [])
  end

  @doc false
  def escape(other, char, count) do
    escape(other, char, count, [])
  end

  defp escape(<<_, _::binary>> = binary, _char, 0, acc) do
    {acc, binary}
  end
  defp escape(<<char, t::binary>>, char, count, acc) do
    escape(t, char, decrement(count), [acc | [?\\, char]])
  end
  defp escape(<<?#, ?{, t::binary>>, char, count, acc) do
    escape(t, char, decrement(count), [acc | '\\\#{'])
  end
  defp escape(<<?\a, t::binary>>, char, count, acc) do
    escape(t, char, decrement(count), [acc | '\\a'])
  end
  defp escape(<<?\b, t::binary>>, char, count, acc) do
    escape(t, char, decrement(count), [acc | '\\b'])
  end
  defp escape(<<?\d, t::binary>>, char, count, acc) do
    escape(t, char, decrement(count), [acc | '\\d'])
  end
  defp escape(<<?\e, t::binary>>, char, count, acc) do
    escape(t, char, decrement(count), [acc | '\\e'])
  end
  defp escape(<<?\f, t::binary>>, char, count, acc) do
    escape(t, char, decrement(count), [acc | '\\f'])
  end
  defp escape(<<?\n, t::binary>>, char, count, acc) do
    escape(t, char, decrement(count), [acc | '\\n'])
  end
  defp escape(<<?\r, t::binary>>, char, count, acc) do
    escape(t, char, decrement(count), [acc | '\\r'])
  end
  defp escape(<<?\\, t::binary>>, char, count, acc) do
    escape(t, char, decrement(count), [acc | '\\\\'])
  end
  defp escape(<<?\t, t::binary>>, char, count, acc) do
    escape(t, char, decrement(count), [acc | '\\t'])
  end
  defp escape(<<?\v, t::binary>>, char, count, acc) do
    escape(t, char, decrement(count), [acc | '\\v'])
  end
  defp escape(<<h::utf8, t::binary>>, char, count, acc)
       when h in 0x20..0x7E
       when h in 0xA0..0xD7FF
       when h in 0xE000..0xFFFD
       when h in 0x10000..0x10FFFF do
    escape(t, char, decrement(count), [acc | <<h::utf8>>])
  end
  defp escape(<<h, t::binary>>, char, count, acc) do
    escape(t, char, decrement(count), [acc | escape_char(h)])
  end
  defp escape(<<>>, _char, _count, acc) do
    {acc, <<>>}
  end

  @doc false
  # Also used by Regex
  def escape_char(0) do
    '\\0'
  end

  def escape_char(char) when char < 0x100 do
    <<a::4, b::4>> = <<char::8>>
    ['\\x', to_hex(a), to_hex(b)]
  end

  def escape_char(char) when char < 0x10000 do
    <<a::4, b::4, c::4, d::4>> = <<char::16>>
    ['\\x{', to_hex(a), to_hex(b), to_hex(c), to_hex(d), ?}]
  end

  def escape_char(char) when char < 0x1000000 do
    <<a::4, b::4, c::4, d::4, e::4, f::4>> = <<char::24>>
    ['\\x{', to_hex(a), to_hex(b), to_hex(c),
             to_hex(d), to_hex(e), to_hex(f), ?}]
  end

  defp to_hex(c) when c in 0..9, do: ?0 + c
  defp to_hex(c) when c in 10..15, do: ?A + c - 10

  ## Bitstrings

  defp inspect_bitstring("", opts) do
    color("<<>>", :binary, opts)
  end

  defp inspect_bitstring(bitstring, opts) do
    left = color("<<", :binary, opts)
    right = color(">>", :binary, opts)
    nest surround(left, each_bit(bitstring, opts.limit, opts), right), 1
  end

  defp each_bit(_, 0, _) do
    "..."
  end

  defp each_bit(<<>>, _counter, _opts) do
    :doc_nil
  end

  defp each_bit(<<h::8>>, _counter, opts) do
    Inspect.Integer.inspect(h, opts)
  end

  defp each_bit(<<h, t::bitstring>>, counter, opts) do
    glue(concat(Inspect.Integer.inspect(h, opts), ","),
         each_bit(t, decrement(counter), opts))
  end

  defp each_bit(bitstring, _counter, opts) do
    size = bit_size(bitstring)
    <<h::size(size)>> = bitstring
    Inspect.Integer.inspect(h, opts) <> "::size(" <> Integer.to_string(size) <> ")"
  end

  @compile {:inline, decrement: 1}
  defp decrement(:infinity), do: :infinity
  defp decrement(counter),   do: counter - 1
end

defimpl Inspect, for: List do
  def inspect([], opts) do
    color("[]", :list, opts)
  end

  # TODO: Remove :char_list and :as_char_lists handling in 2.0
  def inspect(term, opts) do
    %Inspect.Opts{charlists: lists, char_lists: lists_deprecated, printable_limit: printable_limit} = opts
    lists =
      if lists == :infer and lists_deprecated != :infer do
        case lists_deprecated do
          :as_char_lists ->
            IO.warn "the :char_lists inspect option and its :as_char_lists " <>
              "value are deprecated, use the :charlists option and its " <>
              ":as_charlists value instead"
            :as_charlists
          _ ->
            IO.warn "the :char_lists inspect option is deprecated, use :charlists instead"
            lists_deprecated
        end
      else
        lists
      end

    open = color("[", :list, opts)
    sep = color(",", :list, opts)
    close = color("]", :list, opts)

    cond do
      lists == :as_charlists or (lists == :infer and printable?(term, printable_limit)) ->
        inspected =
          case Inspect.BitString.escape(IO.chardata_to_string(term), ?', printable_limit) do
            {escaped, ""} -> [?', escaped, ?']
            {escaped, _} -> [?', escaped, ?', " ++ ..."]
          end
        IO.iodata_to_binary inspected
      keyword?(term) ->
        surround_many(open, term, close, opts, &keyword/2, sep)
      true ->
        surround_many(open, term, close, opts, &to_doc/2, sep)
    end
  end

  @doc false
  def keyword({key, value}, opts) do
    key = color(key_to_binary(key) <> ": ", :atom, opts)
    concat(key, to_doc(value, opts))
  end

  @doc false
  def keyword?([{key, _value} | rest]) when is_atom(key) do
    case Atom.to_charlist(key) do
      'Elixir.' ++ _ -> false
      _ -> keyword?(rest)
    end
  end

  def keyword?([]),     do: true
  def keyword?(_other), do: false

  @doc false
  def printable?(_, 0), do: true
  def printable?([char | rest], counter) when char in 32..126, do: printable?(rest, decrement(counter))
  def printable?([?\n | rest], counter), do: printable?(rest, decrement(counter))
  def printable?([?\r | rest], counter), do: printable?(rest, decrement(counter))
  def printable?([?\t | rest], counter), do: printable?(rest, decrement(counter))
  def printable?([?\v | rest], counter), do: printable?(rest, decrement(counter))
  def printable?([?\b | rest], counter), do: printable?(rest, decrement(counter))
  def printable?([?\f | rest], counter), do: printable?(rest, decrement(counter))
  def printable?([?\e | rest], counter), do: printable?(rest, decrement(counter))
  def printable?([?\a | rest], counter), do: printable?(rest, decrement(counter))
  def printable?([], counter), do: true
  def printable?(_, counter), do: false

  @compile {:inline, decrement: 1}
  defp decrement(:infinity), do: :infinity
  defp decrement(counter),   do: counter - 1

  ## Private

  defp key_to_binary(key) do
    case Inspect.Atom.inspect(key) do
      ":" <> right -> right
      other -> other
    end
  end
end

defimpl Inspect, for: Tuple do
  def inspect(tuple, opts) do
    open = color("{", :tuple, opts)
    sep = color(",", :tuple, opts)
    close = color("}", :tuple, opts)
    surround_many(open, Tuple.to_list(tuple), close, opts, &to_doc/2, sep)
  end
end

defimpl Inspect, for: Map do
  def inspect(map, opts) do
    nest inspect(map, "", opts), 1
  end

  def inspect(map, name, opts) do
    map = :maps.to_list(map)
    open = color("%" <> name <> "{", :map, opts)
    sep = color(",", :map, opts)
    close = color("}", :map, opts)
    surround_many(open, map, close, opts, traverse_fun(map), sep)
  end

  defp traverse_fun(list) do
    if Inspect.List.keyword?(list) do
      &Inspect.List.keyword/2
    else
      &to_map/2
    end
  end

  defp to_map({key, value}, opts) do
    concat(
      concat(to_doc(key, opts), " => "),
      to_doc(value, opts)
    )
  end
end

defimpl Inspect, for: Integer do
  def inspect(term, %Inspect.Opts{base: base} = opts) do
    inspected = Integer.to_string(term, base_to_value(base)) |> prepend_prefix(base)
    color(inspected, :number, opts)
  end

  defp base_to_value(base) do
    case base do
      :binary  -> 2
      :decimal -> 10
      :octal   -> 8
      :hex     -> 16
    end
  end

  defp prepend_prefix(value, :decimal), do: value
  defp prepend_prefix(value, base) do
    prefix = case base do
      :binary -> "0b"
      :octal  -> "0o"
      :hex    -> "0x"
    end
    prefix <> value
  end
end

defimpl Inspect, for: Float do
  def inspect(term, opts) do
    inspected = IO.iodata_to_binary(:io_lib_format.fwrite_g(term))
    color(inspected, :number, opts)
  end
end

defimpl Inspect, for: Regex do
  def inspect(regex, opts) do
    source = IO.iodata_to_binary(['~r/', escape(regex.source, ?/), ?/, regex.opts])
    color(source, :regex, opts)
  end

  defp escape(bin, term),
    do: escape(bin, [], term)

  defp escape(<<?\\, term>> <> rest, buf, term),
    do: escape(rest, [buf | [?\\, term]], term)

  defp escape(<<term>> <> rest, buf, term),
    do: escape(rest, [buf | [?\\, term]], term)

  # The list of characters is from 'String.printable?' implementation
  # minus characters treated specially by regex: \s, \d, \b, \e

  defp escape(<<?\n>> <> rest, buf, term),
    do: escape(rest, [buf | '\\n'], term)

  defp escape(<<?\r>> <> rest, buf, term),
    do: escape(rest, [buf | '\\r'], term)

  defp escape(<<?\t>> <> rest, buf, term),
    do: escape(rest, [buf | '\\t'], term)

  defp escape(<<?\v>> <> rest, buf, term),
    do: escape(rest, [buf | '\\v'], term)

  defp escape(<<?\f>> <> rest, buf, term),
    do: escape(rest, [buf | '\\f'], term)

  defp escape(<<?\a>> <> rest, buf, term),
    do: escape(rest, [buf | '\\a'], term)

  defp escape(<<char::utf8, rest::binary>>, buf, term)
       when char in 0x20..0x7E
       when char in 0xA0..0xD7FF
       when char in 0xE000..0xFFFD
       when char in 0x10000..0x10FFFF,
    do: escape(rest, [buf | <<char::utf8>>], term)

  defp escape(<<char, rest::binary>>, buf, term),
    do: escape(rest, [buf | Inspect.BitString.escape_char(char)], term)

  defp escape(<<>>, buf, _), do: buf
end

defimpl Inspect, for: Function do
  def inspect(function, _opts) do
    fun_info = :erlang.fun_info(function)
    mod = fun_info[:module]
    name = fun_info[:name]

    if fun_info[:type] == :external and fun_info[:env] == [] do
      "&#{Inspect.Atom.inspect(mod)}.#{escape_name(name)}/#{fun_info[:arity]}"
    else
      case Atom.to_charlist(mod) do
        'elixir_compiler_' ++ _ ->
          if function_exported?(mod, :__RELATIVE__, 0) do
            "#Function<#{uniq(fun_info)} in file:#{mod.__RELATIVE__}>"
          else
            default_inspect(mod, fun_info)
          end
        _ ->
          default_inspect(mod, fun_info)
      end
    end
  end

  def escape_name(name) when is_atom(name) do
    escape_name(Atom.to_string(name))
  end

  def escape_name(name) when is_binary(name) do
    case Macro.classify_identifier(name) do
      :callable ->
        name
      type when type in [:not_callable, :alias] ->
        "\"" <> name <> "\""
      :other ->
        {escaped, _} = Inspect.BitString.escape(name, ?")
        IO.iodata_to_binary [?", escaped, ?"]
    end
  end

  # Example of this format: -func/arity-fun-count-
  def extract_anonymous_fun_parent("-" <> rest) do
    # We use :re instead of String.split/3 because we want to keep the "/"s and
    # "-"s (this is what the "(" and ")" in the regex do). We want to keep them
    # because we want to rebuild part of this split list (the function name)
    # later on.
    result =
      rest
      |> :re.split("([/-])")
      |> Enum.reject(&(&1 == ""))
      |> Enum.reverse()

    case result do
      ["-", _count, "-", _inner, "-", arity, "/" | reversed_function] ->
        {Enum.join(Enum.reverse(reversed_function)), arity}
      _other ->
        :error
    end
  end

  def extract_anonymous_fun_parent(other) when is_binary(other), do: :error

  defp default_inspect(mod, fun_info) do
    "#Function<#{uniq(fun_info)}/#{fun_info[:arity]} in " <>
      "#{Inspect.Atom.inspect(mod)}#{extract_name(fun_info[:name])}>"
  end

  defp extract_name([]) do
    ""
  end

  defp extract_name(name) do
    name = Atom.to_string(name)
    case extract_anonymous_fun_parent(name) do
      {name, arity} ->
        "." <> escape_name(name) <> "/" <> arity
      :error ->
        "." <> escape_name(name)
    end
  end

  defp uniq(fun_info) do
    Integer.to_string(fun_info[:new_index]) <> "." <>
      Integer.to_string(fun_info[:uniq])
  end
end

defimpl Inspect, for: PID do
  def inspect(pid, _opts) do
    "#PID" <> IO.iodata_to_binary(:erlang.pid_to_list(pid))
  end
end

defimpl Inspect, for: Port do
  def inspect(port, _opts) do
    IO.iodata_to_binary(:erlang.port_to_list(port))
  end
end

defimpl Inspect, for: Reference do
  def inspect(ref, _opts) do
    '#Ref' ++ rest = :erlang.ref_to_list(ref)
    "#Reference" <> IO.iodata_to_binary(rest)
  end
end

defimpl Inspect, for: Any do
  def inspect(%{__struct__: struct} = map, opts) do
    try do
      struct.__struct__
    rescue
      _ -> Inspect.Map.inspect(map, opts)
    else
      dunder ->
        if :maps.keys(dunder) == :maps.keys(map) do
          pruned = :maps.remove(:__exception__, :maps.remove(:__struct__, map))
          colorless_opts = %{opts | syntax_colors: []}
          Inspect.Map.inspect(pruned, Inspect.Atom.inspect(struct, colorless_opts), opts)
        else
          Inspect.Map.inspect(map, opts)
        end
    end
  end
end


Don't assume terminal availability in ANSI doctests

defmodule IO.ANSI.Sequence do
  @moduledoc false

  defmacro defsequence(name, code) do
    quote do
      name = unquote(name)
      code = unquote(code)

      def name, [], [], do:
        quote do: "\e[#{unquote(code)}m"

      args =
        quote do: [<< unquote(atom_to_binary(name)), rest :: binary >> ]

      defp :escape_sequence, args, [], do:
        quote do: { "\e[#{unquote(code)}m", rest }
    end
  end
end

defmodule IO.ANSI do
  @moduledoc """
  This module provides functionality to render ANSI escape sequences
  (http://en.wikipedia.org/wiki/ANSI_escape_code) —  characters embedded
  in the text used to control formatting, color, and other output options
  on video text terminals.
  """

  import IO.ANSI.Sequence

  @doc """
  Checks whether the default I/O device is a terminal or a file.

  Used to identify whether printing ANSI escape sequences will likely
  be printed as intended.
  """
  @spec terminal? :: boolean
  @spec terminal?(:io.device) :: boolean
  def terminal?(device // :erlang.group_leader) do
    match?({:ok, _}, :io.columns(device))
  end

  @doc "Resets all attributes"
  defsequence :reset, 0

  @doc "Bright (increased intensity) or Bold"
  defsequence :bright, 1

  @doc "Faint (decreased intensity), not widely supported"
  defsequence :faint, 2

  @doc "Italic: on. Not widely supported. Sometimes treated as inverse."
  defsequence :italic, 3

  @doc "Underline: Single"
  defsequence :underline, 4

  @doc "Blink: Slow. Less than 150 per minute"
  defsequence :blink_slow, 5

  @doc "Blink: Rapid. MS-DOS ANSI.SYS; 150 per minute or more; not widely supported"
  defsequence :blink_rapid, 6

  @doc "Image: Negative. Swap foreground and background"
  defsequence :inverse, 7

  @doc "Image: Negative. Swap foreground and background"
  defsequence :reverse, 7

  @doc "Conceal. Not widely supported"
  defsequence :conceal, 8

  @doc "Crossed-out. Characters legible, but marked for deletion. Not widely supported."
  defsequence :crossed_out, 9

  @doc "Sets primary (default) font"
  defsequence :primary_font, 10

  lc font_n inlist [1, 2, 3, 4, 5, 6, 7, 8, 9] do
    @doc "Sets alternative font #{font_n}"
    defsequence :"font_#{font_n}", font_n + 10
  end

  @doc "Normal color or intensity"
  defsequence :normal, 22

  @doc "Not italic"
  defsequence :not_italic, 23

  @doc "Underline: None"
  defsequence :no_underline, 24

  @doc "Blink: off"
  defsequence :blink_off, 25

  colors = [:black, :red, :green, :yellow, :blue, :magenta, :cyan, :white]
  colors = Enum.zip(0..(length(colors)-1), colors)

  lc { code, color } inlist colors do
    @doc "Sets foreground color to #{color}"
    defsequence color, code + 30

    @doc "Sets background color to #{color}"
    defsequence :"#{color}_background", code + 40
  end

  @doc "Default text color"
  defsequence :default_color, 39

  @doc "Default background color"
  defsequence :default_background, 49

  @doc "Framed"
  defsequence :framed, 51

  @doc "Encircled"
  defsequence :encircled, 52

  @doc "Overlined"
  defsequence :overlined, 53

  @doc "Not framed or encircled"
  defsequence :not_framed_encircled, 54

  @doc "Not overlined"
  defsequence :not_overlined, 55

  # Catch spaces between codes
  defp escape_sequence(<< ?\s, rest :: binary >>) do
    escape_sequence(rest)
  end

  defp escape_sequence(other) do
    [spec|_] = String.split(other, %r/(,|\})/)
    raise ArgumentError, message: "invalid ANSI sequence specification: #{spec}"
  end

  @doc %B"""
  Escapes a string by converting named ANSI sequences into actual ANSI codes.

  The format for referring to sequences is `%{red}` and `%{red,bright}` (for
  multiple sequences).

  It will also append a %{reset} to the string. If you don't want this
  behaviour, use `escape_fragment/1` and `escape_fragment/2`.

  An optional boolean parameter can be passed to enable or disable
  emitting actual ANSI codes. When false, no ANSI codes will emitted.
  By default, standard output will be checked if it is a terminal capable
  of handling these sequences (using `terminal?/0` function)

  ## Example

    iex> IO.ANSI.escape("Hello %{red,bright,green}yes", true)
    "Hello \e[31m\e[1m\e[32myes\e[0m"
  """
  @spec escape(String.t, emit :: boolean) :: String.t
  def escape(string, emit // terminal?) do
    {rendered, emitted} = do_escape(string, false, emit, false, [])
    if emitted and emit do
      rendered <> reset
    else
      rendered
    end
  end

  @doc %B"""
  Escapes a string by converting named ANSI sequences into actual ANSI codes.

  The format for referring to sequences is `%{red}` and `%{red,bright}` (for
  multiple sequences).

  An optional boolean parameter can be passed to enable or disable
  emitting actual ANSI codes. When false, no ANSI codes will emitted.
  By default, standard output will be checked if it is a terminal capable
  of handling these sequences (using `terminal?/0` function)

  ## Example

    iex> IO.ANSI.escape_fragment("Hello %{red,bright,green}yes", true)
    "Hello \e[31m\e[1m\e[32myes"
    iex> IO.ANSI.escape_fragment("%{reset}bye", true)
    "\e[0mbye"

  """
  @spec escape_fragment(String.t, emit :: boolean) :: String.t
  def escape_fragment(string, emit // terminal?) do
    {rendered, _emitted} = do_escape(string, false, emit, false, [])
    rendered
  end

  defp do_escape(<< ?%, ?{, rest :: binary >>, false, emit, _emitted, acc) do
    do_escape_sequence(rest, emit, acc)
  end
  defp do_escape(<< ?,, rest :: binary >>, true, emit, _emitted, acc) do
    do_escape_sequence(rest, emit, acc)
  end
  defp do_escape(<< ?\s, rest :: binary >>, true, emit, emitted, acc) do
    do_escape(rest, true, emit, emitted, acc)
  end
  defp do_escape(<< ?}, rest :: binary >>, true, emit, emitted, acc) do
    do_escape(rest, false, emit, emitted, acc)
  end
  defp do_escape(<< x :: [binary, size(1)], rest :: binary>>, false, emit, emitted, acc) do
    do_escape(rest, false, emit, emitted, [x|acc])
  end
  defp do_escape("", false, _emit, emitted, acc) do
    {list_to_binary(Enum.reverse(acc)), emitted}
  end

  defp do_escape_sequence(rest, emit, acc) do
    {code, rest} = escape_sequence(rest)
    if emit do
      acc = [code|acc]
    end
    do_escape(rest, true, emit, true, acc)
  end
end

defmodule IO.ANSI.Sequence do
  @moduledoc false

  defmacro defsequence(name, code) do
    quote do
      name = unquote(name)
      code = unquote(code)

      def name, [], [], do:
        quote do: "\e[#{unquote(code)}m"

      args =
        quote do: [<< unquote(atom_to_binary(name)), rest :: binary >> ]

      defp :escape_sequence, args, [], do:
        quote do: { "\e[#{unquote(code)}m", rest }
    end
  end
end

defmodule IO.ANSI do
  @moduledoc """
  This module provides functionality to render ANSI escape sequences
  (http://en.wikipedia.org/wiki/ANSI_escape_code) —  characters embedded
  in the text used to control formatting, color, and other output options
  on video text terminals.
  """

  import IO.ANSI.Sequence

  @doc """
  Checks whether the default I/O device is a terminal or a file.

  Used to identify whether printing ANSI escape sequences will likely
  be printed as intended.
  """
  @spec terminal? :: boolean
  @spec terminal?(:io.device) :: boolean
  def terminal?(device // :erlang.group_leader) do
    match?({:ok, _}, :io.columns(device))
  end

  @doc "Resets all attributes"
  defsequence :reset, 0

  @doc "Bright (increased intensity) or Bold"
  defsequence :bright, 1

  @doc "Faint (decreased intensity), not widely supported"
  defsequence :faint, 2

  @doc "Italic: on. Not widely supported. Sometimes treated as inverse."
  defsequence :italic, 3

  @doc "Underline: Single"
  defsequence :underline, 4

  @doc "Blink: Slow. Less than 150 per minute"
  defsequence :blink_slow, 5

  @doc "Blink: Rapid. MS-DOS ANSI.SYS; 150 per minute or more; not widely supported"
  defsequence :blink_rapid, 6

  @doc "Image: Negative. Swap foreground and background"
  defsequence :inverse, 7

  @doc "Image: Negative. Swap foreground and background"
  defsequence :reverse, 7

  @doc "Conceal. Not widely supported"
  defsequence :conceal, 8

  @doc "Crossed-out. Characters legible, but marked for deletion. Not widely supported."
  defsequence :crossed_out, 9

  @doc "Sets primary (default) font"
  defsequence :primary_font, 10

  lc font_n inlist [1, 2, 3, 4, 5, 6, 7, 8, 9] do
    @doc "Sets alternative font #{font_n}"
    defsequence :"font_#{font_n}", font_n + 10
  end

  @doc "Normal color or intensity"
  defsequence :normal, 22

  @doc "Not italic"
  defsequence :not_italic, 23

  @doc "Underline: None"
  defsequence :no_underline, 24

  @doc "Blink: off"
  defsequence :blink_off, 25

  colors = [:black, :red, :green, :yellow, :blue, :magenta, :cyan, :white]
  colors = Enum.zip(0..(length(colors)-1), colors)

  lc { code, color } inlist colors do
    @doc "Sets foreground color to #{color}"
    defsequence color, code + 30

    @doc "Sets background color to #{color}"
    defsequence :"#{color}_background", code + 40
  end

  @doc "Default text color"
  defsequence :default_color, 39

  @doc "Default background color"
  defsequence :default_background, 49

  @doc "Framed"
  defsequence :framed, 51

  @doc "Encircled"
  defsequence :encircled, 52

  @doc "Overlined"
  defsequence :overlined, 53

  @doc "Not framed or encircled"
  defsequence :not_framed_encircled, 54

  @doc "Not overlined"
  defsequence :not_overlined, 55

  # Catch spaces between codes
  defp escape_sequence(<< ?\s, rest :: binary >>) do
    escape_sequence(rest)
  end

  defp escape_sequence(other) do
    [spec|_] = String.split(other, %r/(,|\})/)
    raise ArgumentError, message: "invalid ANSI sequence specification: #{spec}"
  end

  @doc %B"""
  Escapes a string by converting named ANSI sequences into actual ANSI codes.

  The format for referring to sequences is `%{red}` and `%{red,bright}` (for
  multiple sequences).

  It will also append a %{reset} to the string. If you don't want this
  behaviour, use `escape_fragment/1` and `escape_fragment/2`.

  An optional boolean parameter can be passed to enable or disable
  emitting actual ANSI codes. When false, no ANSI codes will emitted.
  By default, standard output will be checked if it is a terminal capable
  of handling these sequences (using `terminal?/0` function)

  ## Example

    iex> IO.ANSI.escape("Hello %{red,bright,green}yes")
    "Hello \e[31m\e[1m\e[32myes\e[0m"
  """
  @spec escape(String.t, emit :: boolean) :: String.t
  def escape(string, emit // terminal?) do
    {rendered, emitted} = do_escape(string, false, emit, false, [])
    if emitted and emit do
      rendered <> reset
    else
      rendered
    end
  end

  @doc %B"""
  Escapes a string by converting named ANSI sequences into actual ANSI codes.

  The format for referring to sequences is `%{red}` and `%{red,bright}` (for
  multiple sequences).

  An optional boolean parameter can be passed to enable or disable
  emitting actual ANSI codes. When false, no ANSI codes will emitted.
  By default, standard output will be checked if it is a terminal capable
  of handling these sequences (using `terminal?/0` function)

  ## Example

    iex> IO.ANSI.escape_fragment("Hello %{red,bright,green}yes")
    "Hello \e[31m\e[1m\e[32myes"
    iex> IO.ANSI.escape_fragment("%{reset}bye")
    "\e[0mbye"

  """
  @spec escape_fragment(String.t, emit :: boolean) :: String.t
  def escape_fragment(string, emit // terminal?) do
    {rendered, _emitted} = do_escape(string, false, emit, false, [])
    rendered
  end

  defp do_escape(<< ?%, ?{, rest :: binary >>, false, emit, _emitted, acc) do
    do_escape_sequence(rest, emit, acc)
  end
  defp do_escape(<< ?,, rest :: binary >>, true, emit, _emitted, acc) do
    do_escape_sequence(rest, emit, acc)
  end
  defp do_escape(<< ?\s, rest :: binary >>, true, emit, emitted, acc) do
    do_escape(rest, true, emit, emitted, acc)
  end
  defp do_escape(<< ?}, rest :: binary >>, true, emit, emitted, acc) do
    do_escape(rest, false, emit, emitted, acc)
  end
  defp do_escape(<< x :: [binary, size(1)], rest :: binary>>, false, emit, emitted, acc) do
    do_escape(rest, false, emit, emitted, [x|acc])
  end
  defp do_escape("", false, _emit, emitted, acc) do
    {list_to_binary(Enum.reverse(acc)), emitted}
  end

  defp do_escape_sequence(rest, emit, acc) do
    {code, rest} = escape_sequence(rest)
    if emit do
      acc = [code|acc]
    end
    do_escape(rest, true, emit, true, acc)
  end
end


Add link to monitor/2 example

Add link to monitor/2 example

Because copying the entire example would be silly.

defmodule Process do
  @moduledoc """
  Conveniences for working with processes and the process dictionary.

  Besides the functions available in this module, the `Kernel` module
  exposes and auto-imports some basic functionality related to processes
  available through the functions:

    * `Kernel.spawn/1` and `Kernel.spawn/3`
    * `Kernel.spawn_link/1` and `Kernel.spawn_link/3`
    * `Kernel.spawn_monitor/1` and `Kernel.spawn_monitor/3`
    * `Kernel.self/0`
    * `Kernel.send/2`

  """

  @doc """
  Returns `true` if the process exists and is alive (i.e. it is not exiting
  and has not exited yet). Otherwise, returns `false`.

  `pid` must refer to a process at the local node.
  """
  @spec alive?(pid) :: boolean
  def alive?(pid) do
    :erlang.is_process_alive(pid)
  end

  @doc """
  Returns all key-values in the dictionary.
  """
  @spec get :: [{term, term}]
  def get do
    :erlang.get()
  end

  @doc """
  Returns the value for the given `key`.
  """
  @spec get(term) :: term
  @spec get(term, default :: term) :: term
  def get(key, default \\ nil) do
    case :erlang.get(key) do
      :undefined ->
        default
      value ->
        value
    end
  end

  @doc """
  Returns all keys that have the given `value`.
  """
  @spec get_keys(term) :: [term]
  def get_keys(value) do
    :erlang.get_keys(value)
  end

  @doc """
  Stores the given key-value in the process dictionary.
  """
  @spec put(term, term) :: term | nil
  def put(key, value) do
    nillify :erlang.put(key, value)
  end

  @doc """
  Deletes the given `key` from the dictionary.
  """
  @spec delete(term) :: term | nil
  def delete(key) do
    nillify :erlang.erase(key)
  end

  @doc """
  Sends an exit signal with the given reason to the pid.

  The following behaviour applies if reason is any term except `:normal` or `:kill`:

    1. If pid is not trapping exits, pid will exit with the given reason.

    2. If pid is trapping exits, the exit signal is transformed into a message
       `{:EXIT, from, reason}` and delivered to the message queue of pid.

    3. If reason is the atom `:normal`, pid will not exit (unless it is the calling
       process's pid, in which case it will exit with the reason `:normal`).
       If it is trapping exits, the exit signal is transformed into a message
       `{:EXIT, from, :normal}` and delivered to its message queue.

    4. If reason is the atom `:kill`, that is if `exit(pid, :kill)` is called,
       an untrappable exit signal is sent to pid which will unconditionally
       exit with exit reason `:killed`.

  Inlined by the compiler.

  ## Examples

      Process.exit(pid, :kill)

  """
  @spec exit(pid, term) :: true
  def exit(pid, reason) do
    :erlang.exit(pid, reason)
  end

  @doc """
  Sends a message to the given process.

  If the option `:noconnect` is used and sending the message would require an
  auto-connection to another node the message is not sent and `:noconnect` is
  returned.

  If the option `:nosuspend` is used and sending the message would cause the
  sender to be suspended the message is not sent and `:nosuspend` is returned.

  Otherwise the message is sent and `:ok` is returned.

  ## Examples

      iex> Process.send({:name, :node_does_not_exist}, :hi, [:noconnect])
      :noconnect

  """
  @spec send(dest, msg, [option]) ::  result when
        dest: pid | port | atom | {atom, node},
        msg: any,
        option: :noconnect | :nosuspend,
        result: :ok | :noconnect | :nosuspend
  def send(dest, msg, options) do
    :erlang.send(dest, msg, options)
  end

  @doc """
  Sends `msg` to `dest` after `time` milliseconds.

  If `dest` is a pid, it must be the pid of a local process, dead or alive.
  If `dest` is an atom, it must be the name of a registered process
  which is looked up at the time of delivery. No error is given if the name does
  not refer to a process.

  This function returns a timer reference, which can be read or canceled with
  `:erlang.read_timer/1`, `:erlang.start_timer/3` and `:erlang.cancel_timer/1`.
  Note `time` cannot be greater than `4294967295`.

  Finally, the timer will be automatically canceled if the given `dest` is a pid
  which is not alive or when the given pid exits. Note that timers will not be
  automatically canceled when `dest` is an atom (as the atom resolution is done
  on delivery).
  """
  @spec send_after(pid | atom, term, non_neg_integer) :: reference
  def send_after(dest, msg, time) do
    :erlang.send_after(time, dest, msg)
  end

  @type spawn_opt  :: :link | :monitor | {:priority, :low | :normal | :high} |
                      {:fullsweep_after, non_neg_integer} |
                      {:min_heap_size, non_neg_integer} |
                      {:min_bin_vheap_size, non_neg_integer}
  @type spawn_opts :: [spawn_opt]

  @doc """
  Spawns the given module and function passing the given args
  according to the given options.

  The result depends on the given options. In particular,
  if `:monitor` is given as an option, it will return a tuple
  containing the pid and the monitoring reference, otherwise
  just the spawned process pid.

  It also accepts extra options, for the list of available options
  check [`:erlang.spawn_opt/4`](http://www.erlang.org/doc/man/erlang.html#spawn_opt-4).

  Inlined by the compiler.
  """
  @spec spawn((() -> any), spawn_opts) :: pid | {pid, reference}
  def spawn(fun, opts) do
    :erlang.spawn_opt(fun, opts)
  end

  @doc """
  Spawns the given module and function passing the given args
  according to the given options.

  The result depends on the given options. In particular,
  if `:monitor` is given as an option, it will return a tuple
  containing the pid and the monitoring reference, otherwise
  just the spawned process pid.

  It also accepts extra options, for the list of available options
  check [`:erlang.spawn_opt/4`](http://www.erlang.org/doc/man/erlang.html#spawn_opt-4).

  Inlined by the compiler.
  """
  @spec spawn(module, atom, list, spawn_opts) :: pid | {pid, reference}
  def spawn(mod, fun, args, opts) do
    :erlang.spawn_opt(mod, fun, args, opts)
  end

  @doc """
  The calling process starts monitoring the item given.
  It returns the monitor reference.

  See [the need for monitoring](http://elixir-lang.org/getting-started/mix-otp/genserver.html#the-need-for-monitoring)
  for an example.
  See [`:erlang.monitor/2`](http://www.erlang.org/doc/man/erlang.html#monitor-2) for more info.

  Inlined by the compiler.
  """
  @spec monitor(pid | {reg_name :: atom, node :: atom} | reg_name :: atom) :: reference
  def monitor(item) do
    :erlang.monitor(:process, item)
  end

  @doc """
  If `monitor_ref` is a reference which the calling process
  obtained by calling `monitor/1`, this monitoring is turned off.
  If the monitoring is already turned off, nothing happens.

  See [`:erlang.demonitor/2`](http://www.erlang.org/doc/man/erlang.html#demonitor-2) for more info.

  Inlined by the compiler.
  """
  @spec demonitor(reference) :: true
  @spec demonitor(reference, options :: [:flush | :info]) :: boolean
  def demonitor(monitor_ref, options \\ []) do
    :erlang.demonitor(monitor_ref, options)
  end

  @doc """
  Returns a list of process identifiers corresponding to all the
  processes currently existing on the local node.

  Note that a process that is exiting, exists but is not alive, i.e.,
  `alive?/1` will return `false` for a process that is exiting,
  but its process identifier will be part of the result returned.

  See [`:erlang.processes/0`](http://www.erlang.org/doc/man/erlang.html#processes-0) for more info.
  """
  @spec list :: [pid]
  def list do
    :erlang.processes()
  end

  @doc """
  Creates a link between the calling process and another process
  (or port) `pid`, if there is not such a link already.

  See [`:erlang.link/1`](http://www.erlang.org/doc/man/erlang.html#link-1) for more info.

  Inlined by the compiler.
  """
  @spec link(pid | port) :: true
  def link(pid) do
    :erlang.link(pid)
  end

  @doc """
  Removes the link, if there is one, between the calling process and
  the process or port referred to by `pid`. Returns `true` and does not
  fail, even if there is no link or `id` does not exist

  See [`:erlang.unlink/1`](http://www.erlang.org/doc/man/erlang.html#unlink-1) for more info.

  Inlined by the compiler.
  """
  @spec unlink(pid | port) :: true
  def unlink(pid) do
    :erlang.unlink(pid)
  end

  @doc """
  Associates the name with a pid or a port identifier. `name`, which must
  be an atom, can be used instead of the pid / port identifier with the
  `Kernel.send/2` function.

  `Process.register/2` will fail with `ArgumentError` if the pid supplied
  is no longer alive, (check with `alive?/1`) or if the name is
  already registered (check with `whereis/1`).
  """
  @spec register(pid | port, atom) :: true
  def register(pid, name) when not name in [nil, false, true] do
    :erlang.register(name, pid)
  end

  @doc """
  Removes the registered name, associated with a pid or a port identifier.

  See [`:erlang.unregister/1`](http://www.erlang.org/doc/man/erlang.html#unregister-1) for more info.
  """
  @spec unregister(atom) :: true
  def unregister(name) do
    :erlang.unregister(name)
  end

  @doc """
  Returns the pid or port identifier with the registered name.
  Returns `nil` if the name is not registered.

  See [`:erlang.whereis/1`](http://www.erlang.org/doc/man/erlang.html#whereis-1) for more info.
  """
  @spec whereis(atom) :: pid | port | nil
  def whereis(name) do
    nillify :erlang.whereis(name)
  end

  @doc """
  Returns the pid of the group leader for the process which evaluates the function.
  """
  @spec group_leader :: pid
  def group_leader do
    :erlang.group_leader
  end

  @doc """
  Sets the group leader of `pid` to `leader`. Typically, this is used when a processes
  started from a certain shell should have a group leader other than `:init`.
  """
  @spec group_leader(pid, leader :: pid) :: true
  def group_leader(pid, leader) do
    :erlang.group_leader(leader, pid)
  end

  @doc """
  Returns a list of names which have been registered using `register/2`.
  """
  @spec registered :: [atom]
  def registered do
    :erlang.registered()
  end

  @typep process_flag :: :trap_exit | :error_handler | :min_heap_size |
                         :min_bin_vheap_size | :priority | :save_calls |
                         :sensitive
  @doc """
  Sets certain flags for the process which calls this function.
  Returns the old value of the flag.

  See [`:erlang.process_flag/2`](http://www.erlang.org/doc/man/erlang.html#process_flag-2) for more info.
  """
  @spec flag(process_flag, term) :: term
  def flag(flag, value) do
    :erlang.process_flag(flag, value)
  end

  @doc """
  Sets certain flags for the process `pid`, in the same manner as `flag/2`.
  Returns the old value of the flag. The allowed values for `flag` are
  only a subset of those allowed in `flag/2`, namely: `save_calls`.

  See [`:erlang.process_flag/3`](http://www.erlang.org/doc/man/erlang.html#process_flag-3) for more info.
  """
  @spec flag(pid, :save_calls, non_neg_integer) :: non_neg_integer
  def flag(pid, flag, value) do
    :erlang.process_flag(pid, flag, value)
  end

  @doc """
  Returns information about the process identified by `pid` or `nil` if the process
  is not alive.
  Use this only for debugging information.

  See [`:erlang.process_info/1`](http://www.erlang.org/doc/man/erlang.html#process_info-1) for more info.
  """
  @spec info(pid) :: Keyword.t
  def info(pid) do
    nillify :erlang.process_info(pid)
  end

  @doc """
  Returns information about the process identified by `pid`
  or `nil` if the process is not alive.

  See [`:erlang.process_info/2`](http://www.erlang.org/doc/man/erlang.html#process_info-2) for more info.
  """
  @spec info(pid, atom | [atom]) :: {atom, term} | [{atom, term}]  | nil
  def info(pid, spec)

  def info(pid, :registered_name) do
    case :erlang.process_info(pid, :registered_name) do
      :undefined -> nil
      [] -> {:registered_name, []}
      other -> other
    end
  end

  def info(pid, spec) when is_atom(spec) or is_list(spec) do
    nillify :erlang.process_info(pid, spec)
  end

  @doc """
  Puts the calling process into a wait state
  where its memory allocation has been reduced as much as possible,
  which is useful if the process does not expect to receive any messages
  in the near future.

  See [`:erlang.hibernate/3`](http://www.erlang.org/doc/man/erlang.html#hibernate-3) for more info.

  Inlined by the compiler.
  """
  @spec hibernate(module, atom, list) :: no_return
  def hibernate(mod, fun, args) do
    :erlang.hibernate(mod, fun, args)
  end

  @compile {:inline, nillify: 1}
  defp nillify(:undefined), do: nil
  defp nillify(other),      do: other
end

defmodule Process do
  @moduledoc """
  Conveniences for working with processes and the process dictionary.

  Besides the functions available in this module, the `Kernel` module
  exposes and auto-imports some basic functionality related to processes
  available through the functions:

    * `Kernel.spawn/1` and `Kernel.spawn/3`
    * `Kernel.spawn_link/1` and `Kernel.spawn_link/3`
    * `Kernel.spawn_monitor/1` and `Kernel.spawn_monitor/3`
    * `Kernel.self/0`
    * `Kernel.send/2`

  """

  @doc """
  Returns `true` if the process exists and is alive (i.e. it is not exiting
  and has not exited yet). Otherwise, returns `false`.

  `pid` must refer to a process at the local node.
  """
  @spec alive?(pid) :: boolean
  def alive?(pid) do
    :erlang.is_process_alive(pid)
  end

  @doc """
  Returns all key-values in the dictionary.
  """
  @spec get :: [{term, term}]
  def get do
    :erlang.get()
  end

  @doc """
  Returns the value for the given `key`.
  """
  @spec get(term) :: term
  @spec get(term, default :: term) :: term
  def get(key, default \\ nil) do
    case :erlang.get(key) do
      :undefined ->
        default
      value ->
        value
    end
  end

  @doc """
  Returns all keys that have the given `value`.
  """
  @spec get_keys(term) :: [term]
  def get_keys(value) do
    :erlang.get_keys(value)
  end

  @doc """
  Stores the given key-value in the process dictionary.
  """
  @spec put(term, term) :: term | nil
  def put(key, value) do
    nillify :erlang.put(key, value)
  end

  @doc """
  Deletes the given `key` from the dictionary.
  """
  @spec delete(term) :: term | nil
  def delete(key) do
    nillify :erlang.erase(key)
  end

  @doc """
  Sends an exit signal with the given reason to the pid.

  The following behaviour applies if reason is any term except `:normal` or `:kill`:

    1. If pid is not trapping exits, pid will exit with the given reason.

    2. If pid is trapping exits, the exit signal is transformed into a message
       `{:EXIT, from, reason}` and delivered to the message queue of pid.

    3. If reason is the atom `:normal`, pid will not exit (unless it is the calling
       process's pid, in which case it will exit with the reason `:normal`).
       If it is trapping exits, the exit signal is transformed into a message
       `{:EXIT, from, :normal}` and delivered to its message queue.

    4. If reason is the atom `:kill`, that is if `exit(pid, :kill)` is called,
       an untrappable exit signal is sent to pid which will unconditionally
       exit with exit reason `:killed`.

  Inlined by the compiler.

  ## Examples

      Process.exit(pid, :kill)

  """
  @spec exit(pid, term) :: true
  def exit(pid, reason) do
    :erlang.exit(pid, reason)
  end

  @doc """
  Sends a message to the given process.

  If the option `:noconnect` is used and sending the message would require an
  auto-connection to another node the message is not sent and `:noconnect` is
  returned.

  If the option `:nosuspend` is used and sending the message would cause the
  sender to be suspended the message is not sent and `:nosuspend` is returned.

  Otherwise the message is sent and `:ok` is returned.

  ## Examples

      iex> Process.send({:name, :node_does_not_exist}, :hi, [:noconnect])
      :noconnect

  """
  @spec send(dest, msg, [option]) ::  result when
        dest: pid | port | atom | {atom, node},
        msg: any,
        option: :noconnect | :nosuspend,
        result: :ok | :noconnect | :nosuspend
  def send(dest, msg, options) do
    :erlang.send(dest, msg, options)
  end

  @doc """
  Sends `msg` to `dest` after `time` milliseconds.

  If `dest` is a pid, it must be the pid of a local process, dead or alive.
  If `dest` is an atom, it must be the name of a registered process
  which is looked up at the time of delivery. No error is given if the name does
  not refer to a process.

  This function returns a timer reference, which can be read or canceled with
  `:erlang.read_timer/1`, `:erlang.start_timer/3` and `:erlang.cancel_timer/1`.
  Note `time` cannot be greater than `4294967295`.

  Finally, the timer will be automatically canceled if the given `dest` is a pid
  which is not alive or when the given pid exits. Note that timers will not be
  automatically canceled when `dest` is an atom (as the atom resolution is done
  on delivery).
  """
  @spec send_after(pid | atom, term, non_neg_integer) :: reference
  def send_after(dest, msg, time) do
    :erlang.send_after(time, dest, msg)
  end

  @type spawn_opt  :: :link | :monitor | {:priority, :low | :normal | :high} |
                      {:fullsweep_after, non_neg_integer} |
                      {:min_heap_size, non_neg_integer} |
                      {:min_bin_vheap_size, non_neg_integer}
  @type spawn_opts :: [spawn_opt]

  @doc """
  Spawns the given module and function passing the given args
  according to the given options.

  The result depends on the given options. In particular,
  if `:monitor` is given as an option, it will return a tuple
  containing the pid and the monitoring reference, otherwise
  just the spawned process pid.

  It also accepts extra options, for the list of available options
  check [`:erlang.spawn_opt/4`](http://www.erlang.org/doc/man/erlang.html#spawn_opt-4).

  Inlined by the compiler.
  """
  @spec spawn((() -> any), spawn_opts) :: pid | {pid, reference}
  def spawn(fun, opts) do
    :erlang.spawn_opt(fun, opts)
  end

  @doc """
  Spawns the given module and function passing the given args
  according to the given options.

  The result depends on the given options. In particular,
  if `:monitor` is given as an option, it will return a tuple
  containing the pid and the monitoring reference, otherwise
  just the spawned process pid.

  It also accepts extra options, for the list of available options
  check [`:erlang.spawn_opt/4`](http://www.erlang.org/doc/man/erlang.html#spawn_opt-4).

  Inlined by the compiler.
  """
  @spec spawn(module, atom, list, spawn_opts) :: pid | {pid, reference}
  def spawn(mod, fun, args, opts) do
    :erlang.spawn_opt(mod, fun, args, opts)
  end

  @doc """
  The calling process starts monitoring the item given.
  It returns the monitor reference.

  See [`:erlang.monitor/2`](http://www.erlang.org/doc/man/erlang.html#monitor-2) for more info.

  Inlined by the compiler.
  """
  @spec monitor(pid | {reg_name :: atom, node :: atom} | reg_name :: atom) :: reference
  def monitor(item) do
    :erlang.monitor(:process, item)
  end

  @doc """
  If `monitor_ref` is a reference which the calling process
  obtained by calling `monitor/1`, this monitoring is turned off.
  If the monitoring is already turned off, nothing happens.

  See [`:erlang.demonitor/2`](http://www.erlang.org/doc/man/erlang.html#demonitor-2) for more info.

  Inlined by the compiler.
  """
  @spec demonitor(reference) :: true
  @spec demonitor(reference, options :: [:flush | :info]) :: boolean
  def demonitor(monitor_ref, options \\ []) do
    :erlang.demonitor(monitor_ref, options)
  end

  @doc """
  Returns a list of process identifiers corresponding to all the
  processes currently existing on the local node.

  Note that a process that is exiting, exists but is not alive, i.e.,
  `alive?/1` will return `false` for a process that is exiting,
  but its process identifier will be part of the result returned.

  See [`:erlang.processes/0`](http://www.erlang.org/doc/man/erlang.html#processes-0) for more info.
  """
  @spec list :: [pid]
  def list do
    :erlang.processes()
  end

  @doc """
  Creates a link between the calling process and another process
  (or port) `pid`, if there is not such a link already.

  See [`:erlang.link/1`](http://www.erlang.org/doc/man/erlang.html#link-1) for more info.

  Inlined by the compiler.
  """
  @spec link(pid | port) :: true
  def link(pid) do
    :erlang.link(pid)
  end

  @doc """
  Removes the link, if there is one, between the calling process and
  the process or port referred to by `pid`. Returns `true` and does not
  fail, even if there is no link or `id` does not exist

  See [`:erlang.unlink/1`](http://www.erlang.org/doc/man/erlang.html#unlink-1) for more info.

  Inlined by the compiler.
  """
  @spec unlink(pid | port) :: true
  def unlink(pid) do
    :erlang.unlink(pid)
  end

  @doc """
  Associates the name with a pid or a port identifier. `name`, which must
  be an atom, can be used instead of the pid / port identifier with the
  `Kernel.send/2` function.

  `Process.register/2` will fail with `ArgumentError` if the pid supplied
  is no longer alive, (check with `alive?/1`) or if the name is
  already registered (check with `whereis/1`).
  """
  @spec register(pid | port, atom) :: true
  def register(pid, name) when not name in [nil, false, true] do
    :erlang.register(name, pid)
  end

  @doc """
  Removes the registered name, associated with a pid or a port identifier.

  See [`:erlang.unregister/1`](http://www.erlang.org/doc/man/erlang.html#unregister-1) for more info.
  """
  @spec unregister(atom) :: true
  def unregister(name) do
    :erlang.unregister(name)
  end

  @doc """
  Returns the pid or port identifier with the registered name.
  Returns `nil` if the name is not registered.

  See [`:erlang.whereis/1`](http://www.erlang.org/doc/man/erlang.html#whereis-1) for more info.
  """
  @spec whereis(atom) :: pid | port | nil
  def whereis(name) do
    nillify :erlang.whereis(name)
  end

  @doc """
  Returns the pid of the group leader for the process which evaluates the function.
  """
  @spec group_leader :: pid
  def group_leader do
    :erlang.group_leader
  end

  @doc """
  Sets the group leader of `pid` to `leader`. Typically, this is used when a processes
  started from a certain shell should have a group leader other than `:init`.
  """
  @spec group_leader(pid, leader :: pid) :: true
  def group_leader(pid, leader) do
    :erlang.group_leader(leader, pid)
  end

  @doc """
  Returns a list of names which have been registered using `register/2`.
  """
  @spec registered :: [atom]
  def registered do
    :erlang.registered()
  end

  @typep process_flag :: :trap_exit | :error_handler | :min_heap_size |
                         :min_bin_vheap_size | :priority | :save_calls |
                         :sensitive
  @doc """
  Sets certain flags for the process which calls this function.
  Returns the old value of the flag.

  See [`:erlang.process_flag/2`](http://www.erlang.org/doc/man/erlang.html#process_flag-2) for more info.
  """
  @spec flag(process_flag, term) :: term
  def flag(flag, value) do
    :erlang.process_flag(flag, value)
  end

  @doc """
  Sets certain flags for the process `pid`, in the same manner as `flag/2`.
  Returns the old value of the flag. The allowed values for `flag` are
  only a subset of those allowed in `flag/2`, namely: `save_calls`.

  See [`:erlang.process_flag/3`](http://www.erlang.org/doc/man/erlang.html#process_flag-3) for more info.
  """
  @spec flag(pid, :save_calls, non_neg_integer) :: non_neg_integer
  def flag(pid, flag, value) do
    :erlang.process_flag(pid, flag, value)
  end

  @doc """
  Returns information about the process identified by `pid` or `nil` if the process
  is not alive.
  Use this only for debugging information.

  See [`:erlang.process_info/1`](http://www.erlang.org/doc/man/erlang.html#process_info-1) for more info.
  """
  @spec info(pid) :: Keyword.t
  def info(pid) do
    nillify :erlang.process_info(pid)
  end

  @doc """
  Returns information about the process identified by `pid`
  or `nil` if the process is not alive.

  See [`:erlang.process_info/2`](http://www.erlang.org/doc/man/erlang.html#process_info-2) for more info.
  """
  @spec info(pid, atom | [atom]) :: {atom, term} | [{atom, term}]  | nil
  def info(pid, spec)

  def info(pid, :registered_name) do
    case :erlang.process_info(pid, :registered_name) do
      :undefined -> nil
      [] -> {:registered_name, []}
      other -> other
    end
  end

  def info(pid, spec) when is_atom(spec) or is_list(spec) do
    nillify :erlang.process_info(pid, spec)
  end

  @doc """
  Puts the calling process into a wait state
  where its memory allocation has been reduced as much as possible,
  which is useful if the process does not expect to receive any messages
  in the near future.

  See [`:erlang.hibernate/3`](http://www.erlang.org/doc/man/erlang.html#hibernate-3) for more info.

  Inlined by the compiler.
  """
  @spec hibernate(module, atom, list) :: no_return
  def hibernate(mod, fun, args) do
    :erlang.hibernate(mod, fun, args)
  end

  @compile {:inline, nillify: 1}
  defp nillify(:undefined), do: nil
  defp nillify(other),      do: other
end


Reword some more examples

Reword some more examples

defmodule Processes do
  use Koans

  koan "You are a process" do
    assert Process.alive?(self()) == ___
  end

  koan "You can ask a process to introduce itself" do
    information = Process.info(self())

    assert information[:status] == ___
  end

  koan "New processes are spawned functions" do
    pid = spawn(fn -> nil end)

    assert Process.alive?(pid) == ___
  end

  koan "You can send messages to processes" do
    send self(), "hola!"

    receive do
      msg -> assert msg == ___
    end
  end

  koan "A common pattern is to include the sender in the message, so that it can reply" do
    pid = spawn(fn -> receive do
                         {:hello, sender} -> send sender, :how_are_you?
                      end
                 end)

    send pid, {:hello, self()}
    assert_receive ___
  end

  koan "Waiting for a message can get boring" do
    parent = self()
    spawn(fn -> receive do
                after
                  5 -> send parent, {:waited_too_long, "I am impatient"}
                end
           end)

    assert_receive ___
  end

  koan "Killing a process will terminate it" do
    pid = spawn(fn -> Process.exit(self(), :kill) end)
    :timer.sleep(500)
    assert Process.alive?(pid) == ___
  end

  koan "You can also terminate processes other than yourself" do
    pid = spawn(fn -> receive do end end)

    assert Process.alive?(pid) == ___
    Process.exit(pid, :kill)
    assert Process.alive?(pid) == ___
  end

  koan "Trapping will allow you to react to someone terminating the process" do
    parent = self()
    pid = spawn(fn ->
                      Process.flag(:trap_exit, true)
                      send parent, :ready
                      receive do
                        {:EXIT, _pid, reason} -> send parent, {:exited, reason}
                      end
    end)

    receive do
      :ready -> true
    end

    Process.exit(pid, :random_reason)

    assert_receive ___
  end

  koan "Trying to quit normally has no effect" do
    pid = spawn(fn -> receive do
                      end
                end)
    Process.exit(pid, :normal)
    assert Process.alive?(pid) == ___
  end

  koan "Exiting normally yourself on the other hand DOES terminate you" do
    pid = spawn(fn -> Process.exit(self, :normal) end)
    :timer.sleep(100)
    assert Process.alive?(pid) == ___
  end

  koan "Parent processes can be informed about exiting children, if they trap and link" do
    Process.flag(:trap_exit, true)
    spawn_link(fn -> Process.exit(self, :normal) end)

    assert_receive {:EXIT, _pid, ___}
  end

  koan "If you monitor your children, you'll be automatically informed for their depature" do
    spawn_monitor(fn -> Process.exit(self(), :normal) end)

    assert_receive {:DOWN, _ref, :process, _pid, ___}
  end
end

defmodule Processes do
  use Koans

  koan "Tests run in a process" do
    assert Process.alive?(self()) == ___
  end

  koan "You can ask a process to introduce itself" do
    information = Process.info(self())

    assert information[:status] == ___
  end

  koan "New processes are spawned" do
    pid = spawn(fn -> nil end)

    assert Process.alive?(pid) == ___
  end

  koan "You can send messages to any process you want" do
    send self(), "hola!"

    receive do
      msg -> assert msg == ___
    end
  end

  koan "A common pattern is to include the sender in the message, so that it can reply" do
    pid = spawn(fn -> receive do
                         {:hello, sender} -> send sender, :how_are_you?
                      end
                 end)

    send pid, {:hello, self()}
    assert_receive ___
  end

  koan "Waiting for a message can get boring" do
    parent = self()
    spawn(fn -> receive do
                after
                  5 -> send parent, {:waited_too_long, "I am impatient"}
                end
           end)

    assert_receive ___
  end

  koan "Killing a process will terminate it" do
    pid = spawn(fn -> Process.exit(self(), :kill) end)
    :timer.sleep(500)
    assert Process.alive?(pid) == ___
  end

  koan "You can also terminate processes other than yourself" do
    pid = spawn(fn -> receive do end end)

    assert Process.alive?(pid) == ___
    Process.exit(pid, :kill)
    assert Process.alive?(pid) == ___
  end

  koan "Trapping will allow you to react to someone terminating the process" do
    parent = self()
    pid = spawn(fn ->
                      Process.flag(:trap_exit, true)
                      send parent, :ready
                      receive do
                        {:EXIT, _pid, reason} -> send parent, {:exited, reason}
                      end
    end)

    receive do
      :ready -> true
    end

    Process.exit(pid, :random_reason)

    assert_receive ___
  end

  koan "Trying to quit normally has no effect" do
    pid = spawn(fn -> receive do
                      end
                end)
    Process.exit(pid, :normal)
    assert Process.alive?(pid) == ___
  end

  koan "Exiting normally yourself on the other hand DOES terminate you" do
    pid = spawn(fn -> Process.exit(self, :normal) end)
    :timer.sleep(100)
    assert Process.alive?(pid) == ___
  end

  koan "Parent processes can be informed about exiting children, if they trap and link" do
    Process.flag(:trap_exit, true)
    spawn_link(fn -> Process.exit(self, :normal) end)

    assert_receive {:EXIT, _pid, ___}
  end

  koan "If you monitor your children, you'll be automatically informed for their depature" do
    spawn_monitor(fn -> Process.exit(self(), :normal) end)

    assert_receive {:DOWN, _ref, :process, _pid, ___}
  end
end