MingaEditor.Frontend.Protocol (Minga v0.1.0)

Copy Markdown View Source

Binary protocol encoder/decoder for BEAM ↔ Zig 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 (Zig → BEAM)

OpcodeNamePayload
0x01key_presscodepoint::32, modifiers::8
0x02resizewidth::16, height::16
0x03readywidth::16, height::16
0x04mouse_eventrow::16-signed, col::16-signed, button::8, mods::8, type::8

Render Commands (BEAM → Zig)

OpcodeNamePayload
0x10draw_textrow::16, col::16, fg::24, bg::24, attrs::8, text_len::16, text
0x1Cdraw_styled_textrow::16, col::16, fg::24, bg::24, attrs::16, ul_color::24, blend::8, font_weight::8, font_id::8, text_len::16, text
0x11set_cursorrow::16, col::16
0x12clear(empty)
0x13batch_end(empty)
0x15set_cursor_shapeshape::8 (BLOCK=0, BEAM=1, UNDERLINE=2)
0x1Bscroll_regiontop_row::16, bottom_row::16, delta::16-signed

Modifier Flags

FlagValue
SHIFT0x01
CTRL0x02
ALT0x04
SUPER0x08

Summary

Types

Cursor shape.

A highlight span from tree-sitter.

An input event decoded from Zig.

Modifier flag bitmask.

Mouse button identifier.

Mouse event type.

Region role atom.

Text style attributes.

Functions

Decodes a render command from a binary payload (primarily for testing).

Decodes an input event from a binary payload.

Encodes a batch_end command (triggers render flush).

Encodes a clear screen command.

Encodes a clear_region command.

Encodes a set_cursor command.

Encodes a set_cursor_shape command.

Encodes a destroy_region command.

Encodes a draw_text command.

Smart encoder: uses draw_styled_text if the style contains extended attributes, otherwise falls back to the more compact draw_text.

Encodes a draw_styled_text command with extended attributes.

Encodes a register_font command to associate a font_id with a font family.

Encodes a scroll_region command for terminal scroll optimization.

Encodes a set_active_region command. Pass 0 to reset to root.

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

conceal_span()

@type conceal_span() :: Minga.Parser.Protocol.conceal_span()

cursor_shape()

@type cursor_shape() :: :block | :beam | :underline

Cursor shape.

edit_delta()

@type edit_delta() :: Minga.Parser.Protocol.edit_delta()

highlight_span()

@type highlight_span() :: Minga.Language.Highlight.Span.t()

A highlight span from tree-sitter.

input_event()

@type input_event() ::
  {:key_press, codepoint :: non_neg_integer(), modifiers()}
  | {: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()}
  | {: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}
  | {: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()}

An input event decoded from Zig.

modifiers()

@type modifiers() :: non_neg_integer()

Modifier flag bitmask.

mouse_button()

@type mouse_button() ::
  :left
  | :middle
  | :right
  | :none
  | :wheel_up
  | :wheel_down
  | :wheel_right
  | :wheel_left
  | {:unknown, non_neg_integer()}

Mouse button identifier.

mouse_event_type()

@type mouse_event_type() ::
  :press | :release | :motion | :drag | {:unknown, non_neg_integer()}

Mouse event type.

region_role()

@type region_role() ::
  :editor | :modeline | :minibuffer | :gutter | :popup | :panel | :border

Region role atom.

style()

@type style() :: [
  fg: non_neg_integer(),
  bg: non_neg_integer(),
  bold: boolean(),
  underline: boolean(),
  italic: boolean(),
  reverse: boolean(),
  strikethrough: boolean(),
  underline_style: :line | :curl | :dashed | :dotted | :double,
  underline_color: non_neg_integer(),
  blend: 0..100,
  font_weight:
    :thin | :light | :regular | :medium | :semibold | :bold | :heavy | :black,
  font_id: non_neg_integer()
]

Text style attributes.

Functions

decode_command(arg)

@spec decode_command(binary()) ::
  {:ok,
   :clear
   | :batch_end
   | {:draw_text, map()}
   | {:draw_styled_text, map()}
   | {:set_cursor, non_neg_integer(), non_neg_integer()}
   | {:set_cursor_shape, cursor_shape()}}
  | {:error, :unknown_opcode | :malformed}

Decodes a render command from a binary payload (primarily for testing).

decode_event(data)

@spec decode_event(binary()) ::
  {:ok, input_event()} | {:error, :unknown_opcode | :malformed}

Decodes an input event from a binary payload.

encode_batch_end()

@spec encode_batch_end() :: binary()

Encodes a batch_end command (triggers render flush).

encode_clear()

@spec encode_clear() :: binary()

Encodes a clear screen command.

encode_clear_region(id)

@spec encode_clear_region(non_neg_integer()) :: binary()

Encodes a clear_region command.

encode_close_buffer(buffer_id)

See Minga.Parser.Protocol.encode_close_buffer/1.

encode_cursor(row, col)

