Packages
fnord
0.8.24
0.9.40
0.9.39
0.9.38
0.9.37
0.9.36
0.9.35
0.9.34
0.9.33
0.9.32
0.9.31
0.9.30
0.9.29
0.9.28
0.9.27
0.9.26
0.9.25
0.9.24
0.9.23
0.9.22
0.9.21
0.9.20
0.9.19
0.9.18
0.9.17
0.9.16
0.9.15
0.9.14
0.9.13
0.9.12
0.9.11
0.9.10
0.9.9
0.9.8
0.9.7
0.9.6
0.9.5
0.9.4
0.9.3
0.9.2
0.9.1
0.9.0
0.8.99
0.8.98
0.8.97
0.8.96
0.8.95
0.8.94
0.8.93
0.8.92
0.8.91
0.8.90
0.8.89
0.8.88
0.8.87
0.8.86
0.8.85
0.8.84
0.8.83
0.8.82
0.8.81
0.8.80
0.8.79
0.8.78
0.8.77
0.8.76
0.8.75
0.8.74
0.8.73
0.8.72
0.8.71
0.8.70
0.8.69
0.8.68
0.8.67
0.8.66
0.8.65
0.8.64
0.8.63
0.8.62
0.8.61
0.8.60
0.8.59
0.8.58
0.8.57
0.8.56
0.8.55
0.8.54
0.8.53
0.8.52
0.8.51
0.8.50
0.8.49
0.8.48
0.8.47
0.8.46
0.8.45
0.8.44
0.8.43
0.8.42
0.8.41
0.8.40
0.8.39
0.8.38
0.8.37
0.8.36
0.8.35
0.8.34
0.8.33
0.8.32
0.8.31
0.8.30
0.8.29
0.8.27
0.8.26
0.8.25
0.8.24
0.8.23
0.8.22
0.8.21
0.8.20
0.8.19
0.8.18
0.8.17
0.8.16
0.8.15
0.8.14
0.8.13
0.8.12
0.8.11
0.8.1
0.8.0
0.7.24
0.7.23
0.7.22
0.7.21
0.7.20
0.7.19
0.7.18
0.7.17
0.7.16
0.7.15
0.7.14
0.7.13
0.7.12
0.7.11
0.7.10
0.7.9
0.7.8
0.7.7
0.7.6
0.7.5
0.7.3
0.7.2
0.7.1
0.7.0
0.6.9
0.6.8
0.6.7
0.6.6
0.6.5
0.6.4
0.6.3
0.6.1
0.6.0
0.5.9
0.5.8
0.5.7
0.5.6
0.5.5
0.5.4
0.5.3
0.5.2
0.5.1
0.5.0
0.4.44
0.4.43
0.4.42
0.4.41
0.4.40
0.4.39
0.4.38
0.4.37
0.4.36
0.4.35
0.4.34
0.4.33
0.4.32
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.0
0.2.0
0.1.0
AI code archaeology
Current section
Files
Jump to
Current section
Files
lib/ui.ex
defmodule UI do
require Logger
# ----------------------------------------------------------------------------
# Messaging
# ----------------------------------------------------------------------------
def say(msg) do
UI.flush()
msg
|> UI.Formatter.format_output()
|> IO.puts()
end
@spec confirm(binary) :: boolean
def confirm(msg), do: confirm(msg, false)
@spec confirm(binary, boolean) :: boolean
def confirm(msg, default) do
has_default = is_boolean(default)
cond do
is_tty?() ->
yes = if default == true, do: "Y", else: "y"
no = if default == false, do: "N", else: "n"
flush()
IO.write(:stderr, UI.Formatter.format_output("#{msg} (#{yes}/#{no}) "))
case IO.gets("") do
"y\n" -> true
"Y\n" -> true
_ -> default
end
has_default ->
default
true ->
Logger.warning(
"Confirmation requested without default, but session is not connected to a TTY."
)
false
end
end
def flush, do: Logger.flush()
def report_step(msg), do: info(msg)
def report_step(msg, detail), do: info(msg, detail)
def begin_step(msg, detail \\ nil) do
if is_nil(detail) do
Logger.info(IO.ANSI.format([:green, msg, :reset], colorize?()))
else
Logger.info(IO.ANSI.format([:green, msg, :reset, ": ", :cyan, detail, :reset], colorize?()))
end
end
def end_step(msg, detail \\ nil) do
if is_nil(detail) do
Logger.info(IO.ANSI.format([:yellow, msg, :reset], colorize?()))
else
Logger.info(
IO.ANSI.format([:yellow, msg, :reset, ": ", :cyan, detail, :reset], colorize?())
)
end
end
def printf_debug(item) do
Logger.debug(inspect(item, pretty: true))
Logger.flush()
item
end
def debug(msg) do
Logger.debug(IO.ANSI.format([:green, msg, :reset], colorize?()))
end
def debug(msg, detail) do
Logger.debug(IO.ANSI.format([:green, msg, :reset, ": ", :cyan, detail, :reset], colorize?()))
end
def info(msg) do
Logger.info(IO.ANSI.format([:green, msg, :reset], colorize?()))
end
def info(msg, detail) do
msg = msg || ""
detail = detail || ""
Logger.info(IO.ANSI.format([:green, msg, :reset, ": ", :cyan, detail, :reset], colorize?()))
end
def warn(msg) do
Logger.warning(IO.ANSI.format([:yellow, msg, :reset], colorize?()))
end
def warn(msg, detail) do
Logger.warning(
IO.ANSI.format([:yellow, msg, :reset, ": ", :cyan, detail, :reset], colorize?())
)
end
def error(msg) do
Logger.error(IO.ANSI.format([:red, msg, :reset], colorize?()))
end
def error(msg, detail) do
Logger.error(IO.ANSI.format([:red, msg, :reset, ": ", :cyan, detail, :reset], colorize?()))
end
def warning_banner(msg) do
IO.puts(
:stderr,
IO.ANSI.format(
[
:red_background,
:black,
" <<< WARNING >>> #{msg} <<< WARNING >>> ",
:reset
],
colorize?()
)
)
end
@spec fatal(binary) :: no_return()
def fatal(msg) do
Logger.error(IO.ANSI.format([:red, msg, :reset], colorize?()))
Logger.flush()
System.halt(1)
end
@spec fatal(binary, binary) :: no_return()
def fatal(msg, detail) do
Logger.error(IO.ANSI.format([:red, msg, :reset, ": ", :cyan, detail, :reset], colorize?()))
Logger.flush()
System.halt(1)
end
@spec log_usage(AI.Model.t(), non_neg_integer) :: :ok
def log_usage(model, usage) when is_integer(usage) do
percentage = Float.round(usage / model.context * 100, 2)
str_usage = Util.format_number(usage)
str_context = Util.format_number(model.context)
info("Context window usage", "#{percentage}% (#{str_usage} / #{str_context} tokens)")
end
def is_tty? do
:prim_tty.isatty(:stderr)
|> case do
true -> true
_ -> false
end
end
def colorize?, do: is_tty?()
def italicize(text) do
IO.ANSI.format([:italic, text, :reset], colorize?())
end
# ----------------------------------------------------------------------------
# Interactive elements
# ----------------------------------------------------------------------------
def quiet?() do
Application.get_env(:fnord, :quiet)
end
def spin(processing, func) do
if quiet?() do
begin_step(processing)
{msg, result} = func.()
end_step(msg)
result
else
Spinner.run(func, processing)
end
end
def progress_bar_start(name, label, total) do
if !quiet?() do
Owl.ProgressBar.start(
id: name,
label: label,
total: total,
timer: true,
absolute_values: true
)
end
end
def progress_bar_update(name) do
if !quiet?() do
Owl.ProgressBar.inc(id: name)
Owl.LiveScreen.await_render()
end
end
def async_stream(enumerable, fun, label \\ "Working", options \\ []) do
progress_bar_start(:async_stream, label, Enum.count(enumerable))
enumerable
|> Util.async_stream(
fn item ->
result = fun.(item)
progress_bar_update(:async_stream)
result
end,
options
)
end
def choose(prompt, options, owl_opts \\ []) do
prompt |> UI.Formatter.format_output() |> IO.puts()
Owl.IO.select(options, owl_opts)
end
def prompt(prompt, owl_opts \\ []) do
prompt |> UI.Formatter.format_output() |> IO.puts()
Owl.IO.input(owl_opts)
end
end