UI.Queue (fnord v0.8.82)
View SourcePriority queue for UI operations to ensure proper serialization of output and user interactions.
What is a UI Context?
A UI context is a logical grouping of related UI operations that should execute together without interruption from other UI operations. For example, a confirmation dialog that shows information, asks a question, and displays the result should all execute as one atomic unit.
Each UI context has a unique token that allows UI operations to either:
- Execute immediately (if called from within the same context)
- Queue for later execution (if called from outside any context)
Context Wrappers for Interactive UI
Use these wrapper functions when calling interactive UI functions from contexts that could cause deadlocks:
run_from_genserver/1- For GenServer callbacks (starts fresh UI context)run_from_task/1- For Services.Globals.Spawn.async (preserves parent UI context)
Interactive UI functions that require wrapping:
GenServer example:
def handle_call(:confirm_delete, _from, state) do
result = UI.Queue.run_from_genserver(fn ->
UI.confirm("Delete this item?")
end)
{:reply, result, state}
endServices.Globals.Spawn.async example:
task = Services.Globals.Spawn.async(fn ->
UI.Queue.run_from_task(fn ->
UI.confirm("Process this item?")
end)
end)
result = Task.await(task)Non-interactive UI functions (UI.info/2, UI.error/2, etc.) can be called directly.
Summary
Functions
Returns a specification to start this module under a supervisor.
Wrapper for running interactive UI calls from GenServer callbacks.
Wrapper for running interactive UI calls from async tasks (Services.Globals.Spawn.async).
Functions
Returns a specification to start this module under a supervisor.
See Supervisor.
Wrapper for running interactive UI calls from GenServer callbacks.
This starts a fresh UI interaction context, which prevents deadlocks when GenServer callbacks need to make interactive UI calls that could send messages back to the same GenServer.
Use this for interactive functions like UI.confirm/1, UI.choose/2, and UI.prompt/1
when called from handle_call/3, handle_cast/2, or handle_info/2.
Example
def handle_call(:confirm_delete, _from, state) do
result = UI.Queue.run_from_genserver(fn ->
UI.confirm("Delete this item?")
end)
{:reply, result, state}
end
Wrapper for running interactive UI calls from async tasks (Services.Globals.Spawn.async).
This preserves the parent process's UI interaction context, allowing async tasks to participate in the same UI interaction as their parent. This is essential when tasks need to make interactive UI calls as part of an ongoing user interaction.
Use this when spawning tasks that might make interactive UI calls and you want them to be part of the current user interaction session.
Example
# In a function that's already in a UI interaction context
task = Services.Globals.Spawn.async(fn ->
UI.Queue.run_from_task(fn ->
# This UI call will be part of the parent's interaction
UI.confirm("Process this item?")
end)
end)
result = Task.await(task)