Binary protocol encoder/decoder for BEAM ↔ frontend communication.
Messages are length-prefixed binaries (4-byte big-endian header,
handled by Erlang's {:packet, 4} Port option). The payload
starts with a 1-byte opcode followed by opcode-specific fields.
Input Events (frontend → BEAM)
| Opcode | Name | Payload |
|---|---|---|
| 0x01 | key_press | codepoint::32, modifiers::8[, seq::32] |
| 0x02 | resize | width::16, height::16 |
| 0x03 | ready | width::16, height::16[, caps..., protocol_version::16] |
| 0x04 | mouse_event | row::16-signed, col::16-signed, button::8, mods::8, type::8 |
The extended ready handshake carries the frontend's compiled-in
protocol_version; the BEAM rejects a mismatch with protocol_error (0x18).
Render Commands (BEAM → frontend)
Rendering is semantic-first. GUI render commands are encoded by Minga.Frontend.Adapter.GUI, with this module retaining the common side-channel encoders for titles, fonts, window background, frame-transaction boundaries (begin_frame/commit_frame), and the protocol_error version-mismatch signal. The cell-paradigm encoders (draw_text, set_cursor, clear, region commands) were retired in protocol_version 2; batch_end was replaced by the begin/commit frame transaction in protocol_version 3 (#2219).
Modifier Flags
| Flag | Value |
|---|---|
| SHIFT | 0x01 |
| CTRL | 0x02 |
| ALT | 0x04 |
| SUPER | 0x08 |
Summary
Types
Cursor shape.
A highlight span from tree-sitter.
An input event decoded from Zig.
A frontend-originated input correlation sequence (u32).
Modifier flag bitmask.
Mouse button identifier.
Mouse event type.
Functions
Decodes an input event from a binary payload.
Encodes a begin_frame command that opens a frame transaction (#2219).
Encodes a commit_frame command that closes a frame transaction (#2219).
Encodes a protocol_error command.
Encodes a register_font command to associate a font_id with a font family.
Encodes a set_font command to configure the GUI frontend's font.
Encodes a set_font_fallback command to configure the GUI's font fallback chain.
Encodes a set_title command to update the terminal window title.
Encodes a set_window_bg command to set the default background color.
Checks if a modifier flag is set.
Returns the ALT modifier flag.
Returns the CTRL modifier flag.
Returns the SHIFT modifier flag.
Returns the SUPER modifier flag.
Types
@type conceal_span() :: Minga.Parser.Protocol.conceal_span()
@type cursor_shape() :: :block | :beam | :underline
Cursor shape.
@type edit_delta() :: Minga.Parser.Protocol.edit_delta()
@type highlight_span() :: Minga.Language.Highlight.Span.t()
A highlight span from tree-sitter.
@type input_event() :: {:key_press, codepoint :: non_neg_integer(), modifiers(), input_seq()} | {:resize, width :: pos_integer(), height :: pos_integer()} | {:ready, width :: pos_integer(), height :: pos_integer()} | {:ready, width :: pos_integer(), height :: pos_integer(), MingaEditor.Frontend.Capabilities.t(), protocol_version :: non_neg_integer()} | {:capabilities_updated, MingaEditor.Frontend.Capabilities.t()} | {:paste_event, text :: String.t()} | {:mouse_event, row :: integer(), col :: integer(), mouse_button(), modifiers(), mouse_event_type(), click_count :: pos_integer()} | {:highlight_spans, buffer_id :: non_neg_integer(), version :: non_neg_integer(), [highlight_span()]} | {:highlight_names, buffer_id :: non_neg_integer(), [String.t()]} | {:conceal_spans, buffer_id :: non_neg_integer(), version :: non_neg_integer(), [conceal_span()]} | {:grammar_loaded, success :: boolean(), name :: String.t()} | {:injection_ranges, buffer_id :: non_neg_integer(), [Minga.Language.Highlight.InjectionRange.t()]} | {:language_at_response, request_id :: non_neg_integer(), language :: String.t()} | {:fold_ranges, buffer_id :: non_neg_integer(), version :: non_neg_integer(), [{start_line :: non_neg_integer(), end_line :: non_neg_integer()}]} | {:indent_result, request_id :: non_neg_integer(), line :: non_neg_integer(), indent_level :: integer()} | {:textobject_result, request_id :: non_neg_integer(), result :: {non_neg_integer(), non_neg_integer(), non_neg_integer(), non_neg_integer()} | nil} | {:node_info, request_id :: non_neg_integer(), Minga.Parser.StructuralNavResult.t() | nil} | {:match_item_result, request_id :: non_neg_integer(), result :: {non_neg_integer(), non_neg_integer()} | nil} | {:textobject_positions, buffer_id :: non_neg_integer(), version :: non_neg_integer(), %{required(atom()) => [{non_neg_integer(), non_neg_integer()}]}} | {:request_reparse, buffer_id :: non_neg_integer()} | {:log_message, level :: String.t(), text :: String.t()} | {:gui_action, MingaEditor.Frontend.Protocol.GUI.gui_action()} | {:request_keyframe, last_good_frame_seq :: non_neg_integer()}
An input event decoded from Zig.
@type input_seq() :: non_neg_integer()
A frontend-originated input correlation sequence (u32).
Stamped by the frontend at input decode for end-to-end keystroke latency
instrumentation (ticket #2215). The BEAM echoes the latest processed sequence
back on commit_frame. 0 means "no correlation" (legacy frontends that omit it).
@type modifiers() :: non_neg_integer()
Modifier flag bitmask.
@type mouse_button() :: :left | :middle | :right | :none | :wheel_up | :wheel_down | :wheel_right | :wheel_left | {:unknown, non_neg_integer()}
Mouse button identifier.
@type mouse_event_type() :: :press | :release | :motion | :drag | {:unknown, non_neg_integer()}
Mouse event type.
Functions
@spec decode_event(binary()) :: {:ok, input_event()} | {:error, :unknown_opcode | :malformed}
Decodes an input event from a binary payload.
@spec encode_begin_frame(non_neg_integer(), non_neg_integer()) :: binary()
Encodes a begin_frame command that opens a frame transaction (#2219).
frame_seq is the strictly monotonic global frame sequence (reuses
Renderer.Server's seq) used for resync/attach ordering. base_frame_seq names
the frame this transaction's deltas assume; base_frame_seq == 0 means keyframe
(full snapshots, no deltas). Both fields are masked to u32 so a large monotonic
frame_seq stays wire-safe. fixed:9 = opcode(1) + frame_seq(u32) + base(u32).
@spec encode_commit_frame(non_neg_integer(), input_seq()) :: binary()
Encodes a commit_frame command that closes a frame transaction (#2219).
frame_seq must match the open begin_frame's frame_seq. input_seq is the
echoed input correlation sequence (formerly carried by batch_end, ticket #2215):
the frontend resolves a keystroke-to-write latency sample when the frame presents.
input_seq defaults to 0 ("no correlation") and is a SEPARATE id from
frame_seq. fixed:9 = opcode(1) + frame_seq(u32) + input_seq(u32).
Encodes a protocol_error command.
The BEAM emits this when a frontend's handshake protocol_version does not
match the BEAM's compiled-in Opcodes.protocol_version(). The frontend
displays the UTF-8 reason as a blocking error instead of trying to decode a
command stream it cannot parse. len16-framed: opcode(1) + len(u16) + message.
@spec encode_register_font(non_neg_integer(), String.t()) :: binary()
Encodes a register_font command to associate a font_id with a font family.
Font ID 0 is the primary font (set via set_font). IDs 1-255 are
secondary fonts that can be referenced by font_id in draw_styled_text.
The GUI creates a FontFace for each registered font at the same size as
the primary. If the secondary font's cell metrics differ from the primary,
the GUI logs a warning and falls back to the primary for those glyphs.
Format: opcode:8, font_id:8, name_len:16, name:bytes
@spec encode_set_font(String.t(), pos_integer(), boolean(), atom()) :: binary()
Encodes a set_font command to configure the GUI frontend's font.
The font family is resolved by the frontend using NSFontManager (macOS) so both display names ("JetBrains Mono") and PostScript names ("JetBrainsMonoNF-Regular") work. The TUI ignores this command.
Format: opcode:8, size:16, weight:8, ligatures:8, name_len:16, name:bytes
Fields are ordered by category: font identity (size, weight, name) then rendering features (ligatures). The variable-length name stays at the end.
Encodes a set_font_fallback command to configure the GUI's font fallback chain.
The fallback chain is tried in order when the primary font (set via set_font)
doesn't have a glyph. Each entry is a font family name resolved by the frontend
via NSFontManager. After the configured fallbacks, the system fallback
(CTFontCreateForString) is used as a last resort.
Format: opcode:8, count:8, [name_len:16, name:bytes]*
Encodes a set_title command to update the terminal window title.
@spec encode_set_window_bg(non_neg_integer()) :: binary()
Encodes a set_window_bg command to set the default background color.
The Zig renderer uses this as the fallback background for any cell
that doesn't specify an explicit bg: value. This prevents cells
from falling back to the terminal's default background, which may
not match the editor theme.
Checks if a modifier flag is set.
@spec mod_alt() :: modifiers()
Returns the ALT modifier flag.
@spec mod_ctrl() :: modifiers()
Returns the CTRL modifier flag.
@spec mod_shift() :: modifiers()
Returns the SHIFT modifier flag.
@spec mod_super() :: modifiers()
Returns the SUPER modifier flag.