A block decoration: fully custom-rendered lines injected between buffer lines.
Block decorations produce styled content from a render callback. That content is inserted into the display line stream at an anchor position. They scroll with the buffer, occupy display rows, and participate in viewport height calculations, but have no buffer line number and no gutter.
This is the equivalent of Zed's BlockProperties (message headers, image
previews, slash command output in the AI chat).
Render callback
The render callback receives the available width and returns styled content in one of three forms:
[{text, style}]— single-line block (most common: headers, separators)[[{text, style}]]— multi-line block (list of segment lists, one per row)[DisplayList.draw()]— raw draw tuples for maximum control
The content renderer normalizes the first two forms into draw tuples positioned at the correct screen rows.
Height
Set height to an explicit integer for blocks with a known, stable height.
Set height to :dynamic for blocks whose height depends on the render
callback output. Dynamic heights are resolved by invoking the callback
during DisplayMap construction. The callback is cached per block per frame,
so it's only called once regardless of height.
Summary
Types
Click callback: receives row offset within block and column.
Render callback: receives available width, returns styled content.
Result from a render callback.
Functions
Normalizes the render callback result into a list of segment lists (one per display line).
Returns the height of the block decoration in display lines.
Types
@type click_fn() :: (row :: non_neg_integer(), col :: non_neg_integer() -> :ok) | nil
Click callback: receives row offset within block and column.
@type render_fn() :: (width :: pos_integer() -> render_result())
Render callback: receives available width, returns styled content.
@type render_result() :: [{String.t(), Minga.Core.Face.t()}] | [[{String.t(), Minga.Core.Face.t()}]]
Result from a render callback.
[{text, style}]— single-line block[[{text, style}]]— multi-line block (list of lines, each a list of segments)
@type t() :: %Minga.Core.Decorations.BlockDecoration{ anchor_line: non_neg_integer(), group: term() | nil, height: pos_integer() | :dynamic, id: reference(), on_click: click_fn(), placement: :above | :below, priority: integer(), render: render_fn() }
Functions
@spec normalize_render_result(render_result()) :: [ [{String.t(), Minga.Core.Face.t()}] ]
Normalizes the render callback result into a list of segment lists (one per display line).
@spec resolve_height(t(), pos_integer()) :: pos_integer()
Returns the height of the block decoration in display lines.
For explicit heights, returns the stored value. For :dynamic heights,
invokes the render callback with the given width to determine the height
from the result.