GenServer that manages the frontend renderer Port.
Operates in two modes depending on the MINGA_PORT_MODE env var:
Spawn mode (default): BEAM is the parent process. Port.Manager spawns the GUI/TUI binary as a child via
Port.open({:spawn_executable, ...}). Used in development, TUI mode, and Burrito releases.Connected mode (
MINGA_PORT_MODE=connected): BEAM is a child of the GUI process. The GUI set up stdin/stdout pipes before launching us. Port.Manager opens{:fd, 0, 1}as a Port instead of spawning a child. Used when launching fromMinga.app(Finder, Spotlight, Dock).
Both modes use identical {:packet, 4} framing. The protocol layer (event decoding, render commands, subscriber broadcasting) is the same.
Output admission always uses Port.command/3 with :nosuspend. If the transport is unwritable, the manager retains one current frame and one latest coalesced replacement, retries within a short budget, then requests correlated keyframe recovery. Synchronous admission calls keep frame binaries out of the manager mailbox while leaving the process free to receive frontend input between attempts.
Subscribers register via subscribe/1 and receive messages as:
{:minga_input, event}where event is a MingaEditor.Frontend.Protocol.input_event().
Summary
Types
Non-suspending frontend transport admission result.
Renderer backend.
Options for starting the port manager.
Internal state.
Functions
Returns the frontend's reported capabilities.
Returns a specification to start this module under a supervisor.
Returns bounded output-pressure diagnostics.
Returns whether the renderer has sent its ready signal.
Attempts non-suspending admission of encoded commands to the renderer.
Like send_commands/2 but stamps the synchronous admission request with a monotonic send time. The receiver emits a [:minga, :render, :hop_latency] (hop: :send_commands) sample measuring the Renderer.Server to Port.Manager scheduling delay. Used only for the per-frame render batch on the keystroke path.
Starts the port manager.
Subscribes the calling process to receive input events.
Returns the terminal size as {width, height}, or nil if not yet ready.
Builds a /dev/ path from the tty name returned by ps -o tty=.
Types
@type admission() :: :accepted | :unwritable
Non-suspending frontend transport admission result.
@type backend() :: :tui | :gui
Renderer backend.
@type start_opt() :: {:name, GenServer.name()} | {:renderer_path, String.t()} | {:backend, backend()} | {:port_mode, MingaEditor.Frontend.Manager.State.port_mode()} | {:port_opener, (term(), [term()] -> port())} | {:port_commander, MingaEditor.Frontend.Manager.State.port_commander()} | {:output_retry_ms, pos_integer()} | {:output_failure_ms, non_neg_integer()} | {:tty_path, String.t() | nil}
Options for starting the port manager.
@type state() :: MingaEditor.Frontend.Manager.State.t()
Internal state.
Functions
@spec capabilities(GenServer.server()) :: MingaEditor.Frontend.Capabilities.t()
Returns the frontend's reported capabilities.
Returns a specification to start this module under a supervisor.
See Supervisor.
@spec output_pressure(GenServer.server()) :: MingaEditor.Frontend.Manager.OutputPressure.stats()
Returns bounded output-pressure diagnostics.
@spec ready?(GenServer.server()) :: boolean()
Returns whether the renderer has sent its ready signal.
@spec send_commands(GenServer.server() | nil, [binary()]) :: admission()
Attempts non-suspending admission of encoded commands to the renderer.
@spec send_render_commands(GenServer.server() | nil, [binary()]) :: admission()
Like send_commands/2 but stamps the synchronous admission request with a monotonic send time. The receiver emits a [:minga, :render, :hop_latency] (hop: :send_commands) sample measuring the Renderer.Server to Port.Manager scheduling delay. Used only for the per-frame render batch on the keystroke path.
@spec start_link([start_opt()]) :: GenServer.on_start()
Starts the port manager.
@spec subscribe(GenServer.server()) :: :ok
Subscribes the calling process to receive input events.
@spec terminal_size(GenServer.server()) :: {pos_integer(), pos_integer()} | nil
Returns the terminal size as {width, height}, or nil if not yet ready.
Builds a /dev/ path from the tty name returned by ps -o tty=.
The format varies by OS and version:
- macOS long form:
"ttys008"→"/dev/ttys008" - macOS short form:
"s003"→"/dev/ttys003" - Linux:
"pts/3"→"/dev/pts/3"
Checks if /dev/{name} exists first (handles long form and Linux).
Falls back to /dev/tty{name} for short forms.
Returns nil when the process has no controlling terminal. ps -o tty=
reports this as all question marks: "??" on macOS, "?" on Linux. Without
this guard we would build a bogus path like /dev/tty?, which the Go renderer
cannot open and crashes on. Returning nil lets the renderer fall back to
/dev/tty.