@spec encode_cursor(non_neg_integer(), non_neg_integer()) :: binary()

Encodes a set_cursor command.

encode_cursor_shape(atom)

@spec encode_cursor_shape(cursor_shape()) :: binary()

Encodes a set_cursor_shape command.

encode_define_region(id, parent_id, role, row, col, width, height, z_order)

Encodes a define_region command.

encode_destroy_region(id)

@spec encode_destroy_region(non_neg_integer()) :: binary()

Encodes a destroy_region command.

encode_draw(row, col, text, style \\ [])

@spec encode_draw(non_neg_integer(), non_neg_integer(), String.t(), style()) ::
  binary()

Encodes a draw_text command.

encode_draw_smart(row, col, text, style \\ [])

@spec encode_draw_smart(non_neg_integer(), non_neg_integer(), String.t(), style()) ::
  binary()

Smart encoder: uses draw_styled_text if the style contains extended attributes, otherwise falls back to the more compact draw_text.

encode_draw_styled(row, col, text, style \\ [])

@spec encode_draw_styled(non_neg_integer(), non_neg_integer(), String.t(), style()) ::
  binary()

Encodes a draw_styled_text command with extended attributes.

Extended over draw_text with:

  • attrs expanded to 16 bits (adds strikethrough 0x10, underline_style 3 bits at 0xE0)
  • underline_color as a separate 24-bit RGB field (0x000000 = use fg)
  • blend as an 8-bit opacity value (0-100, 100 = fully opaque)
  • font_weight as an 8-bit weight index (0-7, maps to thin through black)

Use this for text that needs underline styles, strikethrough, underline color, blend, or per-span font weight. For simple text (fg/bg/bold/italic/underline/reverse), encode_draw/4 is more compact.

encode_edit_buffer(buffer_id, version, edits)

See Minga.Parser.Protocol.encode_edit_buffer/3.

encode_load_grammar(name, path)

See Minga.Parser.Protocol.encode_load_grammar/2.

encode_parse_buffer(buffer_id, version, source)

See Minga.Parser.Protocol.encode_parse_buffer/3.

encode_query_language_at(buffer_id, request_id, byte_offset)

See Minga.Parser.Protocol.encode_query_language_at/3.

encode_register_font(font_id, family)

@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

encode_request_indent(buffer_id, request_id, line)

See Minga.Parser.Protocol.encode_request_indent/3.

encode_request_textobject(buffer_id, request_id, row, col, capture_name)

See Minga.Parser.Protocol.encode_request_textobject/5.

encode_scroll_region(top_row, bottom_row, delta)

@spec encode_scroll_region(non_neg_integer(), non_neg_integer(), integer()) ::
  binary()

Encodes a scroll_region command for terminal scroll optimization.

Tells the Zig renderer to use ANSI scroll region sequences to shift content within the given screen row range by delta lines, avoiding a full redraw.

  • top_row / bottom_row — screen row range (inclusive) for the scroll region.
  • delta — positive = scroll up (content moves up, new lines at bottom),
          negative = scroll down (content moves down, new lines at top).

Wire format: opcode(1) + top_row(2) + bottom_row(2) + delta(2, signed) = 7 bytes.

encode_set_active_region(id)

@spec encode_set_active_region(non_neg_integer()) :: binary()

Encodes a set_active_region command. Pass 0 to reset to root.

encode_set_fold_query(buffer_id, query)

See Minga.Parser.Protocol.encode_set_fold_query/2.

encode_set_font(family, size, ligatures, weight \\ :regular)

@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.

encode_set_font_fallback(families)

@spec encode_set_font_fallback([String.t()]) :: binary()

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]*

encode_set_highlight_query(buffer_id, query)

See Minga.Parser.Protocol.encode_set_highlight_query/2.

encode_set_indent_query(buffer_id, query)

See Minga.Parser.Protocol.encode_set_indent_query/2.

encode_set_injection_query(buffer_id, query)

See Minga.Parser.Protocol.encode_set_injection_query/2.

encode_set_language(buffer_id, name)

See Minga.Parser.Protocol.encode_set_language/2.

encode_set_textobject_query(buffer_id, query)

See Minga.Parser.Protocol.encode_set_textobject_query/2.

encode_set_title(title)

@spec encode_set_title(String.t()) :: binary()

Encodes a set_title command to update the terminal window title.

encode_set_window_bg(rgb)

@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.

has_modifier?(mods, flag)

@spec has_modifier?(modifiers(), modifiers()) :: boolean()

Checks if a modifier flag is set.

mod_alt()

@spec mod_alt() :: modifiers()

Returns the ALT modifier flag.

mod_ctrl()

@spec mod_ctrl() :: modifiers()

Returns the CTRL modifier flag.

mod_shift()

@spec mod_shift() :: modifiers()

Returns the SHIFT modifier flag.

mod_super()

@spec mod_super() :: modifiers()

Returns the SUPER modifier flag.