Packages
io_ansi_plus
0.1.49
0.1.84
0.1.83
0.1.82
0.1.81
0.1.80
0.1.79
0.1.78
0.1.77
0.1.76
0.1.73
0.1.72
0.1.71
0.1.70
0.1.69
0.1.68
0.1.67
0.1.66
0.1.65
0.1.63
0.1.62
0.1.61
0.1.60
0.1.59
0.1.58
0.1.57
0.1.56
0.1.55
0.1.54
0.1.53
0.1.52
0.1.51
0.1.50
0.1.49
0.1.48
0.1.47
0.1.46
0.1.45
0.1.44
0.1.43
0.1.41
0.1.40
0.1.39
0.1.38
0.1.37
0.1.36
0.1.35
0.1.34
0.1.33
0.1.32
0.1.31
0.1.30
0.1.29
0.1.28
0.1.27
0.1.26
0.1.25
0.1.24
0.1.23
0.1.22
0.1.21
0.1.20
0.1.19
0.1.18
0.1.17
0.1.16
0.1.15
0.1.14
0.1.13
0.1.12
0.1.11
0.1.10
0.1.9
0.1.8
0.1.7
0.1.6
0.1.5
0.1.4
0.1.3
0.1.2
0.1.1
0.1.0
Functionality to render ANSI escape sequences. Clone of module IO.ANSI but supporting named xterm colors.
Current section
Files
Jump to
Current section
Files
lib/io/ansi/plus/ie.ex
defmodule IO.ANSI.Plus.IE do
@moduledoc false
use PersistConfig
alias IO.ANSI.Plus, as: ANSI
@colors get_env(:colors)
defmacro __using__(_options) do
quote do
import unquote(__MODULE__)
alias unquote(__MODULE__)
alias IO.ANSI.Plus, as: ANSI
:ok
end
end
@spec color_samples :: [String.t()]
def color_samples do
for %{code: code, hex: hex, names: names} <- @colors do
"-  #{color_sample_names(code, names)} (#{code})"
end
end
@spec delete_color_samples :: map
def delete_color_samples do
results =
for %{hex: hex} <- @colors do
{File.rm("images/#{hex}.png"), hex}
end
reduce(results)
end
# @spec write_color_samples :: map
# def write_color_samples do
# image = :egd.create(12, 12)
# results =
# for %{hex: hex, rgb: rbg} <- @colors do
# fill = :egd.color(rbg)
# :ok = :egd.filledRectangle(image, {0, 0}, {12, 12}, fill)
# binary = :egd.render(image)
# {File.write("images/#{hex}.png", binary), hex}
# end
# :ok = :egd.destroy(image)
# reduce(results)
# end
@spec print_color_samples :: :ok
def print_color_samples do
color_samples() |> Enum.each(&IO.puts/1)
end
@spec print_standard_colors(pos_integer, pos_integer) :: :ok
def print_standard_colors(squares_per_row, column_width) do
for row <- standard_color_rows(squares_per_row) do
Enum.each(row, &print_square(&1, column_width, _with_code? = false))
IO.write("\n")
end
IO.write("\n")
end
@spec print_xterm_colors(Range.t(), pos_integer, pos_integer) :: :ok
def print_xterm_colors(%Range{} = range, squares_per_row, column_width) do
for row <- xterm_color_rows(range, squares_per_row) do
Enum.each(row, &print_square(&1, column_width, _with_code? = true))
IO.write("\n")
end
IO.write("\n")
end
@spec print_color_chart :: :ok
def print_color_chart do
IO.write("\n")
print_standard_colors(8, 12)
print_xterm_colors(0..15, 8, 12)
print_xterm_colors(16..255, 6, 18)
end
@spec names_for_code(0..255) :: [atom]
def names_for_code(code) when code in 0..255 do
names =
Enum.find_value(@colors, fn %{code: color_code, names: names} ->
if color_code == code, do: names
end)
if code in 0..15 do
[standard_color_names() |> Enum.at(code) | names]
else
if(Enum.empty?(names), do: [:"color#{code}"], else: names)
end
end
## Private functions
@spec reduce([...]) :: map
defp reduce(results) do
Enum.reduce(results, %{}, fn
{:ok, _name}, acc ->
Map.update(acc, :ok, 1, &(&1 + 1))
{{:error, reason}, name}, acc ->
Map.update(acc, reason, {1, [name]}, fn {n, names} ->
{n + 1, [name | names]}
end)
end)
end
@spec fave_names :: %{non_neg_integer => atom}
defp fave_names do
Enum.reduce(@colors, %{}, fn
%{code: _code, names: []}, acc -> acc
%{code: code, names: [name | _]}, acc -> Map.put(acc, code, name)
end)
end
@spec standard_color_rows(pos_integer) :: [keyword(non_neg_integer)]
defp standard_color_rows(squares_per_row) do
standard_color_names()
|> Enum.with_index()
|> Enum.chunk_every(squares_per_row)
end
@spec standard_color_names :: [atom]
defp standard_color_names do
names = [:black, :red, :green, :yellow, :blue, :magenta, :cyan, :white]
lites = Enum.map(names, fn name -> :"light_#{name}" end)
names ++ lites
end
@spec xterm_color_rows(Range.t(), pos_integer) :: [keyword(non_neg_integer)]
defp xterm_color_rows(%Range{} = range, squares_per_row) do
for i <- range do
if fave_names()[i], do: {fave_names()[i], i}, else: {:"color#{i}", i}
end
|> Enum.chunk_every(squares_per_row)
end
@spec print_square({atom, non_neg_integer}, pos_integer, boolean) :: :ok
defp print_square({name, code}, column_width, with_code?) do
[
background(name),
foreground(code),
text(name, code, column_width, with_code?)
]
|> ANSI.write()
end
@spec background(atom) :: atom
defp background(name), do: :"#{name}_background"
@spec black_foreground_codes :: [non_neg_integer]
defp black_foreground_codes do
[7, 10, 11, 14, 15] ++
Enum.to_list(34..51) ++
Enum.to_list(70..87) ++
Enum.to_list(106..123) ++
Enum.to_list(142..159) ++
Enum.to_list(178..195) ++ Enum.to_list(214..231) ++ Enum.to_list(244..255)
end
defp foreground(code) do
if code in black_foreground_codes(), do: :black, else: :light_white
end
@spec adjust_text(String.t(), pos_integer) :: String.t()
defp adjust_text(text, column_width) do
if String.length(text) > column_width - 1 do
String.slice(text, 0..(column_width - 3)) <> "…"
else
text
end
|> String.pad_trailing(column_width)
end
@spec text(atom, non_neg_integer, pos_integer, boolean) :: String.t()
defp text(name, _code, column_width, _with_code? = false) do
"#{inspect(name)}" |> adjust_text(column_width)
end
defp text(name, code, column_width, _with_code?) do
text = "#{inspect(name)} (#{code})"
if String.length(text) > column_width - 1 do
"#{inspect(name)}"
else
text
end
|> adjust_text(column_width)
end
@spec color_sample_names(non_neg_integer, [atom]) :: String.t()
defp color_sample_names(code, _names = []) do
if code in 0..15 do
"`#{standard_color_names() |> Enum.at(code) |> inspect()}`"
else
"`:color#{code}`"
end
end
defp color_sample_names(code, names) do
names =
if code in 0..15 do
[standard_color_names() |> Enum.at(code) | names]
else
names
end
names
|> Enum.reduce("", fn name, acc -> acc <> "`#{inspect(name)}` " end)
|> String.trim_trailing()
end
end