Skip to content

xnano.core

xnano.core

xnano.core


Run interfaces live or offscreen and inspect their rendered frames.

Modules:

Classes:

  • Exit

    Request that the active runtime stop.

  • HookError

    Report a hook failure while preserving its original cause.

  • Frame

    Immutable snapshot of one painted native frame.

  • Runtime

    Drive one application through an xnano_core session.

  • Cursor

    Show, hide, style, and move the caret for a Runtime session.

  • Device

    Control device settings for a Runtime session.

Functions:

Exit

Bases: BaseException

Request that the active runtime stop.

HookError

HookError(hook_name: str, cause: BaseException)

Bases: RuntimeError

Report a hook failure while preserving its original cause.

Source code in xnano/core/exceptions.py
def __init__(self, hook_name: str, cause: BaseException) -> None:
    self.hook_name = hook_name
    self.cause = cause
    super().__init__(f"Hook {hook_name!r} raised: {cause!r}")
    self.__cause__ = cause

Frame dataclass

Frame(
    width: int,
    height: int,
    text: str = "",
    ansi: str = "",
    cursor_position: tuple[int, int] | None = None,
    cursor_visible: bool = True,
    cursor_style: str | None = None,
    title: str | None = None,
    commands: tuple[Mapping[str, Any], ...] = (),
    revision: int = 0,
)

Immutable snapshot of one painted native frame.

Example

Frame(width=20, height=4, text="Ready")

Attributes:

Methods:

  • contains

    Return whether plain text contains needle.

width instance-attribute

width: int

Frame width in cells.

height instance-attribute

height: int

Frame height in cells.

text class-attribute instance-attribute

text: str = ''

Plain-text cell rows.

ansi class-attribute instance-attribute

ansi: str = ''

ANSI-styled cell rows.

cursor_position class-attribute instance-attribute

cursor_position: tuple[int, int] | None = None

Caret position in cells.

cursor_visible class-attribute instance-attribute

cursor_visible: bool = True

Whether the caret is visible.

cursor_style class-attribute instance-attribute

cursor_style: str | None = None

Caret shape and blink style.

title class-attribute instance-attribute

title: str | None = None

Window or document title.

commands class-attribute instance-attribute

commands: tuple[Mapping[str, Any], ...] = ()

Device commands emitted with the frame.

revision class-attribute instance-attribute

revision: int = 0

Monotonic frame revision.

rows property

rows: tuple[str, ...]

Plain-text rows of the frame.

contains

contains(needle: str) -> bool

Return whether plain text contains needle.

Source code in xnano/core/frame.py
def contains(self, needle: str) -> bool:
    """Return whether plain text contains ``needle``."""
    return needle in self.text

Runtime

Runtime(
    session: CoreSession,
    *,
    live: bool,
    state: StateT | None = None,
    title: str | None = None,
    surface: str = "terminal",
    tick_interval: int = 16
)

Bases: Generic[StateT]

Drive one application through an xnano_core session.

Most applications use :class:xnano.terminal.Terminal; use Runtime directly when you need explicit session ownership.

Attributes:

Example

runtime = Runtime.offscreen(24, 3) frame = runtime.render("Hello") frame.width, frame.height (24, 3) runtime.close()

Methods:

  • live

    Create a runtime backed by the active terminal.

  • offscreen

    Create an active in-memory runtime.

  • supports_live_terminal

    Return whether this build can claim a live terminal.

  • enter

    Bind this runtime to the current context.

  • close

    Restore the native session and release the active binding.

  • set_root

    Set the renderable used by subsequent empty renders.

  • render

    Render one frame and return its immutable snapshot.

  • call_soon

    Schedule callback to run on the UI thread before the next pump.

  • pump

    Poll and dispatch at most one event.

  • dispatch

    Dispatch one event to the root grid or component.

  • play_effect

    Play an effect over fields recorded by the latest render.

  • cancel_effect

    Stop the effect registered under key.

  • is_animating

    Whether any effect is currently running in this session.

  • perform

    Perform a synthetic action through its event representation.

  • resize

    Resize support is fixed at offscreen-session construction.

  • request_exit

    Stop the run loop after the current dispatch.

  • focus

    Focus a named field group.

  • blur

    Clear field focus.

  • focus_next

    Move focus through the root grid when supported.

  • focus_previous

    Move focus backward through the root grid when supported.

  • get_output

    Return the current buffer as plain text.

  • get_output_as_ansi

    Return the current buffer with ANSI styling.

