UI (fnord v0.9.17)
View SourceUser interface functions for output, logging, and user interaction.
Context Warnings for Interactive UI
Interactive UI functions (confirm/1, choose/2, prompt/1) can cause deadlocks
when called from certain contexts and must be wrapped appropriately.
GenServer Callbacks
Use UI.Queue.run_from_genserver/1 to prevent deadlocks:
def handle_call(:delete_item, _from, state) do
confirmed = UI.Queue.run_from_genserver(fn ->
UI.confirm("Delete this item?")
end)
# ...
endServices.Globals.Spawn.async and Spawned Processes
Use UI.Queue.run_from_task/1 when tasks need to participate in an existing UI interaction:
task = Services.Globals.Spawn.async(fn ->
UI.Queue.run_from_task(fn ->
UI.confirm("Process this item?")
end)
end)Creating UI Components
Use UI.interact/1 to group multiple UI operations into a single atomic component:
def confirm_with_details(item) do
UI.interact(fn ->
UI.info("Item details: #{item.name}")
UI.puts("Size: #{item.size}, Modified: #{item.date}")
UI.confirm("Delete this item?")
end)
endNon-interactive functions (info/2, warn/2, error/2, puts/1, say/1) are safe
to call directly from any context.
Interactive vs Non-Interactive Functions
Interactive (require context wrappers in GenServer/Task contexts):
Non-interactive (safe to call directly from any context):
Summary
Functions
Formats a string through the external FNORD_FORMATTER command, if configured. Skipped when quiet mode is active or stdout is not a TTY.
Execute a function as a single interaction unit. All UI calls within the function (puts, log, choose, prompt, etc.) will be treated as part of this interaction and execute immediately without queuing.
Open content in the user's editor and return the edited text.
Functions
Formats a string through the external FNORD_FORMATTER command, if configured. Skipped when quiet mode is active or stdout is not a TTY.
Execute a function as a single interaction unit. All UI calls within the function (puts, log, choose, prompt, etc.) will be treated as part of this interaction and execute immediately without queuing.
This is useful for composite TUI components that combine multiple UI elements.
@spec log_usage(AI.Model.t(), non_neg_integer() | map()) :: :ok
Open content in the user's editor and return the edited text.
Respects ELIXIR_EDITOR, then EDITOR, falling back to vi.
Uses a Port with :nouse_stdio so the editor inherits the real terminal
file descriptors - this avoids the hang that System.shell causes with
TUI editors like vim/nvim (whose stdin would otherwise be BEAM's pipe).
@spec warning_banner(binary()) :: :ok