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/y are 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 Paste event.

    Off by default: with it on, an app that does not handle Paste sees 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
  • EnableMouse

    Enable SGR mouse tracking (button, drag and scroll events).

  • DisableMouse

    Disable all mouse tracking.

  • EnableBracketedPaste

    Enable bracketed paste, so pasted text arrives as one Paste event instead of as one key press per character.

  • DisableBracketedPaste

    Disable bracketed paste.

  • BeginSynchronizedOutput

    Start 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 EndSynchronizedOutput the emulator keeps showing what it had and applies everything that was written in one go.

  • EndSynchronizedOutput

    Show what was written since BeginSynchronizedOutput.

pub type TerminalSize {
  TerminalSize(width: Int, height: Int)
}

Constructors

  • TerminalSize(width: Int, height: Int)

Values

pub fn cleanup(backend: Backend(state), state: state) -> Nil
pub fn clear_and_home() -> List(RenderOp)
pub fn default_options() -> Options

Mouse off, bracketed paste off.

pub fn init(backend: Backend(state)) -> Result(state, Error)
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.

✨ Search Document