Packages
io_ansi_table
1.0.13
1.0.40
1.0.39
1.0.38
1.0.37
1.0.36
1.0.34
1.0.33
1.0.32
1.0.31
1.0.30
1.0.29
1.0.28
1.0.27
1.0.26
1.0.25
1.0.24
1.0.23
1.0.22
1.0.21
1.0.20
1.0.19
1.0.18
1.0.17
1.0.16
1.0.15
1.0.14
1.0.13
1.0.12
1.0.11
1.0.10
1.0.9
1.0.8
1.0.7
1.0.6
1.0.5
1.0.4
1.0.3
1.0.2
1.0.1
1.0.0
0.4.32
0.4.31
0.4.30
0.4.29
0.4.28
0.4.27
0.4.26
0.4.25
0.4.24
0.4.23
0.4.22
0.4.21
0.4.20
0.4.19
0.4.18
0.4.17
0.4.16
0.4.15
0.4.14
0.4.13
0.4.12
0.4.11
0.4.10
0.4.9
0.4.8
0.4.7
0.4.6
0.4.5
0.4.4
0.4.3
0.4.2
0.4.1
0.4.0
0.3.29
0.3.28
0.3.27
0.3.26
0.3.25
0.3.24
0.3.23
0.3.22
0.3.21
0.3.20
0.3.19
0.3.18
0.3.17
0.3.16
0.3.15
0.3.14
0.3.13
0.3.12
0.3.11
0.3.10
0.3.9
0.3.8
0.3.7
0.3.6
0.3.5
0.3.4
0.3.3
0.3.2
0.3.1
0.3.0
0.2.5
0.2.4
0.2.3
0.2.2
0.2.1
0.2.0
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
Writes data to "stdio" in a table with borders and colors. Can choose a table style to change the look of the table.
Current section
Files
Jump to
Current section
Files
lib/io/ansi/table/spec.ex
defmodule IO.ANSI.Table.Spec do
@moduledoc """
Creates a table `spec` struct from `headers` and `options`.
Also writes data (from `maps`) to stdout per a table `spec`.
"""
use PersistConfig
alias __MODULE__
alias IO.ANSI.Plus, as: ANSI
alias IO.ANSI.Table.{Column, Header, LineType, Row, Style}
@default_bell get_env(:default_bell)
@default_count get_env(:default_count)
@default_margins get_env(:default_margins)
@default_max_width get_env(:default_max_width)
@default_sort_symbols get_env(:default_sort_symbols)
@default_style get_env(:default_style)
@enforce_keys [
# initial fields
:spec_name,
:headers,
:align_specs,
:bell,
:count,
:header_fixes,
:margins,
:max_width,
:sort_specs,
:sort_symbols,
:style
]
defstruct [
# initial fields
:spec_name,
:headers,
:align_specs,
:bell,
:count,
:header_fixes,
:margins,
:max_width,
:sort_specs,
:sort_symbols,
:style,
# derived fields
align_attrs: [],
column_widths: [],
headings: [],
left_margin: "",
rows: [],
sort_attrs: []
]
@type t :: %Spec{
# initial fields
spec_name: String.t(),
headers: [Header.t(), ...],
align_specs: [Header.align_spec()],
bell: boolean,
count: integer,
header_fixes: %{optional(String.t() | Regex.t()) => String.t()},
margins: Keyword.t(),
max_width: pos_integer,
sort_specs: [Header.sort_spec()],
sort_symbols: [Header.sort_symbol()],
style: Style.t(),
# derived fields
align_attrs: [Header.align_attr()],
column_widths: [Column.width()],
headings: [String.t()],
left_margin: String.t(),
rows: [Row.t()],
sort_attrs: [Header.sort_attr()]
}
@doc """
Creates a table `spec` struct from `headers` and `options`.
"""
@spec new([Header.t(), ...], Keyword.t()) :: t
def new([_ | _] = headers, options \\ []) when is_list(options) do
%Spec{
spec_name: spec_name(options),
headers: headers,
align_specs: Keyword.get(options, :align_specs, []),
bell: Keyword.get(options, :bell, @default_bell),
count: Keyword.get(options, :count, @default_count),
header_fixes: Keyword.get(options, :header_fixes, %{}),
margins: Keyword.merge(@default_margins, options[:margins] || []),
max_width: Keyword.get(options, :max_width, @default_max_width),
sort_specs: Keyword.get(options, :sort_specs, []),
sort_symbols:
Keyword.merge(@default_sort_symbols, options[:sort_symbols] || []),
style: Keyword.get(options, :style, @default_style)
}
end
@spec extend(t) :: t
def extend(%Spec{} = spec) do
spec
|> Spec.AlignAttrs.derive()
|> Spec.Headings.derive()
|> Spec.LeftMargin.derive()
|> Spec.SortAttrs.derive()
end
@doc """
Identifies a table spec server.
Defaults to the current application name expressed as a string.
## Examples
iex> alias IO.ANSI.Table.Spec
iex> Spec.spec_name(style: :light, count: 9, spec_name: "github_issues")
"github_issues"
iex> alias IO.ANSI.Table.Spec
iex> Spec.spec_name([])
"io_ansi_table"
"""
@spec spec_name(Keyword.t()) :: String.t()
def spec_name(options) do
case options[:spec_name] do
nil ->
case :application.get_application() do
{:ok, app} -> app
:undefined -> Mix.Project.config()[:app]
end
|> to_string()
spec_name when is_binary(spec_name) ->
spec_name
end
end
@doc """
Writes data from `maps` to stdout per table `spec` and `options`.
"""
@spec write_table([Access.container()], t, Keyword.t()) :: :ok
def write_table(maps, %Spec{} = spec, options \\ [])
when is_list(maps) and is_list(options) do
spec
|> put(:bell, options[:bell])
|> put(:count, options[:count])
|> put(:max_width, options[:max_width])
|> put(:style, options[:style])
|> Spec.Rows.derive(maps)
|> Spec.ColumnWidths.derive()
|> write_table()
end
## Private functions
@spec put(t, atom, Map.value()) :: t
defp put(spec, _key, nil), do: spec
defp put(spec, key, value), do: Map.put(spec, key, value)
@spec top_margin(t) :: String.t()
defp top_margin(%Spec{margins: margins} = _spec) do
case margins[:top] do
# Move the cursor up N lines: \e[<N>A...
n when n <= -1 -> ANSI.cursor_up(-n)
n -> String.duplicate("\n", n)
end
end
@spec bottom_margin(t) :: String.t()
defp bottom_margin(%Spec{margins: margins} = _spec) do
case margins[:bottom] do
n when n >= 0 -> String.duplicate("\n", margins[:bottom])
_ -> ""
end
end
@spec write_table(t) :: :ok
defp write_table(spec) do
top_margin(spec) |> IO.write()
Style.line_types(spec.style) |> Enum.each(&LineType.write_lines(&1, spec))
bottom_margin(spec) |> IO.write()
IO.write(if spec.bell, do: "\a", else: "")
end
end