ExTermbox (ExTermbox v2.0.4)
View SourceElixir bindings for the termbox2 library, providing a way to control the terminal and draw simple UIs using Erlang NIFs.
This module provides the main user-facing API. It interacts with the termbox2
NIF functions via the ExTermbox.Server
GenServer, which must be running.
Architecture
ExTermbox
relies on a GenServer
, typically registered as ExTermbox.Server
,
to manage the lifecycle of the termbox2
NIF library and handle asynchronous
events. Most functions in this module are thin wrappers that send messages
(calls or casts) to this server process.
See ExTermbox.Server
for implementation details.
Usage
- Initialization: Call
ExTermbox.init/1
to start theExTermbox.Server
. This callstb_init()
via the NIF and registers the calling process as the 'owner' to receive events. - API Calls: Use functions like
change_cell/5
,clear/0
,print/5
, etc. These functions communicate with the runningExTermbox.Server
. - Display: Call
ExTermbox.present/0
to synchronize the internal back buffer with the terminal screen. - Events: The
ExTermbox.Server
automatically polls for terminal events (keyboard, mouse, resize) usingtb_peek_event()
via the NIF. Events are parsed into%ExTermbox.Event{}
structs and sent as messages in the format{:termbox_event, event}
to the owner process (the one that calledinit/1
). You do not need to manually poll for events. - Shutdown: Call
ExTermbox.shutdown/0
when finished. This stops theExTermbox.Server
gracefully, which in turn callstb_shutdown()
via the NIF.
Event Handling
Events are delivered automatically as messages in the format {:termbox_event, %ExTermbox.Event{}}
to the process that called init/1
. You should handle these messages in your
process's handle_info/2
callback (if it's a GenServer or similar OTP process).
Example (handle_info
in the owner process):
def handle_info({:termbox_event, %ExTermbox.Event{type: :key, key: :q}}, state) do
IO.puts("Quit key pressed!")
# Initiate shutdown sequence
ExTermbox.shutdown()
{:stop, :normal, state}
end
def handle_info({:termbox_event, event}, state) do
IO.inspect(event, label: "Received Termbox Event")
# Handle other events (resize, mouse, other keys)
{:noreply, state}
end
Summary
Functions
Changes the character, foreground, and background attributes of a specific cell
in the internal back buffer by sending a request to the ExTermbox.Server
.
Clears the internal back buffer by sending a request to the ExTermbox.Server
.
[Debug] Causes the C helper process to exit immediately. FOR TESTING ONLY.
Retrieves the character, foreground, and background attributes of a specific cell
by querying the ExTermbox.Server
.
Returns the height of the terminal by querying the ExTermbox.Server
.
Initializes the termbox library by starting the ExTermbox.Server
GenServer.
Synchronizes the internal back buffer with the terminal screen by sending a
request to the ExTermbox.Server
.
A convenience function to print a string at a given position with specified attributes.
Selects the input mode by sending a request to the ExTermbox.Server
.
Sets the clear attributes (foreground and background) used by clear/1
by sending a request to the ExTermbox.Server
.
Sets the cursor position by sending a request to the ExTermbox.Server
.
Sets the output mode by sending a request to the ExTermbox.Server
.
Shuts down the termbox library by stopping the ExTermbox.Server
GenServer.
Returns the width of the terminal by querying the ExTermbox.Server
.
Types
Functions
@spec change_cell( integer(), integer(), char() | String.t(), integer(), integer(), atom() | pid() ) :: :ok | {:error, any()}
Changes the character, foreground, and background attributes of a specific cell
in the internal back buffer by sending a request to the ExTermbox.Server
.
The server calls the termbox2
NIF function tb_set_cell()
.
This does not immediately affect the visible terminal; present/1
must be called
to synchronize.
Arguments:
x
: The zero-based column index.y
: The zero-based row index.char
: The character to place in the cell. Can be:- An integer codepoint (e.g.,
?a
). - A single-character string (e.g.,
"a"
). - A single-codepoint UTF-8 string (e.g.,
"€"
).
- An integer codepoint (e.g.,
fg
: The foreground attribute (an integer constant fromExTermbox.Constants
). Combine colors (e.g.,Constants.color(:red)
) with attributes (e.g.,Constants.attribute(:bold)
) using bitwise OR (Bitwise.bor/2
).bg
: The background attribute (an integer constant fromExTermbox.Constants
).server
: The registered name or PID of the server (defaults to#{inspect(@server_name)}
).
Returns :ok
if the arguments are valid and the request is sent.
Returns {:error, :invalid_char}
if the char
argument is not a valid single
character representation.
This function uses GenServer.cast
, so errors during the NIF call itself
will not be reported back directly but may be logged by the server.
Clears the internal back buffer by sending a request to the ExTermbox.Server
.
The server calls the termbox2
NIF function tb_clear()
.
This does not immediately affect the visible terminal; present/1
must be called
to synchronize.
Arguments:
server
: The registered name or PID of the server (defaults to#{inspect(@server_name)}
).
Returns :ok
on success or {:error, reason}
if the GenServer call fails.
[Debug] Causes the C helper process to exit immediately. FOR TESTING ONLY.
Requires the PID or registered name of the PortHandler process.
@spec get_cell(integer(), integer(), atom() | pid()) :: {:ok, {integer(), integer(), integer()}} | {:error, any()}
Retrieves the character, foreground, and background attributes of a specific cell
by querying the ExTermbox.Server
.
Note: This function is not currently implemented in v2.0.0. The underlying
tb_get_cell/2
function is not available in the current termbox2_nif version.
Calls will return {:error, {:not_implemented, "..."}}
.
This feature may be added in a future version when the NIF library is updated.
Returns {:ok, {char_codepoint, fg_attribute, bg_attribute}}
on success,
or {:error, reason}
on failure.
Arguments:
x
: The zero-based column index.y
: The zero-based row index.server
: The registered name or PID of the server (defaults to#{inspect(@server_name)}
).
@spec height(atom() | pid()) :: {:ok, non_neg_integer()} | {:error, any()}
Returns the height of the terminal by querying the ExTermbox.Server
.
The server retrieves this information via the termbox2
NIF function tb_height()
.
Arguments:
server
: The registered name or PID of the server (defaults toElixir.ExTermbox.Server
).
Initializes the termbox library by starting the ExTermbox.Server
GenServer.
This function attempts to start and link an ExTermbox.Server
process.
The server process, upon its own initialization, will call the underlying
termbox2
NIF function tb_init()
.
The calling process is registered as the "owner" of the termbox session and
will receive {:termbox_event, %ExTermbox.Event{}}
messages.
Returns {:ok, server_name}
on success, where server_name
is the atom used
to register the GenServer (defaults to ExTermbox.Server
). Returns {:error, reason}
if the server cannot be started or if tb_init()
fails within the server.
If the server is already running under the specified name, it logs a warning
and returns {:ok, server_name}
without attempting to start a new one.
Options:
:name
(atom): The registered name for theExTermbox.Server
GenServer. Defaults toExTermbox.Server
.:owner
(pid): The PID to receive termbox events. Defaults toself()
. This is typically not overridden directly, asinit/1
sets it.:poll_interval_ms
(pos_integer): The interval in milliseconds for polling terminal events viatb_peek_event
. Defaults to10
.
All options are passed down to ExTermbox.Server.start_link/1
.
Synchronizes the internal back buffer with the terminal screen by sending a
request to the ExTermbox.Server
.
The server calls the termbox2
NIF function tb_present()
.
Arguments:
server
: The registered name or PID of the server (defaults to#{inspect(@server_name)}
).
Returns :ok
on success or {:error, reason}
if the GenServer call fails.
A convenience function to print a string at a given position with specified attributes.
This function iterates through the string's characters and calls change_cell/6
for each one, sending multiple requests to the ExTermbox.Server
.
Note: This function assumes a left-to-right character display and does not handle
line wrapping or terminal boundaries explicitly. Characters printed beyond the
terminal width might be ignored by the underlying termbox2
library.
Arguments:
x
: The starting zero-based column index.y
: The zero-based row index.fg
: The foreground attribute (integer constant fromExTermbox.Constants
).bg
: The background attribute (integer constant fromExTermbox.Constants
).str
: The string to print.server
: The registered name or PID of the server (defaults to#{inspect(@server_name)}
).
Returns :ok
. Like change_cell/6
, this uses GenServer.cast
, so errors during
individual NIF calls are not reported directly.
Selects the input mode by sending a request to the ExTermbox.Server
.
The server validates the mode atom against ExTermbox.Constants.input_mode/1
and then calls the termbox2
NIF function tb_set_input_mode()
.
Arguments:
mode
: An input mode atom defined inExTermbox.Constants
(e.g.,:esc
,:alt
,:mouse
).server
: The registered name or PID of the server (defaults to#{inspect(@server_name)}
).
Returns :ok
on success, {:error, :invalid_input_mode}
if the mode atom is
unrecognized, or {:error, reason}
for other GenServer call errors.
Sets the clear attributes (foreground and background) used by clear/1
by sending a request to the ExTermbox.Server
.
The server validates the attributes and calls the termbox2
NIF function
tb_set_clear_attrs()
.
Arguments:
fg
: The foreground attribute (an integer constant fromExTermbox.Constants
).bg
: The background attribute (an integer constant fromExTermbox.Constants
).server
: The registered name or PID of the server (defaults to#{inspect(@server_name)}
).
Returns :ok
on success, or {:error, reason}
if the GenServer call fails.
Sets the cursor position by sending a request to the ExTermbox.Server
.
The server calls the termbox2
NIF function tb_set_cursor()
.
Use x = -1
and y = -1
(or the default arguments) to hide the cursor.
See ExTermbox.Constants.hide_cursor/0
.
Arguments:
x
: The zero-based column index (-1 to hide).y
: The zero-based row index (-1 to hide).server
: The registered name or PID of the server (defaults to#{inspect(@server_name)}
).
Returns :ok
. This function uses GenServer.cast
, so errors during the NIF call
will not be reported back directly but may be logged by the server.
Sets the output mode by sending a request to the ExTermbox.Server
.
The server validates the mode atom against ExTermbox.Constants.output_mode/1
and then calls the termbox2
NIF function tb_set_output_mode()
.
Arguments:
mode
: An output mode atom defined inExTermbox.Constants
(e.g.,:normal
,:grayscale
,:xterm256
).server
: The registered name or PID of the server (defaults to#{inspect(@server_name)}
).
Returns :ok
on success, {:error, :invalid_output_mode}
if the mode atom is
unrecognized, or {:error, reason}
for other GenServer call errors.
@spec shutdown(atom()) :: :ok | {:error, :unexpected_registry_value}
Shuts down the termbox library by stopping the ExTermbox.Server
GenServer.
This function finds the ExTermbox.Server
process (using the provided or
default name) and requests it to stop gracefully (using :shutdown
).
The server's terminate/2
callback is responsible for calling the termbox2
NIF function tb_shutdown()
to restore the terminal state.
Returns :ok
if the stop request was sent or if the server was not running.
Returns {:error, reason}
if finding the server process fails unexpectedly.
Arguments:
server_name
: The registered name of the server to stop. Defaults toExTermbox.Server
.
@spec start_link(keyword()) :: GenServer.on_start()
@spec width(atom() | pid()) :: {:ok, non_neg_integer()} | {:error, any()}
Returns the width of the terminal by querying the ExTermbox.Server
.
The server retrieves this information via the termbox2
NIF function tb_width()
.
Arguments:
server
: The registered name or PID of the server (defaults toElixir.ExTermbox.Server
).