Source code in xnano/core/runtime.py
def __init__(
    self,
    session: CoreSession,
    *,
    live: bool,
    state: StateT | None = None,
    title: str | None = None,
    surface: str = "terminal",
    tick_interval: int = 16,
) -> None:
    self._session = session
    self._live = live
    self._state = state
    self._surface = surface
    self._root: Any = None
    self._revision = 0
    self._closed = False
    self._should_exit = False
    self._focused_group: str | None = None
    self._token: contextvars.Token[Runtime[Any] | None] | None = None
    self._frame_commands: list[dict[str, Any]] = []
    self._stage = Stage()
    self._elapsed_ms = 0
    self._tick_hook_times: dict[tuple[int, str], int] = {}
    self._post_init_grids: set[int] = set()
    self._watch_values: dict[tuple[int, str, str], Any] = {}
    self._grid_breakpoints: dict[int, str] = {}
    self._tick_interval = max(1, tick_interval)
    self._last_tick_ms = time.monotonic() * 1000
    self._signals_installed = False
    self._prev_signal_handlers: dict[signal.Signals, Any] = {}
    self._cursor = Cursor(self)
    self._device = Device(self)
    self._actions = Actions(self)
    self._call_soon_queue: collections.deque[
        tuple[Callable[..., Any], tuple[Any, ...]]
    ] = collections.deque()
    self._call_soon_lock = threading.Lock()
    if title is not None:
        self._device.title = title

session property

session: CoreSession

Native session owned by this runtime.

terminal property

terminal: 'Runtime[StateT]'

Compatibility name for the runtime's terminal surface.

surface property

surface: str

Presentation surface name.

is_live property

is_live: bool

Whether the runtime owns the user's terminal.

state property writable

state: StateT | None

Application state shared with hooks.

device property

device: Device

Display controls for this session.

cursor property

cursor: Cursor

Caret controls for this session.

actions property

actions: Actions

Synthetic action performer for this session.

stage property

stage: Stage

Current layout stage when a grid has rendered.

size property

size: tuple[int, int]

Viewport width and height in cells.

focused_group property

focused_group: str | None

Name of the focused field group.

live classmethod

live(
    *,
    state: StateT | None = None,
    title: str | None = None,
    tick_interval: int = 16,
    mouse_events: bool = False
) -> "Runtime[StateT]"

Create a runtime backed by the active terminal.

Source code in xnano/core/runtime.py
@classmethod
def live(
    cls,
    *,
    state: StateT | None = None,
    title: str | None = None,
    tick_interval: int = 16,
    mouse_events: bool = False,
) -> "Runtime[StateT]":
    """Create a runtime backed by the active terminal."""
    session = CoreSession.init(tick_rate_ms=None)
    if mouse_events:
        session.enable_mouse_capture()
    return cls(
        session,
        live=True,
        state=state,
        title=title,
        tick_interval=tick_interval,
    )

offscreen classmethod

offscreen(
    width: int = 80,
    height: int = 24,
    *,
    state: StateT | None = None,
    title: str | None = None
) -> "Runtime[StateT]"

Create an active in-memory runtime.

Source code in xnano/core/runtime.py
@classmethod
def offscreen(
    cls,
    width: int = 80,
    height: int = 24,
    *,
    state: StateT | None = None,
    title: str | None = None,
) -> "Runtime[StateT]":
    """Create an active in-memory runtime."""
    runtime = cls(
        CoreSession.offscreen(width, height),
        live=False,
        state=state,
        title=title,
        surface="offscreen",
    )
    return runtime.enter()

supports_live_terminal staticmethod

supports_live_terminal() -> bool

Return whether this build can claim a live terminal.

Source code in xnano/core/runtime.py
@staticmethod
def supports_live_terminal() -> bool:
    """Return whether this build can claim a live terminal."""
    return CoreSession.supports_live_terminal()

enter

enter() -> 'Runtime[StateT]'

Bind this runtime to the current context.

Source code in xnano/core/runtime.py
def enter(self) -> "Runtime[StateT]":
    """Bind this runtime to the current context."""
    if self._token is None:
        self._token = _ACTIVE_RUNTIME.set(self)
    if self._live:
        self._install_signal_handlers()
    return self

close

close() -> None

