-
Notifications
You must be signed in to change notification settings - Fork 1
register event handler
This lets you register custom events that run when specific patterns are detected in the raw stdin data.
from textual_drivers import DrivenApp
class MyApp(DrivenApp):
def on_mount(self) -> None:
self._driver.register_event_handler(
pattern, # see pattern types below
event_constructor, # you can pass in the direct type itself
priority= # whether to prevent Textual's parser from handling this further
)| Pattern | Match behaviour |
|---|---|
str |
Glob matched against each ESC-tokenised chunk via fnmatch.fnmatch
|
BoundedPattern(start, end) |
Finds all non-overlapping substrings in the raw data that begin with start and end with end
|
re.Pattern |
Finds all matches of pattern.finditer(data) in the raw data |
Detect the terminal's response to a Primary Device Attributes query (\x1b[c), which arrives as \x1b[?<params>c:
from textual.app import ComposeResult
from textual.message import Message
from textual.widgets import Label
from textual_drivers import DrivenApp
class DeviceAttributesReceived(Message):
def __init__(self, data: str) -> None:
super().__init__()
self.data = data
class MyApp(DrivenApp):
def compose(self) -> ComposeResult:
yield Label("Waiting for terminal response…")
def on_mount(self) -> None:
self.app._driver.register_event_handler("\x1b[?*c", DeviceAttributesReceived)
self.app._driver.write("\x1b[c")
self.app._driver.flush()
def on_device_attributes_received(self, event: DeviceAttributesReceived) -> None:
self.query_one(Label).update(f"Terminal identified: {event.data!r}")Detect the terminal's response to a Primary Device Attributes query, by matching the fixed start and end sentinels:
from textual_drivers import BoundedPattern
driver.register_event_handler(
BoundedPattern(start="\x1b[?1;2", end="c"),
DeviceAttributesReceived,
priority=True,
)BoundedPattern helps if you have sequences that have a fixed start and end content, and do not care about the middle.
Detect the terminal's response to a Primary Device Attributes query with a regex that captures the parameters:
import re
driver.register_event_handler(
re.compile(r"\x1b\[\?([0-9;]+)c"),
CursorPositionMsg,
priority=True,
)The event_constructor can also be a plain callable that receives the matched string and returns anything:
def _debug(data: str) -> None:
print(f"raw: {data!r}", flush=True)
driver.register_event_handler(BoundedPattern(start="\x1b]72;", end=_ST), _debug)If a Event is returned from the function/method, it is posted to the app as usual.
driver.raw_data_signal is a Signal[str] that fires once for every raw stdin read chunk, before any pattern matching or filtering. It is the lowest-level observation point available — the string is exactly what came off the file descriptor, decoded from UTF-8 but otherwise unprocessed.
Subscribe in on_mount using Textual's signal API:
def on_mount(self) -> None:
self.app._driver.raw_data_signal.subscribe(self, self._on_raw_stdin)
def _on_raw_stdin(self, data: str) -> None:
self.query_one("#log", Log).write_line(f"raw: {data!r}")