Current section
Files
Jump to
Current section
Files
lib/anansi.ex
defmodule Anansi do
@moduledoc """
Utilities to generate ANSI control code instructions.
[ANSI escape codes](https://en.wikipedia.org/wiki/ANSI_escape_code) are
strings that can be sent to the terminal to instruct it on how to control its
screen, pager, cursor, and the formatting, font, and color of the text it displays.
When these instructions are written to STDOUT, they affect the way the terminal behaves.
"""
import Anansi.Sequence, only: [compose: 1]
@doc """
Detects if ANSI is currently supported (STDIN and STDOUT are ttys).
"""
def enabled? do
Application.get_env(:elixir, :ansi_enabled, false)
end
@doc """
Generates an instruction from the given `codes` and `terminal` code.
"""
def escape(codes \\ [], terminal) do
"\e[" <> Enum.map_join(List.wrap(codes), ";", &to_string/1) <> terminal
end
@doc """
Generates an ANSI instruction that applies the given `setting` to `control`.
"""
def instruction(control, setting)
####
# TEXT RESET
##
def instruction(:text, :reset) do
escape 0, "m"
end
####
# TEXT FORMATS
##
def instruction(:bold, :on) do
escape 1, "m"
end
def instruction(:bold, :off) do
escape 21, "m"
end
def instruction(:faint, :on) do
escape 2, "m"
end
def instruction(:faint, :off) do
escape 22, "m"
end
def instruction(:italic, :on) do
escape 3, "m"
end
def instruction(:italic, :off) do
escape 23, "m"
end
def instruction(:underline, :on) do
escape 4, "m"
end
def instruction(:underline, :off) do
escape 24, "m"
end
def instruction(:blink, :slow) do
escape 5, "m"
end
def instruction(:blink, :fast) do
escape 6, "m"
end
def instruction(:blink, :off) do
escape 25, "m"
end
def instruction(:invert, :on) do
escape 7, "m"
end
def instruction(:invert, :off) do
escape 27, "m"
end
def instruction(:conceal, :on) do
escape 8, "m"
end
def instruction(:conceal, :off) do
escape 28, "m"
end
def instruction(:strikethrough, :on) do
escape 9, "m"
end
def instruction(:strikethrough, :off) do
escape 29, "m"
end
####
# FONTS
##
def instruction(:font, type) when type in 0..9 do
escape type + 10, "m"
end
####
# FORGROUND COLORS
##
def instruction(:foreground, :black) do
escape 30, "m"
end
def instruction(:foreground, :red) do
escape 31, "m"
end
def instruction(:foreground, :green) do
escape 32, "m"
end
def instruction(:foreground, :yellow) do
escape 33, "m"
end
def instruction(:foreground, :blue) do
escape 34, "m"
end
def instruction(:foreground, :magenta) do
escape 35, "m"
end
def instruction(:foreground, :cyan) do
escape 36, "m"
end
def instruction(:foreground, :white) do
escape 37, "m"
end
def instruction(:foreground, {r, g, b}) when r in 0..255 and g in 0..255 and b in 0..255 do
escape [38, r, g, b], "m"
end
def instruction(:foreground, num) when num in 0..255 do
escape [38, num], "m"
end
def instruction(:foreground, :default) do
escape 39, "m"
end
####
# BACKGROUND COLORS
##
def instruction(:background, :black) do
escape 40, "m"
end
def instruction(:background, :red) do
escape 41, "m"
end
def instruction(:background, :green) do
escape 42, "m"
end
def instruction(:background, :yellow) do
escape 43, "m"
end
def instruction(:background, :blue) do
escape 44, "m"
end
def instruction(:background, :magenta) do
escape 45, "m"
end
def instruction(:background, :cyan) do
escape 46, "m"
end
def instruction(:background, :white) do
escape 47, "m"
end
def instruction(:background, {r, g, b}) when r in 0..255 and g in 0..255 and b in 0..255 do
escape [48, r, g, b], "m"
end
def instruction(:background, num) when num in 0..255 do
escape [48, num], "m"
end
def instruction(:background, :default) do
escape 49, "m"
end
####
# PAGER
##
def instruction(:pager, {:up, amount}) do
escape amount, "S"
end
def instruction(:pager, {:down, amount}) do
escape amount, "T"
end
####
# CURSOR
##
def instruction(:cursor, :position) do
escape 6, "n"
end
def instruction(:cursor, :hide) do
escape "?", "25l"
end
def instruction(:cursor, :show) do
escape "?", "25h"
end
def instruction(:cursor, :save) do
escape "s"
end
def instruction(:cursor, :restore) do
escape "u"
end
def instruction(:cursor, {_, 0}) do
escape 0, "A"
end
def instruction(:cursor, {:up, amount}) when is_integer(amount) and amount > 0 do
escape amount, "A"
end
def instruction(:cursor, {:up, amount}) when is_integer(amount) and amount < 0 do
escape abs(amount), "B"
end
def instruction(:cursor, {:down, amount}) when is_integer(amount) and amount > 0 do
escape amount, "B"
end
def instruction(:cursor, {:down, amount}) when is_integer(amount) and amount < 0 do
escape abs(amount), "A"
end
def instruction(:cursor, {:right, amount}) when is_integer(amount) and amount > 0 do
escape amount, "C"
end
def instruction(:cursor, {:right, amount}) when is_integer(amount) and amount < 0 do
escape abs(amount), "D"
end
def instruction(:cursor, {:left, amount}) when is_integer(amount) and amount > 0 do
escape amount, "D"
end
def instruction(:cursor, {:left, amount}) when is_integer(amount) and amount < 0 do
escape abs(amount), "C"
end
def instruction(:cursor, {row, col}) when (
row == nil or (is_integer(row) and row > 0)
) and (
col == nil or (is_integer(col) and col > 0)
) do
escape [row, col], "H"
end
def instruction(:cursor, {:erase, :screen, :end}) do
escape 0, "J"
end
def instruction(:cursor, {:erase, :screen, :start}) do
escape 1, "J"
end
def instruction(:cursor, {:erase, :screen, :all}) do
escape 2, "J"
end
def instruction(:cursor, {:erase, :line, :end}) do
escape 0, "K"
end
def instruction(:cursor, {:erase, :line, :start}) do
escape 1, "K"
end
def instruction(:cursor, {:erase, :line, :all}) do
escape 2, "K"
end
end