Restore the native session and release the active binding.

Source code in xnano/core/runtime.py
def close(self) -> None:
    """Restore the native session and release the active binding."""
    if self._closed:
        return
    self._closed = True
    if self._token is not None:
        _ACTIVE_RUNTIME.reset(self._token)
        self._token = None
    # Restore the host terminal first (raw mode, mouse tracking,
    # alternate screen, SGR) so a failure restoring signal handlers
    # never leaves the screen corrupted.
    try:
        self._session.restore()
    finally:
        # Runtime owns cursor/device/action proxies that point back to it,
        # so the Python object can remain in a reference cycle after
        # close. Release the unsendable PyO3 session now, on its owner
        # thread, instead of leaving its destructor to a later GC pass.
        del self._session
        self._restore_signal_handlers()

set_root

set_root(root: Any) -> None

Set the renderable used by subsequent empty renders.

Source code in xnano/core/runtime.py
def set_root(self, root: Any) -> None:
    """Set the renderable used by subsequent empty renders."""
    self._root = root

render

render(
    *renderables: Any,
    foreground: ColorLike | None = None,
    background: ColorLike | None = None,
    modifiers: Sequence[CharacterModifier] | None = None,
    horizontal_align: Alignment | None = None,
    vertical_align: VerticalAlignment | None = None,
    border: Border | None = None,
    border_sides: Sequence[Side] | None = None,
    border_color: ColorLike | None = None,
    title: str | None = None,
    title_position: FrameTitlePosition | None = None,
    padding: PaddingLike | None = None,
    gap: int = 0,
    direction: Direction = "vertical",
    color: ColorLike | None = None,
    align: Alignment | None = None
) -> Frame

Render one frame and return its immutable snapshot.

Source code in xnano/core/runtime.py
def render(
    self,
    *renderables: Any,
    foreground: ColorLike | None = None,
    background: ColorLike | None = None,
    modifiers: Sequence[CharacterModifier] | None = None,
    horizontal_align: Alignment | None = None,
    vertical_align: VerticalAlignment | None = None,
    border: Border | None = None,
    border_sides: Sequence[Side] | None = None,
    border_color: ColorLike | None = None,
    title: str | None = None,
    title_position: FrameTitlePosition | None = None,
    padding: PaddingLike | None = None,
    gap: int = 0,
    direction: Direction = "vertical",
    color: ColorLike | None = None,
    align: Alignment | None = None,
) -> Frame:
    """Render one frame and return its immutable snapshot."""
    foreground = resolve_color_alias(foreground, color, stacklevel=3)
    horizontal_align = resolve_renamed_alias(
        horizontal_align,
        align,
        old="align",
        new="horizontal_align",
        stacklevel=3,
    )
    self._render(
        *renderables,
        foreground=foreground,
        background=background,
        modifiers=modifiers,
        horizontal_align=horizontal_align,
        vertical_align=vertical_align,
        border=border,
        border_sides=border_sides,
        border_color=border_color,
        title=title,
        title_position=title_position,
        padding=padding,
        gap=gap,
        direction=direction,
    )
    return self._snapshot_frame()

call_soon

call_soon(callback: Callable[..., Any], *args: Any) -> None

Schedule callback to run on the UI thread before the next pump.

Thread-safe: worker threads enqueue here and the runtime drains the queue on its own thread, so background work can mutate grid state without racing the renderer.

Source code in xnano/core/runtime.py
def call_soon(self, callback: Callable[..., Any], *args: Any) -> None:
    """Schedule ``callback`` to run on the UI thread before the next pump.

    Thread-safe: worker threads enqueue here and the runtime drains the
    queue on its own thread, so background work can mutate grid state
    without racing the renderer.
    """
    with self._call_soon_lock:
        self._call_soon_queue.append((callback, args))

pump

pump(timeout: float = 0.0) -> bool

Poll and dispatch at most one event.

Source code in xnano/core/runtime.py
def pump(self, timeout: float = 0.0) -> bool:
    """Poll and dispatch at most one event."""
    self._drain_call_soon()
    if self._should_exit:
        return False
    timeout_ms = max(0, int(timeout * 1000))
    if self._live and timeout_ms == 0:
        timeout_ms = self._tick_interval
    native_event = self._session.poll_event(timeout_ms)
    if native_event is not None:
        self.dispatch(event_from_core(native_event))
    elif self._root is not None:
        from xnano.core.dispatch import dispatch_idle

        dispatch_idle(self._root, self)
    if self._root is not None:
        from xnano.events import Event, TickEventData

        now = time.monotonic() * 1000
        elapsed_ms = max(0, int(now - self._last_tick_ms))
        self._last_tick_ms = now
        self.dispatch(
            Event.from_data(TickEventData(elapsed_ms=elapsed_ms))
        )
    return not self._should_exit

