Skip to content

xnano.core.controller

xnano.core.controller

xnano.core.controller


Paint grids through their complete layout pipeline.

Classes:

TerminalController

TerminalController(runtime: Any)

Collect absolute paint requests for one native frame.

Methods:

  • paint_clear

    Blank area at z so an overlay occludes the content below it.

  • align_slot_content

    Return the sub-area a field's content paints into.

Source code in xnano/core/controller.py
def __init__(self, runtime: Any) -> None:
    self.runtime = runtime
    self.nodes: list[Any] = []

paint_clear

paint_clear(area: Area, *, z: int = 0) -> None

Blank area at z so an overlay occludes the content below it.

ratatui styles a bordered block's interior but leaves the glyphs under it intact; a popup must clear first to read as opaque.

Source code in xnano/core/controller.py
def paint_clear(self, area: Area, *, z: int = 0) -> None:
    """Blank ``area`` at ``z`` so an overlay occludes the content below it.

    ratatui styles a bordered block's interior but leaves the glyphs
    under it intact; a popup must clear first to read as opaque.
    """
    self._paint(Clear(), area, z=z)

align_slot_content

align_slot_content(
    value: Any, area: Area, field: Any, *, parent_z: int = 0
) -> Area

Return the sub-area a field's content paints into.

Vertical alignment has no ratatui equivalent — Paragraph only aligns horizontally — so a non-"top" vertical_align is resolved here by offsetting the slot's origin. Nested grids are excluded: they fill their slot and have no intrinsic height.

Source code in xnano/core/controller.py
def align_slot_content(
    self,
    value: Any,
    area: Area,
    field: Any,
    *,
    parent_z: int = 0,
) -> Area:
    """Return the sub-area a field's content paints into.

    Vertical alignment has no ratatui equivalent — ``Paragraph`` only
    aligns horizontally — so a non-``"top"`` ``vertical_align`` is
    resolved here by offsetting the slot's origin. Nested grids are
    excluded: they fill their slot and have no intrinsic height.
    """
    vertical = getattr(field, "vertical_align", None)
    if vertical is None or vertical == "top":
        return area
    if is_grid(value):
        return area
    # Prefer the value's own text: a component's ``get_size`` reports 0
    # for the zero-height probe area ``measure_field_slot`` builds, which
    # would silently skip alignment.
    text = _string_content(value)
    if text is not None:
        height = wrapped_line_count(text, area.width)
    elif callable(getattr(value, "get_size", None)):
        height = self.measure_field_slot(
            value, "vertical", field, available_width=area.width
        )
    else:
        return area
    if height <= 0 or height >= area.height:
        return area
    leftover = area.height - height
    offset = leftover // 2 if vertical == "middle" else leftover
    if offset <= 0:
        return area
    # Only the origin moves; the content keeps every remaining row so an
    # under-measured value (a component whose real height exceeds its
    # declared size) is never clipped by alignment alone.
    background = getattr(field, "background", None)
    if background is not None:
        self._paint(TextBlock(background=background), area, z=parent_z - 1)
    return Area(
        x=area.x,
        y=area.y + offset,
        width=area.width,
        height=area.height - offset,
    )

wrapped_line_count

wrapped_line_count(text: str, width: int) -> int

Return how many rows text occupies when wrapped at width.

ratatui wraps on word boundaries, so a raw splitlines() count is short for any line longer than its slot. textwrap matches that behavior closely enough to place content; it is not a substitute for ratatui's own measurement.

ponytail: approximates unicode width as one cell per character. Bind ratatui's Paragraph::line_count if wide glyphs need exact rows.

Source code in xnano/core/controller.py
def wrapped_line_count(text: str, width: int) -> int:
    """Return how many rows ``text`` occupies when wrapped at ``width``.

    ratatui wraps on word boundaries, so a raw ``splitlines()`` count is
    short for any line longer than its slot. ``textwrap`` matches that
    behavior closely enough to place content; it is not a substitute for
    ratatui's own measurement.

    ponytail: approximates unicode width as one cell per character. Bind
    ratatui's ``Paragraph::line_count`` if wide glyphs need exact rows.
    """
    lines = text.splitlines() or [""]
    if width <= 0:
        return len(lines)
    total = 0
    for line in lines:
        if len(line) <= width:
            total += 1
        else:
            total += (
                len(
                    textwrap.wrap(
                        line,
                        width=width,
                        break_long_words=True,
                        break_on_hyphens=False,
                    )
                )
                or 1
            )
    return total

content_scroll_extent

content_scroll_extent(value: Any, axis: str) -> int

Measure a scroll field's total content extent along axis.

Rows for the "y" axis, columns for "x". Falls back to a component's declared size when the value is not row-oriented text.

Source code in xnano/core/controller.py
def content_scroll_extent(value: Any, axis: str) -> int:
    """Measure a scroll field's total content extent along ``axis``.

    Rows for the ``"y"`` axis, columns for ``"x"``. Falls back to a
    component's declared size when the value is not row-oriented text.
    """
    text = _string_content(value)
    if text is not None:
        lines = text.split("\n")
        if axis == "y":
            return len(lines)
        return max((len(line) for line in lines), default=0)
    if isinstance(value, collections.abc.Sequence) and not isinstance(
        value, (str, bytes)
    ):
        return sum(content_scroll_extent(item, axis) for item in value)
    return 0

window_scroll_value

window_scroll_value(
    value: Any, offset: int, axis: str
) -> Any

Return value windowed by offset cells along axis.

Drops the leading offset rows/columns of plain-string content so the fixed-height slot (which clips the bottom natively) shows the window. Non-text values are returned unchanged.

Source code in xnano/core/controller.py
def window_scroll_value(value: Any, offset: int, axis: str) -> Any:
    """Return ``value`` windowed by ``offset`` cells along ``axis``.

    Drops the leading ``offset`` rows/columns of plain-string content so the
    fixed-height slot (which clips the bottom natively) shows the window.
    Non-text values are returned unchanged.
    """
    if offset <= 0:
        return value
    text = _string_content(value)
    if text is None:
        return value
    if axis == "y":
        windowed = "\n".join(text.split("\n")[offset:])
    else:
        windowed = "\n".join(line[offset:] for line in text.split("\n"))
    if isinstance(value, str):
        return windowed
    clone = copy.copy(value)
    object.__setattr__(clone, "content", windowed)
    return clone