Terminal¶

Your login shell running inside a SimVX window.

📄 Docs only

Tags: devtools

Two nodes make a terminal. ShellNode runs a process without blocking the frame: ShellNode(command, use_pty=True) gives it a pseudo-terminal, so full screen programs such as nano, htop and ls --color behave as they do in any terminal, and it emits stdout_data as output arrives and process_exited(code) when the process ends. TerminalEmulator is the Control that draws the character grid, cols wide and rows high, and turns keys into the bytes a terminal sends.

term.attach(shell) wires the two together: the shell’s output is written to the grid and the terminal’s input goes to the shell. After shell.start(), shell.resize(cols, rows) tells the PTY how big the grid is, so programs lay themselves out to fit. This example runs $SHELL (falling back to /bin/bash) and closes the window when the shell exits.

The terminal has keyboard focus from the start; click it to take focus back. Type as usual, Ctrl combinations such as Ctrl+C reach the shell, and the scroll wheel moves through the scrollback.

Text draws in the font the engine ships with. The powerline arrows and icons that themes such as Powerlevel10k print are not in it: install a Nerd Font (for example Hack Nerd Font Mono) and the glyph fallback picks them up.

Source¶

 1# /// simvx
 2# [web]
 3# disabled = true
 4# reason = "Spawns a real OS shell via a PTY: no subprocess or pty devices exist in the browser sandbox."
 5# ///
 6"""Terminal: Your login shell running inside a SimVX window.
 7
 8Two nodes make a terminal. `ShellNode` runs a process without blocking the
 9frame: `ShellNode(command, use_pty=True)` gives it a pseudo-terminal, so full
10screen programs such as `nano`, `htop` and `ls --color` behave as they do in any
11terminal, and it emits `stdout_data` as output arrives and `process_exited(code)`
12when the process ends. `TerminalEmulator` is the `Control` that draws the
13character grid, `cols` wide and `rows` high, and turns keys into the bytes a
14terminal sends.
15
16`term.attach(shell)` wires the two together: the shell's output is written to
17the grid and the terminal's input goes to the shell. After `shell.start()`,
18`shell.resize(cols, rows)` tells the PTY how big the grid is, so programs lay
19themselves out to fit. This example runs `$SHELL` (falling back to `/bin/bash`)
20and closes the window when the shell exits.
21
22The terminal has keyboard focus from the start; click it to take focus back.
23Type as usual, Ctrl combinations such as Ctrl+C reach the shell, and the scroll
24wheel moves through the scrollback.
25
26Text draws in the font the engine ships with. The powerline arrows and icons
27that themes such as Powerlevel10k print are not in it: install a Nerd Font
28(for example Hack Nerd Font Mono) and the glyph fallback picks them up.
29"""
30
31import os
32
33from simvx.core import Anchor, Node, ShellNode
34from simvx.core.ui import Label, TerminalEmulator
35from simvx.graphics import App
36
37COLS, ROWS = 100, 30
38
39
40class TerminalDemo(Node):
41    def on_ready(self):
42        self.add_child(Label("Click the terminal to focus it, then type", anchor=Anchor.TOP_LEFT, inset=(10, 5)))
43        term = self.add_child(TerminalEmulator(cols=COLS, rows=ROWS, anchor=Anchor.TOP_LEFT, inset=(10, 30)))
44        shell = self.add_child(ShellNode(os.environ.get("SHELL", "/bin/bash"), use_pty=True))
45
46        term.attach(shell)
47        shell.start()
48        shell.resize(COLS, ROWS)
49        shell.process_exited.connect(lambda _code: self.app.quit())
50        term.grab_focus()
51
52
53if __name__ == "__main__":
54    App(title="SimVX Terminal", width=880, height=650).run(TerminalDemo())