Packages

Declarative CLI framework and terminal rendering kit for Elixir — commands DSL, auto-generated help, ANSI rendering, tables, headers, boxes, and interactive prompts.

Current section

Files

Jump to
alaja lib alaja.ex
Raw

lib/alaja.ex

defmodule Alaja do
@moduledoc """
Public facade for the Alaja terminal rendering framework.
Provides a simplified API for the most common operations: printing
styled messages (`print_success`, `print_error`, `print_warning`,
`print_info`), creating buffers and cells, converting colour formats,
and rendering tables.
For advanced usage see the sub-modules directly:
`Alaja.Printer`, `Alaja.Components`, and `Alaja.Buffer`.
"""
alias Alaja.{Buffer, Cell, Printer}
alias Pote.Converters
@doc """
Creates an empty cell (space, no colour, no effects).
Returns a `%Cell{}` struct filled with defaults.
"""
@spec empty() :: Cell.t()
def empty, do: Cell.new()
@doc """
Creates a new buffer with the given dimensions.
Returns a `%Buffer{}` with `width * height` empty cells stored in a
flat tuple for O(1) access.
"""
@spec new_buffer(non_neg_integer(), non_neg_integer()) :: Buffer.t()
def new_buffer(width, height), do: Buffer.new(width, height)
@doc """
Converts an RGB tuple to uppercase hex string.
## Examples
iex> Alaja.rgb_to_hex({255, 180, 0})
"#FFB400"
"""
@spec rgb_to_hex({byte(), byte(), byte()}) :: String.t()
def rgb_to_hex({r, g, b}) do
Converters.rgb_to_hex({r, g, b})
end
@doc "Prints a success message (icon: ✓)."
@spec print_success(String.t()) :: :ok
defdelegate print_success(msg), to: Printer
@doc "Prints an error message (icon: ✗)."
@spec print_error(String.t()) :: :ok
defdelegate print_error(msg), to: Printer
@doc "Prints a warning message (icon: ⚠)."
@spec print_warning(String.t()) :: :ok
defdelegate print_warning(msg), to: Printer
@doc "Prints an informational message (icon: ℹ)."
@spec print_info(String.t()) :: :ok
defdelegate print_info(msg), to: Printer
@doc """
Prints a table to stdout.
Delegates to `Alaja.Components.Table.print/2`. Accepts a keyword list
or a list of lists where the first row is treated as headers.
"""
@spec print(keyword() | list()) :: :ok
defdelegate print(opts), to: Alaja.Components.Table
@doc """
Writes an `iodata` payload to stdout **without any transformation**.
Use this when you need to emit raw ANSI escapes (or any pre-formatted
text) that should pass through untouched by Alaja's printers.
## Example
Alaja.print_raw("\\e[31mError\\e[0m\\n")
"""
@spec print_raw(iodata()) :: :ok
def print_raw(iodata), do: IO.write(iodata)
@doc """
Writes an `iodata` payload to a specific device (default `:stdio`).
## Options
* `:device` — `:stdio | {:fd, posix} | pid()`. Defaults to `:stdio`.
Useful for writing to alternative file descriptors or to a process
socket in interactive components.
"""
@spec print_raw(iodata(), keyword()) :: :ok
def print_raw(iodata, opts) do
opts = Keyword.put_new(opts, :device, :stdio)
IO.write(Keyword.fetch!(opts, :device), iodata)
end
@doc """
Unified entry point for running an Alaja-based CLI.
The default `cli_module` is `Alaja.CLI` (the self-hosted demo CLI shipped
with the framework). Pass any module built with
`use Alaja.CLI.Definition, otp_app: :my_app, halt_on_error: true` to run your own (escript-style aborts the BEAM on error). Set `halt_on_error: false` if you want main/1 to return `{:error, reason}` instead.
Both escript entry points and library callers should go through this
function rather than calling `cli_module.main/1` directly so the
public facade has a single documented entry point.
## Examples
# Library caller
Alaja.run(System.argv())
# Custom CLI
Alaja.run(System.argv(), MyApp.CLI)
# escript main_module
defmodule MyApp.CLIEntry do
def main(argv), do: Alaja.run(argv, MyApp.CLI)
end
"""
@spec run([String.t()], module()) :: any()
def run(argv, cli_module \\ Alaja.CLI) when is_list(argv) and is_atom(cli_module) do
cli_module.main(argv)
end
end