dispatch

dispatch(event: Any) -> None

Dispatch one event to the root grid or component.

Source code in xnano/core/runtime.py
def dispatch(self, event: Any) -> None:
    """Dispatch one event to the root grid or component."""
    from xnano.core.dispatch import dispatch_event
    from xnano.utils.focus import (
        apply_text_keyboard,
        cycle_field_focus,
        focused_component,
        move_field_focus,
        spatial_focus_enabled,
    )

    consumed = False
    mouse = getattr(event, "mouse_event", None)
    if mouse is not None and mouse.field is None:
        from xnano.core.dispatch import iter_grids
        from xnano.events import Event, MouseEventData

        for grid in iter_grids(self._root):
            for hit in reversed(getattr(grid, "_grid_field_hits", ())):
                if hit.area.contains((mouse.x, mouse.y)):
                    field = hit.grid._grid_field_info(hit.field_name)
                    self._auto_scroll_wheel(hit, field, mouse.kind)
                    self._click_to_focus(hit, field, mouse.kind)
                    component = getattr(hit.grid, hit.field_name, None)
                    hover = getattr(component, "handle_hover", None)
                    if callable(hover):
                        hover(mouse.x, mouse.y)
                    event = Event.from_data(
                        MouseEventData(
                            kind=mouse.kind,
                            x=mouse.x,
                            y=mouse.y,
                            button=mouse.button,
                            field=hit.field_name,
                            group=field.group,
                        )
                    )
                    break
    keyboard = getattr(event, "keyboard_event", None)
    if keyboard is not None:
        if keyboard.matches("ctrl+c"):
            self.request_exit()
            return
        if keyboard.matches("tab"):
            consumed = cycle_field_focus(self)
        elif keyboard.matches("shift+tab"):
            consumed = cycle_field_focus(self, -1)
        else:
            consumed = apply_text_keyboard(
                focused_component(self),
                keyboard,
            )
            if not consumed and spatial_focus_enabled(self):
                for direction in ("up", "down", "left", "right"):
                    if keyboard.matches(direction):
                        consumed = move_field_focus(self, direction)
                        break
    clipboard = getattr(event, "clipboard_event", None)
    tick = getattr(event, "tick_event", None)
    if tick is not None:
        self._elapsed_ms += tick.elapsed_ms
    component = focused_component(self)
    if clipboard is not None and component is not None:
        paste_handler = getattr(component, "handle_paste", None)
        if callable(paste_handler):
            consumed = (
                bool(paste_handler(clipboard.text or "")) or consumed
            )
    if self._root is not None and not consumed:
        dispatch_event(self._root, self, event)
    root_dispatch = getattr(self._root, "dispatch_event", None)
    if callable(root_dispatch):
        root_dispatch(event, self)

play_effect

play_effect(
    effect: Any,
    *,
    fields: list[str] | None = None,
    repeat: bool = False
) -> list[str]

Play an effect over fields recorded by the latest render.

Parameters:

  • effect (Any) –

    Effect description.

  • fields (list[str] | None, default: None ) –

    Field names whose rendered areas receive the effect.

  • repeat (bool, default: False ) –

    Loop the effect until it is cancelled, instead of running once for its duration.

Returns:

  • list[str]

    The session keys registered, one per field that had a

  • list[str]

    rendered area. Empty when nothing was targeted.

Source code in xnano/core/runtime.py
def play_effect(
    self,
    effect: Any,
    *,
    fields: list[str] | None = None,
    repeat: bool = False,
) -> list[str]:
    """Play an effect over fields recorded by the latest render.

    Args:
        effect: Effect description.
        fields: Field names whose rendered areas receive the effect.
        repeat: Loop the effect until it is cancelled, instead of
            running once for its duration.

    Returns:
        The session keys registered, one per field that had a
        rendered area. Empty when nothing was targeted.
    """
    import xnano_core.rust.native as native

    from xnano.core.effects import resolve_native_effect

    keys: list[str] = []
    lowered = None
    for field in fields or ():
        area = self._session.effect_area_for(field)
        if area is None:
            continue
        if lowered is None:
            # Lower once, not once per target field.
            lowered = resolve_native_effect(effect)
            if repeat:
                lowered = native.repeating_effect(lowered)
        key = f"{getattr(effect, 'key', None) or field}:{field}"
        self._session.add_unique_effect(key, lowered.with_area(area))
        keys.append(key)
    return keys

