Runtime Context¶
The second parameter on a hook is a Context: the event that fired, application state, runtime/host controls, and related helpers.
You do not construct Context yourself. The host builds one per hook call.
Reading the event¶
Optional
Defining a ctx parameter on a hook is optional, all of these are
accepted forms of defining a hook:
from xnano import Context, on_keyboard
@on_keyboard("enter")
def submit(self, ctx: Context) -> None:
key = ctx.keyboard_event # KeyboardEventData, or None
runtime = ctx.runtime # active Runtime
ctx.keyboard_event and ctx.mouse_event are set only when that kind of event
triggered the hook. A @on_tick handler sees None for both.
ctx.surface reports the presentation surface ("terminal", "web", or
offscreen).
Typing Context by state¶
Context is generic over the object passed to Terminal(state=...) or
Web(state=...). How application state relates to Field(state=True) and
painted fields is covered under State.
import dataclasses
from xnano import BaseGrid, Context, Field, Terminal, on_keyboard
@dataclasses.dataclass
class AppState:
count: int = 0
class Counter(BaseGrid, direction="vertical"):
label: str = Field(default="Count: 0", height=1)
@on_keyboard("up")
def inc(self, ctx: Context[AppState]) -> None: # (1)!
ctx.state.count += 1 # (2)!
self.label = f"Count: {ctx.state.count}"
Terminal(state=AppState()).run(Counter())
Context[AppState]is for type checkers; runtime behavior is unchanged.ctx.stateis the same object handed to the host.ctx.get_state()raises if no state was attached.
A plain dataclass or Pydantic model works. State is
an optional convenience bag (not exported from the package root):
Other attributes¶
| Attribute / method | Role |
|---|---|
ctx.event |
Full event object |
ctx.keyboard_event / ctx.mouse_event / ctx.tick_event |
Typed payloads (or None) |
ctx.request |
HTTP Request when a request hook fired |
ctx.surface |
"terminal", "web", or "offscreen" |
ctx.device / ctx.cursor |
Host chrome (Device) |
ctx.actions |
Synthetic actions (perform, keyboard, click, request) |
ctx.stage |
Layout map for advanced paint |
ctx.focus(group) / ctx.blur() |
Field focus by Field(group=...) |
ctx.focused_group |
Current focus group name |
ctx.scroll(group) |
Scroll handle for a named group |
ctx.call_soon(...) |
Schedule work on the runtime |
ctx.has_*_event() |
Predicates for keyboard, mouse, focus, resize, clipboard |
ctx.terminal / ctx.host are aliases for the same runtime object as
ctx.runtime. Prefer ctx.runtime in new code.
Deprecated aliases still work: ctx.keyboard, ctx.mouse, ctx.tick.