etui/backend
Types
pub type Backend(state) {
Backend(
init: fn() -> Result(state, Error),
render: fn(state, List(RenderOp)) -> Result(state, Error),
poll: fn(state, Int) -> Result(#(InputEvent, state), Error),
next_size: fn(state) -> Result(#(TerminalSize, state), Error),
cleanup: fn(state) -> Nil,
)
}
Constructors
-
Backend( init: fn() -> Result(state, Error), render: fn(state, List(RenderOp)) -> Result(state, Error), poll: fn(state, Int) -> Result(#(InputEvent, state), Error), next_size: fn(state) -> Result(#(TerminalSize, state), Error), cleanup: fn(state) -> Nil, )
pub type Error {
TerminalUnsupported(reason: String)
IOError(reason: String)
Interrupted
}
Constructors
-
TerminalUnsupported(reason: String) -
IOError(reason: String) -
Interrupted
pub type InputEvent {
KeyPress(key: String)
Resize(width: Int, height: Int)
Tick
MousePress(x: Int, y: Int, button: MouseButton)
MouseRelease(x: Int, y: Int, button: MouseButton)
MouseScroll(x: Int, y: Int, up: Bool)
MouseDrag(x: Int, y: Int, button: MouseButton)
MouseMove(x: Int, y: Int)
Paste(text: String)
}
Constructors
-
KeyPress(key: String) -
Resize(width: Int, height: Int) -
Tick -
MousePress(x: Int, y: Int, button: MouseButton)Mouse button pressed.
x/yare 0-based terminal cell coordinates. -
MouseRelease(x: Int, y: Int, button: MouseButton)Mouse button released.
-
MouseScroll(x: Int, y: Int, up: Bool)Mouse wheel scrolled.
up: True= scroll up,False= scroll down. -
MouseDrag(x: Int, y: Int, button: MouseButton)Mouse moved with a button held down.
-
MouseMove(x: Int, y: Int)Mouse moved with no button held. Only reported when the backend enables motion tracking.
-
Paste(text: String)Text pasted via bracketed paste, delivered as one event rather than as hundreds of key presses. Requires a backend that enables bracketed paste.
Mouse button identifier.
pub type MouseButton {
MouseLeft
MouseMiddle
MouseRight
}
Constructors
-
MouseLeft -
MouseMiddle -
MouseRight
What a backend should turn on when it initialises the terminal.
pub type Options {
Options(mouse: Bool, paste: Bool)
}
Constructors
-
Options(mouse: Bool, paste: Bool)Arguments
- mouse
-
Report mouse buttons, drags and the wheel as input events.
- paste
-
Deliver pasted text as one
Pasteevent.Off by default: with it on, an app that does not handle
Pastesees nothing at all when the user pastes, which is worse than the mangled key presses it sees today.
pub type RenderOp {
MoveCursor(x: Int, y: Int)
Write(String)
ClearScreen
EnterAltScreen
ExitAltScreen
EnableMouse
DisableMouse
EnableBracketedPaste
DisableBracketedPaste
BeginSynchronizedOutput
EndSynchronizedOutput
}
Constructors
-
MoveCursor(x: Int, y: Int) -
Write(String) -
ClearScreen -
EnterAltScreen -
ExitAltScreen -
EnableMouseEnable SGR mouse tracking (button, drag and scroll events).
-
DisableMouseDisable all mouse tracking.
-
EnableBracketedPasteEnable bracketed paste, so pasted text arrives as one
Pasteevent instead of as one key press per character. -
DisableBracketedPasteDisable bracketed paste.
-
BeginSynchronizedOutputStart synchronized output (DEC private mode 2026).
A frame reaches the terminal as a run of cursor moves and text, and an emulator may paint whatever has arrived so far, which shows half of the old frame above half of the new one. Between this and
EndSynchronizedOutputthe emulator keeps showing what it had and applies everything that was written in one go. -
EndSynchronizedOutputShow what was written since
BeginSynchronizedOutput.
pub type TerminalSize {
TerminalSize(width: Int, height: Int)
}
Constructors
-
TerminalSize(width: Int, height: Int)
Values
pub fn clear_and_home() -> List(RenderOp)
pub fn next_size(
backend: Backend(state),
state: state,
) -> Result(#(TerminalSize, state), Error)
pub fn op_to_ansi(op: RenderOp) -> String
The escape sequence for one render op.
One table, not one per backend. The three backends each carried a copy,
and the copies had already drifted: EnableMouse asked for click
tracking (1000) on the JavaScript targets and not on Erlang, so the same
program reported subtly different mouse events depending on where it ran.
pub fn ops_to_ansi(ops: List(RenderOp)) -> String
Concatenated escape sequences for a list of ops.
pub fn poll(
backend: Backend(state),
state: state,
timeout_ms: Int,
) -> Result(#(InputEvent, state), Error)
pub fn render(
backend: Backend(state),
state: state,
ops: List(RenderOp),
) -> Result(state, Error)
pub fn restore_ops() -> List(RenderOp)
Everything an app has to undo before the terminal is someone else’s again.
Unconditional, and in this order on purpose: a cleanup path runs when things have already gone wrong, and asking a terminal to leave a mode it was never in costs nothing, while tracking which modes were entered costs a correct answer exactly when the state is least trustworthy.
pub fn restore_sequence() -> String
restore_ops as the bytes to send.
The single source for the restore sequence on every target, including the two places that cannot call Gleam: the shell watchdog that fires when the runtime dies without unwinding, and the Node exit handler. Both are handed this string rather than keeping a copy of it.