cancel_effect

cancel_effect(key: str) -> None

Stop the effect registered under key.

Source code in xnano/core/runtime.py
def cancel_effect(self, key: str) -> None:
    """Stop the effect registered under ``key``."""
    self._session.cancel_effect(key)

is_animating

is_animating() -> bool

Whether any effect is currently running in this session.

Source code in xnano/core/runtime.py
def is_animating(self) -> bool:
    """Whether any effect is currently running in this session."""
    return bool(self._session.is_animating())

perform

perform(action: Any) -> None

Perform a synthetic action through its event representation.

Source code in xnano/core/runtime.py
def perform(self, action: Any) -> None:
    """Perform a synthetic action through its event representation."""
    from xnano.actions import (
        ClickAction,
        ClipboardAction,
        FocusAction,
        KeyboardAction,
        MouseAction,
        RequestAction,
        ResizeAction,
        TickAction,
    )
    from xnano.events import (
        ClipboardEventData,
        Event,
        FocusEventData,
        KeyboardEventData,
        MouseEventData,
        ResizeEventData,
        TickEventData,
    )

    if isinstance(action, KeyboardAction):
        for binding in action.bindings:
            self.dispatch(
                Event.from_data(
                    KeyboardEventData.from_binding(
                        str(binding),
                        kind=action.kind or "press",
                    )
                )
            )
        return
    if isinstance(action, MouseAction):
        self.dispatch(
            Event.from_data(
                MouseEventData(
                    kind=action.kind or "press",
                    x=0,
                    y=0,
                    button=action.buttons[0]
                    if action.buttons
                    else "unknown",
                )
            )
        )
        return
    if isinstance(action, ClickAction):
        event = Event.from_data(
            MouseEventData(
                kind="press",
                x=0,
                y=0,
                button=action.button,
                field=action.field,
            )
        )
        self.dispatch(event)
        return
    if isinstance(action, FocusAction):
        self.dispatch(
            Event.from_data(
                FocusEventData(
                    kind=action.kind or "gained",
                    field=action.field,
                )
            )
        )
        return
    if isinstance(action, ClipboardAction):
        self.dispatch(
            Event.from_data(ClipboardEventData(text=action.text))
        )
        return
    if isinstance(action, ResizeAction):
        self.dispatch(
            Event.from_data(
                ResizeEventData(
                    width=action.width or self.size[0],
                    height=action.height or self.size[1],
                )
            )
        )
        return
    if isinstance(action, TickAction):
        self.dispatch(
            Event.from_data(
                TickEventData(elapsed_ms=action.interval_ms),
            )
        )
        return
    if isinstance(action, RequestAction) and self._root is not None:
        from xnano.requests import dispatch_request

        dispatch_request(
            self._root,
            action.method,
            action.path,
            runtime=self,
        )
        return
    self.dispatch(action)

resize

resize(width: int, height: int) -> None

Resize support is fixed at offscreen-session construction.

Source code in xnano/core/runtime.py
def resize(self, width: int, height: int) -> None:
    """Resize support is fixed at offscreen-session construction."""
    if self.size != (width, height):
        raise RuntimeError("Create a new offscreen runtime to resize it.")

request_exit

request_exit() -> None

Stop the run loop after the current dispatch.

Source code in xnano/core/runtime.py
def request_exit(self) -> None:
    """Stop the run loop after the current dispatch."""
    self._should_exit = True

focus

focus(group: str) -> bool

Focus a named field group.

Source code in xnano/core/runtime.py
def focus(self, group: str) -> bool:
    """Focus a named field group."""
    from xnano.utils.focus import (
        resolve_group_target,
        set_field_focus,
    )

    target = resolve_group_target(self, group)
    if target is None:
        return False
    set_field_focus(self, target)
    return True

blur

blur() -> None

Clear field focus.

