Yeesh.IOServer (Yeesh v0.8.3)

View Source

Custom Erlang IO protocol server for intercepting Mix task I/O.

Acts as a group leader for spawned Mix task processes, transparently capturing all IO.puts/IO.gets/IO.write calls. Output is buffered internally; input requests block the task until the caller provides input via provide_input_and_wait/3.

This module implements the Erlang IO protocol (io(3)) as a GenServer. It handles the following IO requests:

  • {:put_chars, encoding, chars} -- buffers output
  • {:put_chars, encoding, mod, fun, args} -- evaluates and buffers
  • {:get_line, encoding, prompt} -- blocks until input is provided
  • {:get_until, encoding, prompt, mod, fun, args} -- same as get_line
  • {:get_chars, encoding, prompt, count} -- same as get_line
  • :getopts / {:setopts, opts} -- encoding options
  • {:requests, list} -- batched requests

Output newlines are normalized from \n to \r\n for xterm.js compatibility when the buffer is flushed.

Lifecycle

  1. Started by Yeesh.MixRunner before spawning the task process.
  2. The task process's group leader is set to this server.
  3. Caller uses start_and_wait/2 to block until the task either requests input (IO.gets) or exits.
  4. For interactive tasks, caller repeatedly calls provide_input_and_wait/3 to feed lines and collect output.
  5. When the task exits, the server reports :done.

Summary

Types

Buffered output text with task status and optional prompt.

Functions

Returns a specification to start this module under a supervisor.

Registers the task process to monitor and begins intercepting its I/O.

Provides a line of input to the blocked task and waits for the next input request or task exit.

Blocks until the monitored task either calls IO.gets or exits.

Starts the IO server.

Stops the IO server, killing the monitored task if still alive.

Types

wait_result()

@type wait_result() ::
  {output :: String.t(), :waiting, prompt :: String.t()}
  | {output :: String.t(), :done}

Buffered output text with task status and optional prompt.

Functions

child_spec(init_arg)

Returns a specification to start this module under a supervisor.

See Supervisor.

monitor_task(server, task_pid)

@spec monitor_task(GenServer.server(), pid()) :: :ok

Registers the task process to monitor and begins intercepting its I/O.

Must be called after start_link/1 and before start_and_wait/2.

provide_input_and_wait(server, input, opts \\ [])

@spec provide_input_and_wait(GenServer.server(), String.t(), keyword()) ::
  wait_result()

Provides a line of input to the blocked task and waits for the next input request or task exit.

The input string is delivered to the pending IO.gets call (with a trailing newline appended). The caller then blocks until the task either calls IO.gets again or terminates.

Returns {output, :waiting, prompt} or {output, :done}.

Options

  • :timeout -- call timeout in milliseconds (default: 30000)

start_and_wait(server, opts \\ [])

@spec start_and_wait(
  GenServer.server(),
  keyword()
) :: wait_result()

Blocks until the monitored task either calls IO.gets or exits.

Returns {output, :waiting, prompt} if the task is waiting for input, or {output, :done} if the task finished.

Options

  • :timeout -- call timeout in milliseconds (default: 30000)

start_link(opts \\ [])

@spec start_link(keyword()) :: GenServer.on_start()

Starts the IO server.

Options

  • :name -- optional GenServer name

stop(server)

@spec stop(GenServer.server()) :: :ok

Stops the IO server, killing the monitored task if still alive.