| Crates.io | par-term-emu-core-rust |
| lib.rs | par-term-emu-core-rust |
| version | 0.21.0 |
| created_at | 2025-11-23 06:58:38.053673+00 |
| updated_at | 2026-01-20 23:32:35.434966+00 |
| description | Comprehensive terminal emulator library in Rust with Python bindings - VT100/VT220/VT320/VT420/VT520 support, PTY, Sixel/iTerm2/Kitty graphics |
| homepage | https://github.com/paulrobello/par-term-emu-core-rust |
| repository | https://github.com/paulrobello/par-term-emu-core-rust |
| max_upload_size | |
| id | 1946201 |
| size | 4,653,530 |
A comprehensive terminal emulator library written in Rust with Python bindings for Python 3.12+. Provides VT100/VT220/VT320/VT420/VT520 compatibility with PTY support, matching iTerm2's feature set.
The entire library has been migrated from std::sync::Mutex to parking_lot::Mutex.
.unwrap(), making the code cleaner and more robust.Added new methods to pass environment variables and working directory directly to spawned processes without modifying the global environment of the parent process.
spawn_shell_with_env(env, cwd), spawn_with_env(command, args, env, cwd)spawn_shell(env=None, cwd=None) - now supports optional environment dictionary and working directory path.unsafe { std::env::set_var() } in multi-threaded applications like those using Tokio.The web frontend UI chrome can now be customized after static build without rebuilding:
/* Edit web_term/theme.css */
:root {
--terminal-bg: #0a0a0a; /* Main background */
--terminal-surface: #1a1a1a; /* Status bar, cards */
--terminal-border: #2a2a2a; /* Borders */
--terminal-accent: #3a3a3a; /* Scrollbar, accents */
--terminal-text: #e0e0e0; /* Primary text */
}
--theme optionStreamingConfig.enable_http / web_root - HTTP server configuration (getter/setter)StreamingServer.max_clients() - Query maximum allowed clientsStreamingServer.create_theme_info() - Create theme dictionaries for protocolencode_server_message("pong") - Pong message encoding supportencode_server_message("connected", theme=...) - Theme support in connected messagesfrom par_term_emu_core_rust import StreamingConfig, StreamingServer, encode_server_message
# Configure HTTP serving
config = StreamingConfig(enable_http=True, web_root="/var/www/terminal")
# Create theme for connected message
theme = StreamingServer.create_theme_info(
name="my-theme",
background=(0, 0, 0),
foreground=(255, 255, 255),
normal=[(0,0,0), (255,0,0), (0,255,0), (255,255,0), (0,0,255), (255,0,255), (0,255,255), (200,200,200)],
bright=[(128,128,128), (255,128,128), (128,255,128), (255,255,128), (128,128,255), (255,128,255), (128,255,255), (255,255,255)]
)
# Encode messages
pong = encode_server_message("pong")
connected = encode_server_message("connected", cols=80, rows=24, session_id="abc", theme=theme)
Pong messagesAutomatic Shell Restart: Streaming server now automatically restarts the shell when it exits
--no-restart-shell CLI option to disable automatic restartPAR_TERM_NO_RESTART_SHELL environment variable supportHeader/Footer Toggle in On-Screen Keyboard: Layout toggle button in keyboard header
Font Size Controls in On-Screen Keyboard: Plus/minus buttons in keyboard header
set_pty_writer now uses interior mutability for shell restart supportFont Size Control: User-adjustable terminal font size in web frontend
Heartbeat/Ping Mechanism: Stale WebSocket connection detection
noopener,noreferrertabIndex={-1} to all buttons to prevent focus acquisition that triggered device keyboardEnvironment Variable Support: All CLI options now support environment variables with PAR_TERM_ prefix
PAR_TERM_HOST, PAR_TERM_PORT, PAR_TERM_THEME, PAR_TERM_HTTP_USERHTTP Basic Authentication: New password protection for the web frontend
--http-user - Username for HTTP Basic Auth--http-password - Clear text password--http-password-hash - htpasswd format hash (bcrypt, apr1, SHA1, MD5 crypt)--http-password-file - Read password from file (auto-detects hash vs clear text)encode_server_message, decode_server_message, encode_client_message, decode_client_message)# Environment variables
export PAR_TERM_HOST=0.0.0.0
export PAR_TERM_HTTP_USER=admin
export PAR_TERM_HTTP_PASSWORD=secret
par-term-streamer --enable-http
# CLI with htpasswd hash
par-term-streamer --enable-http --http-user admin --http-password-hash '$apr1$...'
Web Terminal Macro System: New macro tab in the on-screen keyboard for creating and playing terminal command macros
[[delay:N]], [[enter]], [[tab]], [[esc]], [[space]], [[ctrl+X]], [[shift+X]], [[ctrl+shift+X]], [[shift+tab]], [[shift+enter]]On-Screen Keyboard Enhancements:
^[[?1;2c^[[>0;276;0c) appearing when running tmux or other TUI applications in the web terminal. The issue was caused by xterm.js generating Device Attributes responses when the backend terminal emulator already handles these queries.jemalloc feature for 5-15% server throughput improvement (non-Windows only)TERM from xterm-kitty to xterm-256color for better compatibility with systems lacking kitty terminfo--tls-cert, --tls-key, --tls-pem# Using separate cert and key files
par-term-streamer --enable-http --tls-cert cert.pem --tls-key key.pem
# Using combined PEM file
par-term-streamer --enable-http --tls-pem combined.pem
StreamingConfig methods for TLS setupencode_server_message(), decode_server_message(), encode_client_message(), decode_client_message()See CHANGELOG.md for complete version history.
--download-frontend option to download prebuilt web frontend from GitHub releases--frontend-version option to specify version to download (default: "latest")--use-tty-size option to use current terminal size from TTY# Build the streaming server
make streamer-build-release
# Download prebuilt web frontend (no Node.js required!)
./target/release/par-term-streamer --download-frontend
# Run server with frontend
./target/release/par-term-streamer --enable-http
# Open browser to http://127.0.0.1:8099
Web Terminal Onscreen Keyboard: Mobile-friendly virtual keyboard for touch devices
OSC 9;4 Progress Bar Support (ConEmu/Windows Terminal style):
Streaming Server Enhancements:
--size CLI option for specifying terminal size in COLSxROWS format (e.g., --size 120x40 or -s 120x40)--command / -c CLI option to execute a command after shell startup (with 1 second delay for prompt settling)initial_cols and initial_rows configuration options in StreamingConfig for both Rust and Python APIsPython Bindings Enhancements:
MouseEncoding enum for mouse event encoding control (Default, Utf8, Sgr, Urxvt)use_alt_screen(), use_primary_screen()mouse_encoding(), set_mouse_encoding()set_focus_tracking(), set_bracketed_paste(), set_title()bold_brightening(), set_bold_brightening()Emoji Sequence Preservation: Complete support for complex emoji sequences and grapheme clusters
grapheme module for Unicode cluster detectionWeb Terminal Frontend: Modern Next.js-based web interface
Terminal Sequence Support:
Cell struct no longer implements Copy (now Clone only)
.clone() callsGraphics Protocol Support: Comprehensive multi-protocol graphics implementation
GraphicsStore with scrollback support and memory limitsPre-built Streaming Server Binaries: Download ready-to-run binaries from GitHub Releases
cargo install par-term-emu-core-rust --features streamingSee CHANGELOG.md for complete version history.
ctrl+shift+s, enter, f1, etc.)uv add par-term-emu-core-rust
# or
pip install par-term-emu-core-rust
Requires Rust 1.75+ and Python 3.12+:
# Install maturin (build tool)
uv tool install maturin
# Build and install
maturin develop --release
maturin build --release
uv add --find-links target/wheels par-term-emu-core-rust
# or
pip install target/wheels/par_term_emu_core_rust-*.whl
The library can be used in pure Rust projects without Python. Choose your feature combination:
| Use Case | Cargo.toml | What's Included |
|---|---|---|
| Rust Only | par-term-emu-core-rust = { version = "0.10", default-features = false } |
Terminal, PTY, Macros |
| Rust + Streaming | par-term-emu-core-rust = { version = "0.10", default-features = false, features = ["streaming"] } |
+ WebSocket/HTTP server |
| Python Only | par-term-emu-core-rust = "0.10" |
+ Python bindings |
| Everything | par-term-emu-core-rust = { version = "0.10", features = ["full"] } |
All features |
Download pre-built streaming server (recommended):
Pre-built binaries and web frontend packages are available from GitHub Releases:
# Download binary (Linux example)
wget https://github.com/paulrobello/par-term-emu-core-rust/releases/latest/download/par-term-streamer-linux-x86_64
chmod +x par-term-streamer-linux-x86_64
# Download web frontend
wget https://github.com/paulrobello/par-term-emu-core-rust/releases/latest/download/par-term-web-frontend-v0.10.0.tar.gz
tar -xzf par-term-web-frontend-v0.10.0.tar.gz -C ./web_term
# Run
./par-term-streamer-linux-x86_64 --web-root ./web_term
Available binaries: Linux (x86_64, ARM64), macOS (Intel, Apple Silicon), Windows (x86_64)
Or install from crates.io:
cargo install par-term-emu-core-rust --features streaming
Or build from source:
cargo build --bin par-term-streamer --no-default-features --features streaming --release
./target/release/par-term-streamer --help
See docs/RUST_USAGE.md for detailed Rust API documentation and examples.
For optimal terminal compatibility, install the par-term terminfo definition:
# Install for current user
./terminfo/install.sh
# Or install system-wide
sudo ./terminfo/install.sh --system
# Then use
export TERM=par-term
export COLORTERM=truecolor
See terminfo/README.md for details.
Enhances terminal with semantic prompt markers, command status tracking, and smart selection:
cd shell_integration
./install.sh # Auto-detects bash/zsh/fish
See shell_integration/README.md for details.
from par_term_emu_core_rust import Terminal
# Create terminal
term = Terminal(80, 24)
# Process ANSI sequences
term.process_str("Hello, \x1b[31mWorld\x1b[0m!\n")
term.process_str("\x1b[1;32mBold green text\x1b[0m\n")
# Get content and cursor position
print(term.content())
col, row = term.cursor_position()
print(f"Cursor at: ({col}, {row})")
from par_term_emu_core_rust import PtyTerminal
import time
# Create PTY terminal and spawn shell
with PtyTerminal(80, 24) as term:
term.spawn_shell()
# Send commands
term.write_str("echo 'Hello from shell!'\n")
time.sleep(0.2)
# Get output
print(term.content())
# Resize terminal
term.resize(100, 30)
# Exit shell
term.write_str("exit\n")
# Automatic cleanup
Pass environment variables and working directory directly to spawn_shell() without modifying
the parent process environment. This is safe for multi-threaded applications (e.g., Tokio):
from par_term_emu_core_rust import PtyTerminal
# Spawn with custom environment variables
with PtyTerminal(80, 24) as term:
term.spawn_shell(env={"MY_VAR": "hello", "DEBUG": "1"})
term.write_str("echo $MY_VAR\n") # Outputs: hello
# Spawn with custom working directory
with PtyTerminal(80, 24) as term:
term.spawn_shell(cwd="/tmp")
term.write_str("pwd\n") # Outputs: /tmp
# Combine both
with PtyTerminal(80, 24) as term:
term.spawn_shell(env={"PROJECT": "myapp"}, cwd="/home/user/projects")
The spawn() method also accepts env and cwd parameters:
term.spawn("/bin/bash", ["-c", "echo $MY_VAR"], env={"MY_VAR": "test"}, cwd="/tmp")
term = Terminal(80, 24)
term.process_str("\x1b[1;31mHello, World!\x1b[0m\n")
# Save screenshot
term.screenshot_to_file("output.png")
term.screenshot_to_file("output.svg", format="svg") # Vector graphics!
term.screenshot_to_file("output.html", format="html") # Styled HTML
# Custom configuration
term.screenshot_to_file(
"output.png",
font_size=16.0,
padding=20,
include_scrollback=True,
minimum_contrast=0.5 # iTerm2-compatible contrast adjustment
)
from par_term_emu_core_rust import (
perceived_brightness_rgb, adjust_contrast_rgb,
contrast_ratio, meets_wcag_aa,
rgb_to_hex, hex_to_rgb, mix_colors
)
# iTerm2-compatible contrast adjustment
adjusted = adjust_contrast_rgb((64, 64, 64), (0, 0, 0), 0.5)
# WCAG accessibility checks
ratio = contrast_ratio((0, 0, 0), (255, 255, 255))
print(f"Contrast ratio: {ratio:.1f}:1")
print(f"Meets WCAG AA: {meets_wcag_aa((0, 0, 0), (255, 255, 255))}")
# Color conversions
hex_color = rgb_to_hex((255, 128, 64)) # "#FF8040"
rgb = hex_to_rgb("#FF8040") # (255, 128, 64)
mixed = mix_colors((255, 0, 0), (0, 0, 255), 0.5) # Purple
from par_term_emu_core_rust import Macro, PtyTerminal
import time
# Create a macro manually
macro = Macro("git_status")
macro.set_description("Check git status and show branch")
macro.add_key("g")
macro.add_key("i")
macro.add_key("t")
macro.add_key("space")
macro.add_key("s")
macro.add_key("t")
macro.add_key("a")
macro.add_key("t")
macro.add_key("u")
macro.add_key("s")
macro.add_key("enter")
macro.add_delay(500) # Wait 500ms
macro.add_screenshot("git_status.png") # Trigger screenshot
# Save to YAML
macro.save_yaml("git_status.yaml")
# Load and play back
term = PtyTerminal(80, 24)
term.spawn_shell()
# Load macro from file
loaded_macro = Macro.load_yaml("git_status.yaml")
term.load_macro("git_check", loaded_macro)
# Play the macro
term.play_macro("git_check", speed=1.0) # Normal speed
# Tick to execute macro events
while term.is_macro_playing():
if term.tick_macro(): # Returns True if event was processed
time.sleep(0.01) # Small delay for visual effect
# Check for screenshot triggers
triggers = term.get_macro_screenshot_triggers()
for label in triggers:
term.screenshot_to_file(label)
# Convert a recording to a macro
term.start_recording("test session")
term.write_str("ls -la\n")
time.sleep(0.5)
session = term.stop_recording()
# Convert and save
macro = term.recording_to_macro(session, "ls_command")
macro.save_yaml("ls_command.yaml")
See the examples/ directory for comprehensive examples:
basic_usage_improved.py - Enhanced basic usagecolors_demo.py - Color supportcursor_movement.py - Cursor controltext_attributes.py - Text stylingunicode_emoji.py - Unicode/emoji supportscrollback_demo.py - Scrollback buffer usagealt_screen.py - Alternate screen buffermouse_tracking.py - Mouse eventsbracketed_paste.py - Bracketed pastesynchronized_updates.py - Flicker-free renderingshell_integration.py - OSC 133 integrationtest_osc52_clipboard.py - SSH clipboardtest_kitty_keyboard.py - Kitty keyboard protocolhyperlink_demo.py - Clickable URLsnotifications.py - Desktop notificationsrectangle_operations.py - VT420 rectangle opsdisplay_image_sixel.py - Sixel graphicstest_sixel_simple.py - Simple sixel examplestest_sixel_display.py - Advanced sixel displayscreenshot_demo.py - Screenshot featuresfeature_showcase.py - Comprehensive TUI showcasepty_basic.py - Basic PTY usagepty_shell.py - Interactive shellspty_resize.py - Dynamic resizingpty_event_loop.py - Event loop integrationpty_mouse_events.py - Mouse in PTYpty_custom_env.py - Custom environment variablespty_multiple.py - Multiple PTY sessionspty_with_par_term.py - Integration with par-termstreaming_demo.py - Python WebSocket streaming serverstreaming_client.html - Browser-based terminal clientdemo.yaml - Example macro definitionStandalone Rust Server:
# Build and run (default: ws://127.0.0.1:8080)
make streamer-run
# Run with authentication
make streamer-run-auth
# Or use cargo directly
cargo build --bin par-term-streamer --no-default-features --features streaming --release
./target/release/par-term-streamer --port 8080 --theme dracula
# With authentication
./target/release/par-term-streamer --api-key my-secret --theme monokai
# Install globally
make streamer-install
par-term-streamer --help
Available Themes: iterm2-dark, monokai, dracula, solarized-dark
Using Pre-built Package (Recommended):
Download the pre-built static web frontend from GitHub Releases:
# Download and extract
wget https://github.com/paulrobello/par-term-emu-core-rust/releases/latest/download/par-term-web-frontend-v0.10.0.tar.gz
tar -xzf par-term-web-frontend-v0.10.0.tar.gz -C ./web_term
# Run streamer with web frontend
par-term-streamer --web-root ./web_term
# Open browser to http://localhost:8080
See web_term/README.md for detailed usage instructions.
Building from Source:
A modern Next.js-based web terminal frontend source is in web-terminal-frontend/:
cd web-terminal-frontend
# Install dependencies
npm install
# Development server (runs on port 8030)
npm run dev
# Build for production (outputs to out/)
npm run build
# Copy to web_term for serving
cp -r out/* ../web_term/
Features:
theme.css after build (no rebuild required)See web-terminal-frontend/README.md for detailed setup and configuration.
A full-featured TUI (Text User Interface) application is available in the sister project par-term-emu-tui-rust.

Installation: uv add par-term-emu-tui-rust or pip install par-term-emu-tui-rust
GitHub: https://github.com/paulrobello/par-term-emu-tui-rust
# Run Rust tests
cargo test
# Run Python tests
uv sync # Install dependencies including pytest
pytest tests/
See docs/ARCHITECTURE.md for implementation details.
When using PTY functionality, follow security best practices to prevent command injection and other vulnerabilities.
See docs/SECURITY.md for comprehensive security guidelines.
Contributions are welcome! Please submit issues or pull requests on GitHub.
git clone https://github.com/paulrobello/par-term-emu-core-rust.git
cd par-term-emu-core-rust
make setup-venv # Create virtual environment
make pre-commit-install # Install pre-commit hooks (recommended)
make dev # Build library
make checkall # Run all quality checks
All contributions must pass:
cargo fmt)cargo clippy)make fmt-python)make lint-python)pyright)make test-python)TIP: Use make pre-commit-install to automate all checks on every commit!
See CLAUDE.md for detailed development instructions.
This project is licensed under the MIT License - see the LICENSE file for details.
Paul Robello - probello@gmail.com