Current section

Files

Jump to
progress_bar lib progress_bar.ex
Raw

lib/progress_bar.ex

defmodule ProgressBar do
@ansi_clear_line "\e[2K"
@default_format [
bar: "=",
blank: " ",
left: "|",
right: "|",
percent: true,
bytes: false,
bar_color: [],
blank_color: [],
]
def render(current, total, custom_format \\ @default_format) do
format = Keyword.merge(@default_format, custom_format)
percent = current / total * 100 |> Float.round |> trunc
bar = String.duplicate(format[:bar], percent)
blank = String.duplicate(format[:blank], 100 - percent)
IO.write [
@ansi_clear_line, # So a shorter line can replace a previous, longer line.
"\r", # Back to beginning of line.
format[:left],
color(bar, format[:bar_color]),
color(blank, format[:blank_color]),
format[:right],
formatted_percent(format[:percent], percent),
bytes(format[:bytes], current, total),
newline_if_complete(current, total),
]
end
# Private
defp color(content, []), do: content
defp color(content, ansi_codes) do
[ ansi_codes, content, IO.ANSI.reset ]
end
defp formatted_percent(false, _), do: ""
defp formatted_percent(true, number) do
" " <> String.rjust(Integer.to_string(number), 3) <> "%"
end
defp bytes(false, _, _), do: ""
defp bytes(true, total, total) do
" (#{mb total} MB)"
end
defp bytes(true, current, total) do
" (#{mb current}/#{mb total} MB)"
end
defp mb(bytes) do
bytes / 1_048_576 |> Float.round(2)
end
defp newline_if_complete(total, total), do: "\n"
defp newline_if_complete(_, _), do: ""
end