Source code in xnano/core/runtime.py
def blur(self) -> None:
    """Clear field focus."""
    from xnano.utils.focus import clear_field_focus

    clear_field_focus(self)
    self._focused_group = None

focus_next

focus_next() -> bool

Move focus through the root grid when supported.

Source code in xnano/core/runtime.py
def focus_next(self) -> bool:
    """Move focus through the root grid when supported."""
    from xnano.utils.focus import cycle_field_focus

    return cycle_field_focus(self)

focus_previous

focus_previous() -> bool

Move focus backward through the root grid when supported.

Source code in xnano/core/runtime.py
def focus_previous(self) -> bool:
    """Move focus backward through the root grid when supported."""
    from xnano.utils.focus import cycle_field_focus

    return cycle_field_focus(self, -1)

get_output

get_output() -> str

Return the current buffer as plain text.

Source code in xnano/core/runtime.py
def get_output(self) -> str:
    """Return the current buffer as plain text."""
    return "\n".join(self._session.buffer_snapshot().to_string_lines())

get_output_as_ansi

get_output_as_ansi() -> str

Return the current buffer with ANSI styling.

Source code in xnano/core/runtime.py
def get_output_as_ansi(self) -> str:
    """Return the current buffer with ANSI styling."""
    return "\n".join(self._session.buffer_snapshot().to_ansi_lines())

Cursor

Cursor(runtime: 'Runtime')

Show, hide, style, and move the caret for a Runtime session.

Obtained from runtime.cursor — do not construct this class yourself.

Attributes:

Example

from xnano.core.runtime import Runtime runtime = Runtime.offscreen(20, 4) runtime.cursor.position = (3, 1) runtime.cursor.position (3, 1) runtime.close()

Methods:

  • get_position

    The locally tracked (x, y) caret position.

  • move

    Move the caret to (x, y).

  • move_up

    Move the caret up by count rows.

  • move_down

    Move the caret down by count rows.

  • move_left

    Move the caret left by count columns.

  • move_right

    Move the caret right by count columns.

  • save

    Save the current caret position.

  • restore

    Restore the previously saved caret position.

  • enable_blinking

    Enable caret blinking.

  • disable_blinking

    Disable caret blinking.

Source code in xnano/cursor.py
def __init__(self, runtime: "Runtime") -> None:
    self._runtime = runtime
    self._visible = True
    self._style: CursorStyle = "default"
    self._x = 0
    self._y = 0
    self._saved_position: Coordinate | None = None
    self._blinking = True

visible property writable

visible: bool

Whether the caret is currently shown.

style property writable

style: CursorStyle

The caret's rendering style.

position property writable

position: Coordinate

The current (x, y) caret position.

get_position

get_position() -> Coordinate

The locally tracked (x, y) caret position.

Source code in xnano/cursor.py
def get_position(self) -> Coordinate:
    """The locally tracked ``(x, y)`` caret position."""
    return (self._x, self._y)

move

move(x: int, y: int) -> None

Move the caret to (x, y).

Source code in xnano/cursor.py
def move(self, x: int, y: int) -> None:
    """Move the caret to ``(x, y)``."""
    self._x, self._y = x, y
    if self._is_live():
        self._session.move_cursor_to(x, y)

move_up

move_up(count: int = 1) -> None

Move the caret up by count rows.

Source code in xnano/cursor.py
def move_up(self, count: int = 1) -> None:
    """Move the caret up by ``count`` rows."""
    self._y = max(0, self._y - count)
    self.move(self._x, self._y)

move_down

move_down(count: int = 1) -> None

Move the caret down by count rows.

Source code in xnano/cursor.py
def move_down(self, count: int = 1) -> None:
    """Move the caret down by ``count`` rows."""
    self._y += count
    self.move(self._x, self._y)

move_left

move_left(count: int = 1) -> None

Move the caret left by count columns.

Source code in xnano/cursor.py
def move_left(self, count: int = 1) -> None:
    """Move the caret left by ``count`` columns."""
    self._x = max(0, self._x - count)
    self.move(self._x, self._y)

move_right

move_right(count: int = 1) -> None

Move the caret right by count columns.

Source code in xnano/cursor.py
def move_right(self, count: int = 1) -> None:
    """Move the caret right by ``count`` columns."""
    self._x += count
    self.move(self._x, self._y)

save

save() -> None

Save the current caret position.

