Pass colors parameter to inline handling functions in ANSIDocs

defmodule IEx.ANSIDocs do
  @moduledoc false

  @bullets [?*, ?-, ?+]

  @doc """
  Prints the head of the documentation (i.e. the function signature)
  """
  def print_heading(string, use_ansi // IO.ANSI.terminal?, colors // IEx.Options.get(:colors)) do
    if use_ansi do
      write_doc_heading(string, colors)
    else
      IO.puts "* #{string}\n"
    end
    IEx.dont_display_result
  end

  defp write_doc_heading(heading, colors) do
    IO.puts IO.ANSI.reset
    width   = column_width()
    padding = div(width + String.length(heading), 2)
    heading = heading |> String.rjust(padding) |> String.ljust(width)
    write(:doc_title, heading, colors)
  end

  @doc """
  Prints the documentation body.
  """
  def print(doc, use_ansi // IO.ANSI.terminal?, colors // IEx.Options.get(:colors)) do
    if use_ansi do
      doc
      |> String.split(["\r\n","\n"], trim: false)
      |> Enum.map(&String.rstrip/1)
      |> process("", colors)
    else
      IO.puts doc
    end
    IEx.dont_display_result
  end

  defp process([], _indent, _colors), do: nil

  defp process(["# " <> heading | rest], _indent, colors) do
    write_h1(String.strip(heading), colors)
    process(rest, "", colors)
  end

  defp process(["## " <> heading | rest], _indent, colors) do
    write_h2(String.strip(heading), colors)
    process(rest, "", colors)
  end

  defp process(["### " <> heading | rest], indent, colors) do
    write_h3(String.strip(heading), indent, colors)
    process(rest, indent, colors)
  end

  defp process(["" | rest], indent, colors) do
    process(rest, indent, colors)
  end

  defp process(["    " <> line | rest], indent, colors) do
    process_code(rest, [line], indent, colors)
  end

  defp process([line | rest], indent, colors) do
    { stripped, count } = strip_spaces(line, 0)
    case stripped do
      <<bullet, ?\s, item :: binary >> when bullet in @bullets ->
        process_list(item, rest, count, indent, colors)
      _ ->
        process_text(rest, [line], indent, false, colors)
    end
  end

  defp strip_spaces(" " <> line, acc) do
    strip_spaces(line, acc + 1)
  end

  defp strip_spaces(rest, acc) do
    { rest, acc }
  end

  ## Headings

  defp write_h1(heading, colors) do
    write_h2(String.upcase(heading), colors)
  end

  defp write_h2(heading, colors) do
    write(:doc_headings, heading, colors)
  end

  defp write_h3(heading, indent, colors) do
    IO.write(indent)
    write(:doc_headings, heading, colors)
  end

  ## Lists

  defp process_list(line, rest, count, indent, colors) do
    IO.write indent <> "• "
    { contents, rest, done } = process_list_next(rest, count, false, [])
    process_text(contents, [line], indent <> "  ", true, colors)
    if done, do: IO.puts(IO.ANSI.reset)
    process(rest, indent, colors)
  end

  # Process the thing after a list item entry. It can be either:
  #
  # * Continuation of the list
  # * A nested list
  # * The end of the list
  #
  defp process_list_next([" " <> _ = line | rest], count, _done, acc) do
    case list_next(line, count) do
      :done    -> { Enum.reverse(acc), [line|rest], false }
      chopped  -> process_list_next(rest, count, false, [chopped|acc])
    end
  end

  defp process_list_next([<<bullet, ?\s, _ :: binary>> | _] = rest, _count, _done, acc) when bullet in @bullets do
    { Enum.reverse(acc), rest, false }
  end

  defp process_list_next(["" | rest], count, _done, acc) do
    process_list_next(rest, count, true, [""|acc])
  end

  defp process_list_next(rest, _count, done, acc) do
    { Enum.reverse(acc), rest, done }
  end

  defp list_next(<<bullet, ?\s, _ :: binary>>, 0) when bullet in @bullets, do: :done
  defp list_next(line, 0),          do: chop(line, 2)
  defp list_next(" " <> line, acc), do: list_next(line, acc - 1)
  defp list_next(line, _acc),       do: line

  defp chop(" " <> line, acc) when acc > 0, do: chop(line, acc - 1)
  defp chop(line, _acc), do: line

  ## Text (paragraphs / lists)

  defp process_text(doc=["" | _], para, indent, from_list, colors) do
    write_text(Enum.reverse(para), indent, from_list, colors)
    process(doc, indent, colors)
  end

  defp process_text([], para, indent, from_list, colors) do
    write_text(Enum.reverse(para), indent, from_list, colors)
  end

  defp process_text([line | rest], para, indent, true, colors) do
    { stripped, count } = strip_spaces(line, 0)
    case stripped do
      <<bullet, ?\s, item :: binary>> when bullet in @bullets ->
        write_text(Enum.reverse(para), indent, true, colors)
        process_list(item, rest, count, indent, colors)
      _ ->
        process_text(rest, [line | para], indent, true, colors)
    end
  end

  defp process_text([line | rest], para, indent, from_list, colors) do
    process_text(rest, [line | para], indent, from_list, colors)
  end

  defp write_text(lines, indent, from_list, colors) do
    lines
    |> Enum.join(" ")
    |> handle_links
    |> handle_inline(nil, [], [], colors)
    |> String.split(%r{\s})
    |> write_with_wrap(column_width() - size(indent), indent, from_list)

    unless from_list, do: IO.puts(IO.ANSI.reset)
  end

  ## Code blocks

  defp process_code([], code, indent, colors) do
    write_code(code, indent, colors)
  end

  # Blank line between code blocks
  defp process_code([ "", "    " <> line | rest ], code, indent, colors) do
    process_code(rest, [line, "" | code], indent, colors)
  end

  defp process_code([ "    " <> line | rest ], code, indent, colors) do
    process_code(rest, [line|code], indent, colors)
  end

  defp process_code(rest, code, indent, colors) do
    write_code(code, indent, colors)
    process(rest, indent, colors)
  end

  defp write_code(code, indent, colors) do
    write(:doc_code, "#{indent}┃ #{Enum.join(Enum.reverse(code), "\n#{indent}┃ ")}", colors)
  end

  ## Helpers

  defp write(style, string, colors) do
    color =  colors[style]
    enabled = colors[:enabled]
    seq_color = IO.ANSI.escape_fragment("%{#{color}}", enabled)
    seq_reset = IO.ANSI.escape_fragment("%{reset}", enabled)
    IO.puts seq_color <> string <> seq_reset
    IO.puts seq_reset
  end

  defp write_with_wrap([], _available, _indent, _first) do
    :ok
  end

  defp write_with_wrap(words, available, indent, first) do
    { words, rest } = take_words(words, available, [])
    IO.puts (if first, do: "", else: indent) <> Enum.join(words, " ")
    write_with_wrap(rest, available, indent, false)
  end

  defp take_words([word|words], available, acc) do
    available = available - length_without_escape(word, 0)

    cond do
      # It fits, take one for space and continue decreasing
      available > 0 ->
        take_words(words, available - 1, [word|acc])

      # No space but we got no words
      acc == [] ->
        { [word], words }

      # Otherwise
      true ->
        { Enum.reverse(acc), [word|words] }
    end
  end

  defp take_words([], _available, acc) do
    { Enum.reverse(acc), [] }
  end

  defp length_without_escape(<< ?\e, ?[, _, _, ?m, rest :: binary >>, count) do
    length_without_escape(rest, count)
  end

  defp length_without_escape(<< ?\e, ?[, _, ?m, rest :: binary >>, count) do
    length_without_escape(rest, count)
  end

  defp length_without_escape(rest, count) do
    case String.next_grapheme(rest) do
      :no_grapheme -> count
      { _, rest }  -> length_without_escape(rest, count + 1)
    end
  end

  defp handle_links(text) do
    text
    |> remove_square_brackets_in_link
    |> escape_underlines_in_link
  end

  defp escape_underlines_in_link(text) do
    case Regex.match?(%r{.*(https?\S*)}, text) do
      true ->
        Regex.replace(%r{_}, text, "\\\\_")
      _ ->
        text
    end
  end

  defp remove_square_brackets_in_link(text) do
    Regex.replace(%r{\[(.*?)\]\((.*?)\)}, text, "\\1 (\\2)")
  end

  # Single inline quotes.
  @single [?`, ?_, ?*]

  # ` does not require space in between
  @spaced [?_, ?*]

  # Clauses for handling spaces
  defp handle_inline(<<?*, ?*, ?\s, rest :: binary>>, nil, buffer, acc, colors) do
    handle_inline(rest, nil, [?\s, ?*, ?*|buffer], acc, colors)
  end

  defp handle_inline(<<mark, ?\s, rest :: binary>>, nil, buffer, acc, colors) when mark in @spaced do
    handle_inline(rest, nil, [?\s, mark|buffer], acc, colors)
  end

  defp handle_inline(<<?\s, ?*, ?*, rest :: binary>>, limit, buffer, acc, colors) do
    handle_inline(rest, limit, [?*, ?*, ?\s|buffer], acc, colors)
  end

  defp handle_inline(<<?\s, mark, rest :: binary>>, limit, buffer, acc, colors) when mark in @spaced do
    handle_inline(rest, limit, [mark, ?\s|buffer], acc, colors)
  end

  # Clauses for handling escape
  defp handle_inline(<<?\\, ?\\, rest :: binary>>, limit, buffer, acc, colors) do
    handle_inline(rest, limit, [?\\|buffer], acc, colors)
  end

  defp handle_inline(<<?\\, ?*, ?*, rest :: binary>>, limit, buffer, acc, colors) do
    handle_inline(rest, limit, [?*, ?*|buffer], acc, colors)
  end

  # A escape is not valid inside `
  defp handle_inline(<<?\\, mark, rest :: binary>>, limit, buffer, acc, colors)
      when mark in [?_, ?*, ?`] and not(mark == limit and mark == ?`) do
    handle_inline(rest, limit, [mark|buffer], acc, colors)
  end

  # Inline start
  defp handle_inline(<<?*, ?*, rest :: binary>>, nil, buffer, acc, colors) when rest != "" do
    handle_inline(rest, ?d, ["**"], [Enum.reverse(buffer)|acc], colors)
  end

  defp handle_inline(<<mark, rest :: binary>>, nil, buffer, acc, colors) when rest != "" and mark in @single do
    handle_inline(rest, mark, [<<mark>>], [Enum.reverse(buffer)|acc], colors)
  end

  # Inline end
  defp handle_inline(<<?*, ?*, rest :: binary>>, ?d, buffer, acc, colors) do
    handle_inline(rest, nil, [], [inline_buffer(buffer, colors)|acc], colors)
  end

  defp handle_inline(<<mark, rest :: binary>>, mark, buffer, acc, colors) when mark in @single do
    handle_inline(rest, nil, [], [inline_buffer(buffer, colors)|acc], colors)
  end

  defp handle_inline(<<char, rest :: binary>>, mark, buffer, acc, colors) do
    handle_inline(rest, mark, [char|buffer], acc, colors)
  end

  defp handle_inline(<<>>, _mark, buffer, acc, _colors) do
    iolist_to_binary Enum.reverse([Enum.reverse(buffer)|acc])
  end

  defp inline_buffer(buffer, _colors) do
    [h|t] = Enum.reverse([IO.ANSI.reset|buffer])
    [color_for(h)|t]
  end

  defp color_for("`"),  do: color(:doc_inline_code)
  defp color_for("_"),  do: color(:doc_underline)
  defp color_for("*"),  do: color(:doc_bold)
  defp color_for("**"), do: color(:doc_bold)

  defp color(color_name) do
    colors = IEx.Options.get(:colors)

    if colors[:enabled] do
      IO.ANSI.escape_fragment("%{#{colors[color_name]}}", true)
    else
      ""
    end
  end

  defp column_width() do
    case :io.columns do
      { :ok, width } -> min(width, 80)
      _              -> 80
    end
  end
end

defmodule IEx.ANSIDocs do
  @moduledoc false

  @bullets [?*, ?-, ?+]

  @doc """
  Prints the head of the documentation (i.e. the function signature)
  """
  def print_heading(string, use_ansi // IO.ANSI.terminal?, colors // IEx.Options.get(:colors)) do
    if use_ansi do
      write_doc_heading(string, colors)
    else
      IO.puts "* #{string}\n"
    end
    IEx.dont_display_result
  end

  defp write_doc_heading(heading, colors) do
    IO.puts IO.ANSI.reset
    width   = column_width()
    padding = div(width + String.length(heading), 2)
    heading = heading |> String.rjust(padding) |> String.ljust(width)
    write(:doc_title, heading, colors)
  end

  @doc """
  Prints the documentation body.
  """
  def print(doc, use_ansi // IO.ANSI.terminal?, colors // IEx.Options.get(:colors)) do
    if use_ansi do
      doc
      |> String.split(["\r\n","\n"], trim: false)
      |> Enum.map(&String.rstrip/1)
      |> process("", colors)
    else
      IO.puts doc
    end
    IEx.dont_display_result
  end

  defp process([], _indent, _colors), do: nil

  defp process(["# " <> heading | rest], _indent, colors) do
    write_h1(String.strip(heading), colors)
    process(rest, "", colors)
  end

  defp process(["## " <> heading | rest], _indent, colors) do
    write_h2(String.strip(heading), colors)
    process(rest, "", colors)
  end

  defp process(["### " <> heading | rest], indent, colors) do
    write_h3(String.strip(heading), indent, colors)
    process(rest, indent, colors)
  end

  defp process(["" | rest], indent, colors) do
    process(rest, indent, colors)
  end

  defp process(["    " <> line | rest], indent, colors) do
    process_code(rest, [line], indent, colors)
  end

  defp process([line | rest], indent, colors) do
    { stripped, count } = strip_spaces(line, 0)
    case stripped do
      <<bullet, ?\s, item :: binary >> when bullet in @bullets ->
        process_list(item, rest, count, indent, colors)
      _ ->
        process_text(rest, [line], indent, false, colors)
    end
  end

  defp strip_spaces(" " <> line, acc) do
    strip_spaces(line, acc + 1)
  end

  defp strip_spaces(rest, acc) do
    { rest, acc }
  end

  ## Headings

  defp write_h1(heading, colors) do
    write_h2(String.upcase(heading), colors)
  end

  defp write_h2(heading, colors) do
    write(:doc_headings, heading, colors)
  end

  defp write_h3(heading, indent, colors) do
    IO.write(indent)
    write(:doc_headings, heading, colors)
  end

  ## Lists

  defp process_list(line, rest, count, indent, colors) do
    IO.write indent <> "• "
    { contents, rest, done } = process_list_next(rest, count, false, [])
    process_text(contents, [line], indent <> "  ", true, colors)
    if done, do: IO.puts(IO.ANSI.reset)
    process(rest, indent, colors)
  end

  # Process the thing after a list item entry. It can be either:
  #
  # * Continuation of the list
  # * A nested list
  # * The end of the list
  #
  defp process_list_next([" " <> _ = line | rest], count, _done, acc) do
    case list_next(line, count) do
      :done    -> { Enum.reverse(acc), [line|rest], false }
      chopped  -> process_list_next(rest, count, false, [chopped|acc])
    end
  end

  defp process_list_next([<<bullet, ?\s, _ :: binary>> | _] = rest, _count, _done, acc) when bullet in @bullets do
    { Enum.reverse(acc), rest, false }
  end

  defp process_list_next(["" | rest], count, _done, acc) do
    process_list_next(rest, count, true, [""|acc])
  end

  defp process_list_next(rest, _count, done, acc) do
    { Enum.reverse(acc), rest, done }
  end

  defp list_next(<<bullet, ?\s, _ :: binary>>, 0) when bullet in @bullets, do: :done
  defp list_next(line, 0),          do: chop(line, 2)
  defp list_next(" " <> line, acc), do: list_next(line, acc - 1)
  defp list_next(line, _acc),       do: line

  defp chop(" " <> line, acc) when acc > 0, do: chop(line, acc - 1)
  defp chop(line, _acc), do: line

  ## Text (paragraphs / lists)

  defp process_text(doc=["" | _], para, indent, from_list, colors) do
    write_text(Enum.reverse(para), indent, from_list)
    process(doc, indent, colors)
  end

  defp process_text([], para, indent, from_list, _colors) do
    write_text(Enum.reverse(para), indent, from_list)
  end

  defp process_text([line | rest], para, indent, true, colors) do
    { stripped, count } = strip_spaces(line, 0)
    case stripped do
      <<bullet, ?\s, item :: binary>> when bullet in @bullets ->
        write_text(Enum.reverse(para), indent, true)
        process_list(item, rest, count, indent, colors)
      _ ->
        process_text(rest, [line | para], indent, true, colors)
    end
  end

  defp process_text([line | rest], para, indent, from_list, colors) do
    process_text(rest, [line | para], indent, from_list, colors)
  end

  defp write_text(lines, indent, from_list) do
    lines
    |> Enum.join(" ")
    |> handle_links
    |> handle_inline(nil, [], [])
    |> String.split(%r{\s})
    |> write_with_wrap(column_width() - size(indent), indent, from_list)

    unless from_list, do: IO.puts(IO.ANSI.reset)
  end

  ## Code blocks

  defp process_code([], code, indent, colors) do
    write_code(code, indent, colors)
  end

  # Blank line between code blocks
  defp process_code([ "", "    " <> line | rest ], code, indent, colors) do
    process_code(rest, [line, "" | code], indent, colors)
  end

  defp process_code([ "    " <> line | rest ], code, indent, colors) do
    process_code(rest, [line|code], indent, colors)
  end

  defp process_code(rest, code, indent, colors) do
    write_code(code, indent, colors)
    process(rest, indent, colors)
  end

  defp write_code(code, indent, colors) do
    write(:doc_code, "#{indent}┃ #{Enum.join(Enum.reverse(code), "\n#{indent}┃ ")}", colors)
  end

  ## Helpers

  defp write(style, string, colors // IEx.Options.get(:colors)) do
    color =  colors[style]
    enabled = colors[:enabled]
    seq_color = IO.ANSI.escape_fragment("%{#{color}}", enabled)
    seq_reset = IO.ANSI.escape_fragment("%{reset}", enabled)
    IO.puts seq_color <> string <> seq_reset
    IO.puts seq_reset
  end

  defp write_with_wrap([], _available, _indent, _first) do
    :ok
  end

  defp write_with_wrap(words, available, indent, first) do
    { words, rest } = take_words(words, available, [])
    IO.puts (if first, do: "", else: indent) <> Enum.join(words, " ")
    write_with_wrap(rest, available, indent, false)
  end

  defp take_words([word|words], available, acc) do
    available = available - length_without_escape(word, 0)

    cond do
      # It fits, take one for space and continue decreasing
      available > 0 ->
        take_words(words, available - 1, [word|acc])

      # No space but we got no words
      acc == [] ->
        { [word], words }

      # Otherwise
      true ->
        { Enum.reverse(acc), [word|words] }
    end
  end

  defp take_words([], _available, acc) do
    { Enum.reverse(acc), [] }
  end

  defp length_without_escape(<< ?\e, ?[, _, _, ?m, rest :: binary >>, count) do
    length_without_escape(rest, count)
  end

  defp length_without_escape(<< ?\e, ?[, _, ?m, rest :: binary >>, count) do
    length_without_escape(rest, count)
  end

  defp length_without_escape(rest, count) do
    case String.next_grapheme(rest) do
      :no_grapheme -> count
      { _, rest }  -> length_without_escape(rest, count + 1)
    end
  end

  defp handle_links(text) do
    text
    |> remove_square_brackets_in_link
    |> escape_underlines_in_link
  end

  defp escape_underlines_in_link(text) do
    case Regex.match?(%r{.*(https?\S*)}, text) do
      true ->
        Regex.replace(%r{_}, text, "\\\\_")
      _ ->
        text
    end
  end

  defp remove_square_brackets_in_link(text) do
    Regex.replace(%r{\[(.*?)\]\((.*?)\)}, text, "\\1 (\\2)")
  end

  # Single inline quotes.
  @single [?`, ?_, ?*]

  # ` does not require space in between
  @spaced [?_, ?*]

  # Clauses for handling spaces
  defp handle_inline(<<?*, ?*, ?\s, rest :: binary>>, nil, buffer, acc) do
    handle_inline(rest, nil, [?\s, ?*, ?*|buffer], acc)
  end

  defp handle_inline(<<mark, ?\s, rest :: binary>>, nil, buffer, acc) when mark in @spaced do
    handle_inline(rest, nil, [?\s, mark|buffer], acc)
  end

  defp handle_inline(<<?\s, ?*, ?*, rest :: binary>>, limit, buffer, acc) do
    handle_inline(rest, limit, [?*, ?*, ?\s|buffer], acc)
  end

  defp handle_inline(<<?\s, mark, rest :: binary>>, limit, buffer, acc) when mark in @spaced do
    handle_inline(rest, limit, [mark, ?\s|buffer], acc)
  end

  # Clauses for handling escape
  defp handle_inline(<<?\\, ?\\, rest :: binary>>, limit, buffer, acc) do
    handle_inline(rest, limit, [?\\|buffer], acc)
  end

  defp handle_inline(<<?\\, ?*, ?*, rest :: binary>>, limit, buffer, acc) do
    handle_inline(rest, limit, [?*, ?*|buffer], acc)
  end

  # A escape is not valid inside `
  defp handle_inline(<<?\\, mark, rest :: binary>>, limit, buffer, acc)
      when mark in [?_, ?*, ?`] and not(mark == limit and mark == ?`) do
    handle_inline(rest, limit, [mark|buffer], acc)
  end

  # Inline start
  defp handle_inline(<<?*, ?*, rest :: binary>>, nil, buffer, acc) when rest != "" do
    handle_inline(rest, ?d, ["**"], [Enum.reverse(buffer)|acc])
  end

  defp handle_inline(<<mark, rest :: binary>>, nil, buffer, acc) when rest != "" and mark in @single do
    handle_inline(rest, mark, [<<mark>>], [Enum.reverse(buffer)|acc])
  end

  # Inline end
  defp handle_inline(<<?*, ?*, rest :: binary>>, ?d, buffer, acc) do
    handle_inline(rest, nil, [], [inline_buffer(buffer)|acc])
  end

  defp handle_inline(<<mark, rest :: binary>>, mark, buffer, acc) when mark in @single do
    handle_inline(rest, nil, [], [inline_buffer(buffer)|acc])
  end

  defp handle_inline(<<char, rest :: binary>>, mark, buffer, acc) do
    handle_inline(rest, mark, [char|buffer], acc)
  end

  defp handle_inline(<<>>, _mark, buffer, acc) do
    iolist_to_binary Enum.reverse([Enum.reverse(buffer)|acc])
  end

  defp inline_buffer(buffer) do
    [h|t] = Enum.reverse([IO.ANSI.reset|buffer])
    [color_for(h)|t]
  end

  defp color_for("`"),  do: color(:doc_inline_code)
  defp color_for("_"),  do: color(:doc_underline)
  defp color_for("*"),  do: color(:doc_bold)
  defp color_for("**"), do: color(:doc_bold)

  defp color(color_name) do
    colors = IEx.Options.get(:colors)

    if colors[:enabled] do
      IO.ANSI.escape_fragment("%{#{colors[color_name]}}", true)
    else
      ""
    end
  end

  defp column_width() do
    case :io.columns do
      { :ok, width } -> min(width, 80)
      _              -> 80
    end
  end
end


Don't print `cd .` to shell (#5457)

Don't print `cd .` to shell (#5457)

defmodule Mix.Tasks.New do
  use Mix.Task

  import Mix.Generator

  @shortdoc "Creates a new Elixir project"

  @moduledoc """
  Creates a new Elixir project.
  It expects the path of the project as argument.

      mix new PATH [--sup] [--module MODULE] [--app APP] [--umbrella]

  A project at the given PATH will be created. The
  application name and module name will be retrieved
  from the path, unless `--module` or `--app` is given.

  A `--sup` option can be given to generate an OTP application
  skeleton including a supervision tree. Normally an app is
  generated without a supervisor and without the app callback.

  An `--umbrella` option can be given to generate an
  umbrella project.

  An `--app` option can be given in order to
  name the OTP application for the project.

  A `--module` option can be given in order
  to name the modules in the generated code skeleton.

  ## Examples

      mix new hello_world

  Is equivalent to:

      mix new hello_world --module HelloWorld

  To generate an app with a supervision tree and an application callback:

      mix new hello_world --sup

  """

  @switches [sup: :boolean, umbrella: :boolean, app: :string, module: :string]

  @spec run(OptionParser.argv) :: :ok
  def run(argv) do
    {opts, argv} = OptionParser.parse!(argv, strict: @switches)

    case argv do
      [] ->
        Mix.raise "Expected PATH to be given, please use \"mix new PATH\""
      [path | _] ->
        app = opts[:app] || Path.basename(Path.expand(path))
        check_application_name!(app, !opts[:app])
        mod = opts[:module] || Macro.camelize(app)
        check_mod_name_validity!(mod)
        check_mod_name_availability!(mod)
        unless path == "." do
          check_directory_existence!(path)
          File.mkdir_p!(path)
        end

        File.cd! path, fn ->
          if opts[:umbrella] do
            generate_umbrella(app, mod, path, opts)
          else
            generate(app, mod, path, opts)
          end
        end
    end
  end

  defp generate(app, mod, path, opts) do
    assigns = [app: app, mod: mod, otp_app: otp_app(mod, !!opts[:sup]),
               version: get_version(System.version)]

    create_file "README.md",  readme_template(assigns)
    create_file ".gitignore", gitignore_text()

    if in_umbrella?() do
      create_file "mix.exs", mixfile_apps_template(assigns)
    else
      create_file "mix.exs", mixfile_template(assigns)
    end

    create_directory "config"
    create_file "config/config.exs", config_template(assigns)

    create_directory "lib"
    create_file "lib/#{app}.ex", lib_template(assigns)

    if opts[:sup] do
      create_file "lib/#{app}/application.ex", lib_app_template(assigns)
    end

    create_directory "test"
    create_file "test/test_helper.exs", test_helper_template(assigns)
    create_file "test/#{app}_test.exs", test_template(assigns)

    """

    Your Mix project was created successfully.
    You can use "mix" to compile it, test it, and more:

        #{cd_path(path)}mix test

    Run "mix help" for more commands.
    """
    |> String.trim_trailing
    |> Mix.shell.info
  end

  defp otp_app(_mod, false) do
    "    [applications: [:logger]]"
  end

  defp otp_app(mod, true) do
    "    [applications: [:logger],\n     mod: {#{mod}.Application, []}]"
  end

  defp cd_path(".") do
    ""
  end

  defp cd_path(path) do
    "cd #{path}\n    "
  end

  defp generate_umbrella(_app, mod, path, _opts) do
    assigns = [app: nil, mod: mod]

    create_file ".gitignore", gitignore_text()
    create_file "README.md", readme_template(assigns)
    create_file "mix.exs", mixfile_umbrella_template(assigns)

    create_directory "apps"

    create_directory "config"
    create_file "config/config.exs", config_umbrella_template(assigns)

    """

    Your umbrella project was created successfully.
    Inside your project, you will find an apps/ directory
    where you can create and host many apps:

        #{cd_path(path)}cd apps
        mix new my_app

    Commands like "mix compile" and "mix test" when executed
    in the umbrella project root will automatically run
    for each application in the apps/ directory.
    """
    |> String.trim_trailing
    |> Mix.shell.info
  end

  defp check_application_name!(name, inferred?) do
    unless name =~ ~r/^[a-z][\w_]*$/ do
      Mix.raise "Application name must start with a letter and have only lowercase " <>
                "letters, numbers and underscore, got: #{inspect name}" <>
                (if inferred? do
                  ". The application name is inferred from the path, if you'd like to " <>
                  "explicitly name the application then use the \"--app APP\" option"
                else
                  ""
                end)
    end
  end

  defp check_mod_name_validity!(name) do
    unless name =~ ~r/^[A-Z]\w*(\.[A-Z]\w*)*$/ do
      Mix.raise "Module name must be a valid Elixir alias (for example: Foo.Bar), got: #{inspect name}"
    end
  end

  defp check_mod_name_availability!(name) do
    name = Module.concat(Elixir, name)
    if Code.ensure_loaded?(name) do
      Mix.raise "Module name #{inspect name} is already taken, please choose another name"
    end
  end

  defp check_directory_existence!(path) do
    if File.dir?(path) and not Mix.shell.yes?("The directory #{inspect(path)} already exists. Are you sure you want to continue?") do
      Mix.raise "Please select another directory for installation"
    end
  end

  defp get_version(version) do
    {:ok, version} = Version.parse(version)
    "#{version.major}.#{version.minor}" <>
      case version.pre do
        [h | _] -> "-#{h}"
        []      -> ""
      end
  end

  defp in_umbrella? do
    apps = Path.dirname(File.cwd!)

    try do
      Mix.Project.in_project(:umbrella_check, "../..", fn _ ->
        path = Mix.Project.config[:apps_path]
        path && Path.expand(path) == apps
      end)
    catch
      _, _ -> false
    end
  end

  embed_template :readme, """
  # <%= @mod %>

  **TODO: Add description**
  <%= if @app do %>
  ## Installation

  If [available in Hex](https://hex.pm/docs/publish), the package can be installed as:

    1. Add `<%= @app %>` to your list of dependencies in `mix.exs`:

      ```elixir
      def deps do
        [{:<%= @app %>, "~> 0.1.0"}]
      end
      ```

    2. Ensure `<%= @app %>` is started before your application:

      ```elixir
      def application do
        [applications: [:<%= @app %>]]
      end
      ```

  Documentation can be generated with [ExDoc](https://github.com/elixir-lang/ex_doc)
  and published on [HexDocs](https://hexdocs.pm). Once published, the docs can
  be found at [https://hexdocs.pm/<%= @app %>](https://hexdocs.pm/<%= @app %>).
  <% end %>
  """

  embed_text :gitignore, """
  # The directory Mix will write compiled artifacts to.
  /_build

  # If you run "mix test --cover", coverage assets end up here.
  /cover

  # The directory Mix downloads your dependencies sources to.
  /deps

  # Where 3rd-party dependencies like ExDoc output generated docs.
  /doc

  # If the VM crashes, it generates a dump, let's ignore it too.
  erl_crash.dump

  # Also ignore archive artifacts (built via "mix archive.build").
  *.ez

  # Ignore .fetch files in case you like to edit your project deps locally.
  /.fetch
  """

  embed_template :mixfile, """
  defmodule <%= @mod %>.Mixfile do
    use Mix.Project

    def project do
      [app: :<%= @app %>,
       version: "0.1.0",
       elixir: "~> <%= @version %>",
       build_embedded: Mix.env == :prod,
       start_permanent: Mix.env == :prod,
       deps: deps()]
    end

    # Configuration for the OTP application
    #
    # Type "mix help compile.app" for more information
    def application do
  <%= @otp_app %>
    end

    # Dependencies can be Hex packages:
    #
    #   {:my_dep, "~> 0.3.0"}
    #
    # Or git/path repositories:
    #
    #   {:my_dep, git: "https://github.com/elixir-lang/my_dep.git", tag: "0.1.0"}
    #
    # Type "mix help deps" for more examples and options
    defp deps do
      []
    end
  end
  """

  embed_template :mixfile_apps, """
  defmodule <%= @mod %>.Mixfile do
    use Mix.Project

    def project do
      [app: :<%= @app %>,
       version: "0.1.0",
       build_path: "../../_build",
       config_path: "../../config/config.exs",
       deps_path: "../../deps",
       lockfile: "../../mix.lock",
       elixir: "~> <%= @version %>",
       build_embedded: Mix.env == :prod,
       start_permanent: Mix.env == :prod,
       deps: deps()]
    end

    # Configuration for the OTP application
    #
    # Type "mix help compile.app" for more information
    def application do
  <%= @otp_app %>
    end

    # Dependencies can be Hex packages:
    #
    #   {:my_dep, "~> 0.3.0"}
    #
    # Or git/path repositories:
    #
    #   {:my_dep, git: "https://github.com/elixir-lang/my_dep.git", tag: "0.1.0"}
    #
    # To depend on another app inside the umbrella:
    #
    #   {:my_app, in_umbrella: true}
    #
    # Type "mix help deps" for more examples and options
    defp deps do
      []
    end
  end
  """

  embed_template :mixfile_umbrella, """
  defmodule <%= @mod %>.Mixfile do
    use Mix.Project

    def project do
      [apps_path: "apps",
       build_embedded: Mix.env == :prod,
       start_permanent: Mix.env == :prod,
       deps: deps()]
    end

    # Dependencies can be Hex packages:
    #
    #   {:my_dep, "~> 0.3.0"}
    #
    # Or git/path repositories:
    #
    #   {:my_dep, git: "https://github.com/elixir-lang/my_dep.git", tag: "0.1.0"}
    #
    # Type "mix help deps" for more examples and options.
    #
    # Dependencies listed here are available only for this project
    # and cannot be accessed from applications inside the apps folder
    defp deps do
      []
    end
  end
  """

  embed_template :config, ~S"""
  # This file is responsible for configuring your application
  # and its dependencies with the aid of the Mix.Config module.
  use Mix.Config

  # This configuration is loaded before any dependency and is restricted
  # to this project. If another project depends on this project, this
  # file won't be loaded nor affect the parent project. For this reason,
  # if you want to provide default values for your application for
  # 3rd-party users, it should be done in your "mix.exs" file.

  # You can configure for your application as:
  #
  #     config :<%= @app %>, key: :value
  #
  # And access this configuration in your application as:
  #
  #     Application.get_env(:<%= @app %>, :key)
  #
  # Or configure a 3rd-party app:
  #
  #     config :logger, level: :info
  #

  # It is also possible to import configuration files, relative to this
  # directory. For example, you can emulate configuration per environment
  # by uncommenting the line below and defining dev.exs, test.exs and such.
  # Configuration from the imported file will override the ones defined
  # here (which is why it is important to import them last).
  #
  #     import_config "#{Mix.env}.exs"
  """

  embed_template :config_umbrella, ~S"""
  # This file is responsible for configuring your application
  # and its dependencies with the aid of the Mix.Config module.
  use Mix.Config

  # By default, the umbrella project as well as each child
  # application will require this configuration file, ensuring
  # they all use the same configuration. While one could
  # configure all applications here, we prefer to delegate
  # back to each application for organization purposes.
  import_config "../apps/*/config/config.exs"

  # Sample configuration (overrides the imported configuration above):
  #
  #     config :logger, :console,
  #       level: :info,
  #       format: "$date $time [$level] $metadata$message\n",
  #       metadata: [:user_id]
  """

  embed_template :lib, """
  defmodule <%= @mod %> do
    @moduledoc \"""
    Documentation for <%= @mod %>.
    \"""

    @doc \"""
    Hello world.

    ## Examples

        iex> <%= @mod %>.hello
        :world

    \"""
    def hello do
      :world
    end
  end
  """

  embed_template :lib_app, """
  defmodule <%= @mod %>.Application do
    # See http://elixir-lang.org/docs/stable/elixir/Application.html
    # for more information on OTP Applications
    @moduledoc false

    use Application

    def start(_type, _args) do
      import Supervisor.Spec, warn: false

      # Define workers and child supervisors to be supervised
      children = [
        # Starts a worker by calling: <%= @mod %>.Worker.start_link(arg1, arg2, arg3)
        # worker(<%= @mod %>.Worker, [arg1, arg2, arg3]),
      ]

      # See http://elixir-lang.org/docs/stable/elixir/Supervisor.html
      # for other strategies and supported options
      opts = [strategy: :one_for_one, name: <%= @mod %>.Supervisor]
      Supervisor.start_link(children, opts)
    end
  end
  """

  embed_template :test, """
  defmodule <%= @mod %>Test do
    use ExUnit.Case
    doctest <%= @mod %>

    test "the truth" do
      assert 1 + 1 == 2
    end
  end
  """

  embed_template :test_helper, """
  ExUnit.start()
  """
end

defmodule Mix.Tasks.New do
  use Mix.Task

  import Mix.Generator

  @shortdoc "Creates a new Elixir project"

  @moduledoc """
  Creates a new Elixir project.
  It expects the path of the project as argument.

      mix new PATH [--sup] [--module MODULE] [--app APP] [--umbrella]

  A project at the given PATH will be created. The
  application name and module name will be retrieved
  from the path, unless `--module` or `--app` is given.

  A `--sup` option can be given to generate an OTP application
  skeleton including a supervision tree. Normally an app is
  generated without a supervisor and without the app callback.

  An `--umbrella` option can be given to generate an
  umbrella project.

  An `--app` option can be given in order to
  name the OTP application for the project.

  A `--module` option can be given in order
  to name the modules in the generated code skeleton.

  ## Examples

      mix new hello_world

  Is equivalent to:

      mix new hello_world --module HelloWorld

  To generate an app with a supervision tree and an application callback:

      mix new hello_world --sup

  """

  @switches [sup: :boolean, umbrella: :boolean, app: :string, module: :string]

  @spec run(OptionParser.argv) :: :ok
  def run(argv) do
    {opts, argv} = OptionParser.parse!(argv, strict: @switches)

    case argv do
      [] ->
        Mix.raise "Expected PATH to be given, please use \"mix new PATH\""
      [path | _] ->
        app = opts[:app] || Path.basename(Path.expand(path))
        check_application_name!(app, !opts[:app])
        mod = opts[:module] || Macro.camelize(app)
        check_mod_name_validity!(mod)
        check_mod_name_availability!(mod)
        unless path == "." do
          check_directory_existence!(path)
          File.mkdir_p!(path)
        end

        File.cd! path, fn ->
          if opts[:umbrella] do
            generate_umbrella(app, mod, path, opts)
          else
            generate(app, mod, path, opts)
          end
        end
    end
  end

  defp generate(app, mod, path, opts) do
    assigns = [app: app, mod: mod, otp_app: otp_app(mod, !!opts[:sup]),
               version: get_version(System.version)]

    create_file "README.md",  readme_template(assigns)
    create_file ".gitignore", gitignore_text()

    if in_umbrella?() do
      create_file "mix.exs", mixfile_apps_template(assigns)
    else
      create_file "mix.exs", mixfile_template(assigns)
    end

    create_directory "config"
    create_file "config/config.exs", config_template(assigns)

    create_directory "lib"
    create_file "lib/#{app}.ex", lib_template(assigns)

    if opts[:sup] do
      create_file "lib/#{app}/application.ex", lib_app_template(assigns)
    end

    create_directory "test"
    create_file "test/test_helper.exs", test_helper_template(assigns)
    create_file "test/#{app}_test.exs", test_template(assigns)

    """

    Your Mix project was created successfully.
    You can use "mix" to compile it, test it, and more:

        cd #{path}
        mix test

    Run "mix help" for more commands.
    """
    |> String.trim_trailing
    |> Mix.shell.info
  end

  defp otp_app(_mod, false) do
    "    [applications: [:logger]]"
  end

  defp otp_app(mod, true) do
    "    [applications: [:logger],\n     mod: {#{mod}.Application, []}]"
  end

  defp generate_umbrella(_app, mod, path, _opts) do
    assigns = [app: nil, mod: mod]

    create_file ".gitignore", gitignore_text()
    create_file "README.md", readme_template(assigns)
    create_file "mix.exs", mixfile_umbrella_template(assigns)

    create_directory "apps"

    create_directory "config"
    create_file "config/config.exs", config_umbrella_template(assigns)

    """

    Your umbrella project was created successfully.
    Inside your project, you will find an apps/ directory
    where you can create and host many apps:

        cd #{path}
        cd apps
        mix new my_app

    Commands like "mix compile" and "mix test" when executed
    in the umbrella project root will automatically run
    for each application in the apps/ directory.
    """
    |> String.trim_trailing
    |> Mix.shell.info
  end

  defp check_application_name!(name, inferred?) do
    unless name =~ ~r/^[a-z][\w_]*$/ do
      Mix.raise "Application name must start with a letter and have only lowercase " <>
                "letters, numbers and underscore, got: #{inspect name}" <>
                (if inferred? do
                  ". The application name is inferred from the path, if you'd like to " <>
                  "explicitly name the application then use the \"--app APP\" option"
                else
                  ""
                end)
    end
  end

  defp check_mod_name_validity!(name) do
    unless name =~ ~r/^[A-Z]\w*(\.[A-Z]\w*)*$/ do
      Mix.raise "Module name must be a valid Elixir alias (for example: Foo.Bar), got: #{inspect name}"
    end
  end

  defp check_mod_name_availability!(name) do
    name = Module.concat(Elixir, name)
    if Code.ensure_loaded?(name) do
      Mix.raise "Module name #{inspect name} is already taken, please choose another name"
    end
  end

  defp check_directory_existence!(path) do
    if File.dir?(path) and not Mix.shell.yes?("The directory #{inspect(path)} already exists. Are you sure you want to continue?") do
      Mix.raise "Please select another directory for installation"
    end
  end

  defp get_version(version) do
    {:ok, version} = Version.parse(version)
    "#{version.major}.#{version.minor}" <>
      case version.pre do
        [h | _] -> "-#{h}"
        []      -> ""
      end
  end

  defp in_umbrella? do
    apps = Path.dirname(File.cwd!)

    try do
      Mix.Project.in_project(:umbrella_check, "../..", fn _ ->
        path = Mix.Project.config[:apps_path]
        path && Path.expand(path) == apps
      end)
    catch
      _, _ -> false
    end
  end

  embed_template :readme, """
  # <%= @mod %>

  **TODO: Add description**
  <%= if @app do %>
  ## Installation

  If [available in Hex](https://hex.pm/docs/publish), the package can be installed as:

    1. Add `<%= @app %>` to your list of dependencies in `mix.exs`:

      ```elixir
      def deps do
        [{:<%= @app %>, "~> 0.1.0"}]
      end
      ```

    2. Ensure `<%= @app %>` is started before your application:

      ```elixir
      def application do
        [applications: [:<%= @app %>]]
      end
      ```

  Documentation can be generated with [ExDoc](https://github.com/elixir-lang/ex_doc)
  and published on [HexDocs](https://hexdocs.pm). Once published, the docs can
  be found at [https://hexdocs.pm/<%= @app %>](https://hexdocs.pm/<%= @app %>).
  <% end %>
  """

  embed_text :gitignore, """
  # The directory Mix will write compiled artifacts to.
  /_build

  # If you run "mix test --cover", coverage assets end up here.
  /cover

  # The directory Mix downloads your dependencies sources to.
  /deps

  # Where 3rd-party dependencies like ExDoc output generated docs.
  /doc

  # If the VM crashes, it generates a dump, let's ignore it too.
  erl_crash.dump

  # Also ignore archive artifacts (built via "mix archive.build").
  *.ez

  # Ignore .fetch files in case you like to edit your project deps locally.
  /.fetch
  """

  embed_template :mixfile, """
  defmodule <%= @mod %>.Mixfile do
    use Mix.Project

    def project do
      [app: :<%= @app %>,
       version: "0.1.0",
       elixir: "~> <%= @version %>",
       build_embedded: Mix.env == :prod,
       start_permanent: Mix.env == :prod,
       deps: deps()]
    end

    # Configuration for the OTP application
    #
    # Type "mix help compile.app" for more information
    def application do
  <%= @otp_app %>
    end

    # Dependencies can be Hex packages:
    #
    #   {:my_dep, "~> 0.3.0"}
    #
    # Or git/path repositories:
    #
    #   {:my_dep, git: "https://github.com/elixir-lang/my_dep.git", tag: "0.1.0"}
    #
    # Type "mix help deps" for more examples and options
    defp deps do
      []
    end
  end
  """

  embed_template :mixfile_apps, """
  defmodule <%= @mod %>.Mixfile do
    use Mix.Project

    def project do
      [app: :<%= @app %>,
       version: "0.1.0",
       build_path: "../../_build",
       config_path: "../../config/config.exs",
       deps_path: "../../deps",
       lockfile: "../../mix.lock",
       elixir: "~> <%= @version %>",
       build_embedded: Mix.env == :prod,
       start_permanent: Mix.env == :prod,
       deps: deps()]
    end

    # Configuration for the OTP application
    #
    # Type "mix help compile.app" for more information
    def application do
  <%= @otp_app %>
    end

    # Dependencies can be Hex packages:
    #
    #   {:my_dep, "~> 0.3.0"}
    #
    # Or git/path repositories:
    #
    #   {:my_dep, git: "https://github.com/elixir-lang/my_dep.git", tag: "0.1.0"}
    #
    # To depend on another app inside the umbrella:
    #
    #   {:my_app, in_umbrella: true}
    #
    # Type "mix help deps" for more examples and options
    defp deps do
      []
    end
  end
  """

  embed_template :mixfile_umbrella, """
  defmodule <%= @mod %>.Mixfile do
    use Mix.Project

    def project do
      [apps_path: "apps",
       build_embedded: Mix.env == :prod,
       start_permanent: Mix.env == :prod,
       deps: deps()]
    end

    # Dependencies can be Hex packages:
    #
    #   {:my_dep, "~> 0.3.0"}
    #
    # Or git/path repositories:
    #
    #   {:my_dep, git: "https://github.com/elixir-lang/my_dep.git", tag: "0.1.0"}
    #
    # Type "mix help deps" for more examples and options.
    #
    # Dependencies listed here are available only for this project
    # and cannot be accessed from applications inside the apps folder
    defp deps do
      []
    end
  end
  """

  embed_template :config, ~S"""
  # This file is responsible for configuring your application
  # and its dependencies with the aid of the Mix.Config module.
  use Mix.Config

  # This configuration is loaded before any dependency and is restricted
  # to this project. If another project depends on this project, this
  # file won't be loaded nor affect the parent project. For this reason,
  # if you want to provide default values for your application for
  # 3rd-party users, it should be done in your "mix.exs" file.

  # You can configure for your application as:
  #
  #     config :<%= @app %>, key: :value
  #
  # And access this configuration in your application as:
  #
  #     Application.get_env(:<%= @app %>, :key)
  #
  # Or configure a 3rd-party app:
  #
  #     config :logger, level: :info
  #

  # It is also possible to import configuration files, relative to this
  # directory. For example, you can emulate configuration per environment
  # by uncommenting the line below and defining dev.exs, test.exs and such.
  # Configuration from the imported file will override the ones defined
  # here (which is why it is important to import them last).
  #
  #     import_config "#{Mix.env}.exs"
  """

  embed_template :config_umbrella, ~S"""
  # This file is responsible for configuring your application
  # and its dependencies with the aid of the Mix.Config module.
  use Mix.Config

  # By default, the umbrella project as well as each child
  # application will require this configuration file, ensuring
  # they all use the same configuration. While one could
  # configure all applications here, we prefer to delegate
  # back to each application for organization purposes.
  import_config "../apps/*/config/config.exs"

  # Sample configuration (overrides the imported configuration above):
  #
  #     config :logger, :console,
  #       level: :info,
  #       format: "$date $time [$level] $metadata$message\n",
  #       metadata: [:user_id]
  """

  embed_template :lib, """
  defmodule <%= @mod %> do
    @moduledoc \"""
    Documentation for <%= @mod %>.
    \"""

    @doc \"""
    Hello world.

    ## Examples

        iex> <%= @mod %>.hello
        :world

    \"""
    def hello do
      :world
    end
  end
  """

  embed_template :lib_app, """
  defmodule <%= @mod %>.Application do
    # See http://elixir-lang.org/docs/stable/elixir/Application.html
    # for more information on OTP Applications
    @moduledoc false

    use Application

    def start(_type, _args) do
      import Supervisor.Spec, warn: false

      # Define workers and child supervisors to be supervised
      children = [
        # Starts a worker by calling: <%= @mod %>.Worker.start_link(arg1, arg2, arg3)
        # worker(<%= @mod %>.Worker, [arg1, arg2, arg3]),
      ]

      # See http://elixir-lang.org/docs/stable/elixir/Supervisor.html
      # for other strategies and supported options
      opts = [strategy: :one_for_one, name: <%= @mod %>.Supervisor]
      Supervisor.start_link(children, opts)
    end
  end
  """

  embed_template :test, """
  defmodule <%= @mod %>Test do
    use ExUnit.Case
    doctest <%= @mod %>

    test "the truth" do
      assert 1 + 1 == 2
    end
  end
  """

  embed_template :test_helper, """
  ExUnit.start()
  """
end


Fix a terrible syntax error

Fix a terrible syntax error

I am the worst human being.

defmodule Redix.Auth do
  @moduledoc false

  # This module is responsible for providing functions to perform authentication
  # and db selection on Redis (AUTH and SELECT).

  alias Redix.Protocol

  @doc """
  Authenticates and selects the right database based on the state `state`.

  This function checks the given options to see if a password and/or a database
  are specified. If a password is specified, then this function will send the
  appropriate `AUTH` command to the Redis connection in `state.socket`. If a
  database is specified, then the appropriate `SELECT` command will be issued.

  The socket is expected to be in passive mode, and will be returned in passive
  mode to the caller.
  """
  @spec auth_and_select_db(:gen_tcp.socket, Keyword.t) :: {:ok, binary} | {:error, term}
  def auth_and_select_db(socket, opts) when is_list(opts) do
    with {:ok, tail} <- auth(socket, opts[:password]),
         do: select_db(socket, opts[:database], tail)
  end

  @spec auth(:gen_tcp.socket, nil | binary) :: {:ok | binary} | {:error, term}
  defp auth(socket, password)

  defp auth(_socket, nil) do
    {:ok, ""}
  end

  defp auth(socket, password) when is_binary(password) do
    with :ok <- :gen_tcp.send(socket, Protocol.pack(["AUTH", password])) do
      case blocking_recv(socket, "") do
        {:ok, "OK", tail} ->
          {:ok, tail}
        {:ok, error, _tail} ->
          {:error, error}
        {:error, _reason} = error ->
          error
      end
    end
  end

  @spec select_db(:gen_tcp.socket, nil | non_neg_integer | binary, binary) :: {:ok, binary} | {:error, term}
  defp select_db(socket, db, tail)

  defp select_db(_socket, nil, tail) do
    {:ok, tail}
  end

  defp select_db(socket, db, tail) do
    with :ok <- :gen_tcp.send(socket, Protocol.pack(["SELECT", db])) do
      case blocking_recv(socket, tail) do
        {:ok, "OK", tail} ->
          {:ok, tail}
        {:ok, error, _state} ->
          {:error, error}
        {:error, _reason} = error ->
          error
      end
    end
  end

  @spec blocking_recv(:gen_tcp.socket, binary, nil | (binary -> term)) :: {:ok, term, binary} | {:error, term}
  defp blocking_recv(socket, tail, continuation \\ nil) do
    with {:ok, data} <- :gen_tcp.recv(socket, 0) do
      parser = continuation || &Protocol.parse/1
      case parser.(tail <> data) do
        {:ok, _resp, _rest} = result ->
          result
        {:continuation, continuation} ->
          blocking_recv(socket, "", continuation)
      end
    end
  end
end

defmodule Redix.Auth do
  @moduledoc false

  # This module is responsible for providing functions to perform authentication
  # and db selection on Redis (AUTH and SELECT).

  alias Redix.Protocol

  @doc """
  Authenticates and selects the right database based on the state `state`.

  This function checks the given options to see if a password and/or a database
  are specified. If a password is specified, then this function will send the
  appropriate `AUTH` command to the Redis connection in `state.socket`. If a
  database is specified, then the appropriate `SELECT` command will be issued.

  The socket is expected to be in passive mode, and will be returned in passive
  mode to the caller.
  """
  @spec auth_and_select_db(:gen_tcp.socket, Keyword.t) :: {:ok, binary} | {:error, term}
  def auth_and_select_db(socket, opts) when is_list(opts) do
    with {:ok, tail} <- auth(socket, opts[:password]),
         do: select_db(socket, opts[:database], tail)
  end

  @spec auth(:gen_tcp.socket, nil | binary) :: {:ok | binary} | {:error, term}
  defp auth(socket, password)

  defp auth(_socket, nil) do
    {:ok, ""}
  end

  defp auth(socket, password) when is_binary(password) do
    with :ok <- :gen_tcp.send(socket, Protocol.pack(["AUTH", password])),
      case blocking_recv(socket, "") do
        {:ok, "OK", tail} ->
          {:ok, tail}
        {:ok, error, _tail} ->
          {:error, error}
        {:error, _reason} = error ->
          error
      end
    end
  end

  @spec select_db(:gen_tcp.socket, nil | non_neg_integer | binary, binary) :: {:ok, binary} | {:error, term}
  defp select_db(socket, db, tail)

  defp select_db(_socket, nil, tail) do
    {:ok, tail}
  end

  defp select_db(socket, db, tail) do
    with :ok <- :gen_tcp.send(socket, Protocol.pack(["SELECT", db])) do
      case blocking_recv(socket, tail) do
        {:ok, "OK", tail} ->
          {:ok, tail}
        {:ok, error, _state} ->
          {:error, error}
        {:error, _reason} = error ->
          error
      end
    end
  end

  @spec blocking_recv(:gen_tcp.socket, binary, nil | (binary -> term)) :: {:ok, term, binary} | {:error, term}
  defp blocking_recv(socket, tail, continuation \\ nil) do
    with {:ok, data} <- :gen_tcp.recv(socket, 0) do
      parser = continuation || &Protocol.parse/1
      case parser.(tail <> data) do
        {:ok, _resp, _rest} = result ->
          result
        {:continuation, continuation} ->
          blocking_recv(socket, "", continuation)
      end
    end
  end
end


Remove temporary production logging used to identify problematic data

defmodule RemoteRetroWeb.UserManagement do
  alias RemoteRetro.{User, Mailer, Emails}

  def handle_google_oauth(oauth_info) do
    case User.upsert_record_from(oauth_info: oauth_info) do
      {:ok, user, :inserted} ->
        Emails.welcome_email(user) |> Mailer.deliver_now()
        {:ok, user}

      {:ok, user, :updated} ->
        {:ok, user}
    end
  end
end

defmodule RemoteRetroWeb.UserManagement do
  alias RemoteRetro.{User, Mailer, Emails}

  def handle_google_oauth(oauth_info) do
    if Application.get_env(:remote_retro, :env) !== :test do
      IO.inspect oauth_info
    end

    case User.upsert_record_from(oauth_info: oauth_info) do
      {:ok, user, :inserted} ->
        Emails.welcome_email(user) |> Mailer.deliver_now()
        {:ok, user}

      {:ok, user, :updated} ->
        {:ok, user}
    end
  end
end