Skip to content

text_screens

text_screens

Native text editor / viewer modals.

The web-compatible replacement for the $EDITOR-subprocess and "print to a suspended terminal" instruction workflows (issue #473). Both are plain in-process modals — no child process, no terminal:

  • TextEditorScreen — an editable TextArea; dismisses with the edited text on Save, None on Cancel.
  • TextViewScreen — the same widget in read-only mode for display-only content.

TextEditorScreen(text, *, title)

Bases: ModalScreen[str | None]

Modal TextArea editor.

Dismisses with the (possibly edited) text on Save, or None on Cancel / Escape — the caller decides whether to persist.

Create the editor over text with title on the dialog border.

Source code in src/terok/tui/text_screens.py
def __init__(self, text: str, *, title: str) -> None:
    """Create the editor over *text* with *title* on the dialog border."""
    super().__init__()
    self._text = text
    self._title = title

BINDINGS = [Binding('escape', 'cancel', 'Cancel')] class-attribute instance-attribute

CSS = '\n TextEditorScreen {\n align: center middle;\n }\n\n #text-editor-dialog {\n width: 90%;\n height: 85%;\n border: heavy $primary;\n border-title-align: right;\n background: $surface;\n padding: 1 2;\n }\n\n #text-editor-area {\n height: 1fr;\n margin-bottom: 1;\n }\n\n #text-editor-buttons {\n height: 3;\n align-horizontal: right;\n }\n\n #text-editor-buttons Button {\n margin-left: 1;\n }\n ' class-attribute instance-attribute

compose()

Lay out the editable text area and the Cancel / Save buttons.

Source code in src/terok/tui/text_screens.py
def compose(self) -> ComposeResult:
    """Lay out the editable text area and the Cancel / Save buttons."""
    dialog = Vertical(id="text-editor-dialog")
    dialog.border_title = self._title
    with dialog:
        yield TextArea(self._text, id="text-editor-area")
        with Horizontal(id="text-editor-buttons"):
            yield Button("Cancel", id="text-editor-cancel", variant="default")
            yield Button("Save", id="text-editor-save", variant="primary")

on_mount()

Focus the text area so the operator can type immediately.

Source code in src/terok/tui/text_screens.py
def on_mount(self) -> None:
    """Focus the text area so the operator can type immediately."""
    self.query_one("#text-editor-area", TextArea).focus()

action_cancel()

Escape — dismiss without saving.

Source code in src/terok/tui/text_screens.py
def action_cancel(self) -> None:
    """Escape — dismiss without saving."""
    self.dismiss(None)

TextViewScreen(text, *, title)

Bases: ModalScreen[None]

Read-only modal text viewer — scrollable, selectable, no terminal.

Create the viewer over text with title on the dialog border.

Source code in src/terok/tui/text_screens.py
def __init__(self, text: str, *, title: str) -> None:
    """Create the viewer over *text* with *title* on the dialog border."""
    super().__init__()
    self._text = text
    self._title = title

BINDINGS = [Binding('escape', 'dismiss', 'Close')] class-attribute instance-attribute

CSS = '\n TextViewScreen {\n align: center middle;\n }\n\n #text-view-dialog {\n width: 90%;\n height: 85%;\n border: heavy $primary;\n border-title-align: right;\n background: $surface;\n padding: 1 2;\n }\n\n #text-view-area {\n height: 1fr;\n margin-bottom: 1;\n }\n\n #text-view-buttons {\n height: 3;\n align-horizontal: right;\n }\n ' class-attribute instance-attribute

compose()

Lay out the read-only text area and a Close button.

Source code in src/terok/tui/text_screens.py
def compose(self) -> ComposeResult:
    """Lay out the read-only text area and a Close button."""
    dialog = Vertical(id="text-view-dialog")
    dialog.border_title = self._title
    with dialog:
        yield TextArea(self._text, id="text-view-area", read_only=True)
        with Horizontal(id="text-view-buttons"):
            yield Button("Close", id="text-view-close", variant="default")