Source code in xnano/cursor.py
def save(self) -> None:
    """Save the current caret position."""
    self._saved_position = (self._x, self._y)
    if self._is_live():
        self._session.save_cursor_position()

restore

restore() -> None

Restore the previously saved caret position.

Source code in xnano/cursor.py
def restore(self) -> None:
    """Restore the previously saved caret position."""
    if self._saved_position is not None:
        self._x, self._y = self._saved_position
    if self._is_live():
        self._session.restore_cursor_position()

enable_blinking

enable_blinking() -> None

Enable caret blinking.

Source code in xnano/cursor.py
def enable_blinking(self) -> None:
    """Enable caret blinking."""
    self._blinking = True
    if self._style in {"steady_block", "steady_underline", "steady_bar"}:
        self._set_style(
            cast(
                CursorStyle,
                {
                    "steady_block": "blinking_block",
                    "steady_underline": "blinking_underline",
                    "steady_bar": "blinking_bar",
                }[self._style],
            )
        )

disable_blinking

disable_blinking() -> None

Disable caret blinking.

Source code in xnano/cursor.py
def disable_blinking(self) -> None:
    """Disable caret blinking."""
    self._blinking = False
    if self._style.startswith("blinking_"):
        self._set_style(
            cast(
                CursorStyle,
                {
                    "blinking_block": "steady_block",
                    "blinking_underline": "steady_underline",
                    "blinking_bar": "steady_bar",
                }[self._style],
            )
        )

Device

Device(runtime: 'Runtime')

Control device settings for a Runtime session.

Title, clear, size, scroll, clipboard, raw mode, alternate screen, mouse capture, and related flags. Obtained from runtime.device — do not construct this class yourself.

Attributes:

Example

from xnano.core.runtime import Runtime runtime = Runtime.offscreen(20, 4, title="Example") runtime.device.size.width 20 runtime.close()

Methods:

Source code in xnano/device.py
def __init__(self, runtime: "Runtime") -> None:
    self._runtime = runtime
    self._raw_mode = False
    self._alternate_screen = False
    self._line_wrap = True
    self._mouse_capture = False
    self._bracketed_paste = False
    self._focus_change = False
    self._synchronized_updates = False
    self._title: str | None = None

raw_mode property writable

raw_mode: bool

Whether raw input mode is enabled.

alternate_screen property writable

alternate_screen: bool

Whether the alternate screen buffer is active.

line_wrap property writable

line_wrap: bool

Whether automatic line wrapping is enabled.

mouse_capture property writable

mouse_capture: bool

Whether mouse events are captured.

bracketed_paste property writable

bracketed_paste: bool

Whether bracketed paste mode is enabled.

focus_change property writable

focus_change: bool

Whether OS-level terminal focus change events are enabled.

synchronized_updates property writable

synchronized_updates: bool

Whether synchronized output updates are enabled.

title property writable

title: str | None

Window/page title last set on this device, if any.

size property

size: Size

Current terminal viewport size in cells.

clear

clear(kind: ClearType = 'all') -> None

Clear the terminal display.

Source code in xnano/device.py
def clear(self, kind: ClearType = "all") -> None:
    """Clear the terminal display."""
    if self._is_live():
        self._session.clear(_NATIVE_CLEAR_TYPES[kind])

scroll_up

scroll_up(lines: int = 1) -> None

Scroll the viewport up by lines.

Source code in xnano/device.py
def scroll_up(self, lines: int = 1) -> None:
    """Scroll the viewport up by ``lines``."""
    if self._is_live():
        self._session.scroll_up(lines)

scroll_down

scroll_down(lines: int = 1) -> None

Scroll the viewport down by lines.

Source code in xnano/device.py
def scroll_down(self, lines: int = 1) -> None:
    """Scroll the viewport down by ``lines``."""
    if self._is_live():
        self._session.scroll_down(lines)

copy_to_clipboard

copy_to_clipboard(text: str) -> bool

Copy text to the clipboard when supported.

Source code in xnano/device.py
def copy_to_clipboard(self, text: str) -> bool:
    """Copy ``text`` to the clipboard when supported."""
    return False

get_active_runtime

get_active_runtime() -> 'Runtime[Any] | None'

Return the runtime active in the current context.

Source code in xnano/core/runtime.py
def get_active_runtime() -> "Runtime[Any] | None":
    """Return the runtime active in the current context."""
    return _ACTIVE_RUNTIME.get()