Skip to main content

par_term_emu_core_rust/
lib.rs

1//! A comprehensive terminal emulator library in Rust with Python bindings
2//!
3//! This library provides full VT100/VT220/VT320/VT420/VT520 terminal emulation with iTerm2 feature parity:
4//!
5//! ## VT Compatibility Features
6//! - **VT100**: Basic ANSI escape sequences, cursor control, colors
7//! - **VT220**: Line/character editing (IL, DL, ICH, DCH, ECH)
8//! - **VT320**: Extended features and modes
9//! - **VT420**: Rectangle operations, character protection, left/right margins
10//! - **VT520**: Conformance level control, bell volume control
11//!
12//! ## Color Support
13//! - Basic 16 ANSI colors
14//! - 256-color palette
15//! - True color (24-bit RGB) support
16//!
17//! ## Advanced Features
18//! - Scrollback buffer with configurable size
19//! - Text attributes (bold, italic, underline, strikethrough, blink, reverse, dim, hidden)
20//! - Comprehensive cursor control and positioning
21//! - Scrolling regions (DECSTBM)
22//! - Tab stops with HTS, TBC, CHT, CBT
23//! - Terminal resizing
24//! - Alternate screen buffer (with multiple variants)
25//! - Mouse reporting (X10, Normal, Button, Any modes)
26//! - Mouse encodings (Default, UTF-8, SGR, URXVT)
27//! - Bracketed paste mode
28//! - Focus tracking
29//! - Application cursor keys mode
30//! - Origin mode (DECOM)
31//! - Auto wrap mode (DECAWM)
32//! - Shell integration (OSC 133)
33//! - OSC 8 hyperlinks (recognized)
34//! - Full Unicode support including emoji and wide characters
35//! - Bell event tracking for visual bell implementations
36
37pub mod ansi_utils;
38pub mod badge;
39pub mod cell;
40pub mod color;
41pub mod color_utils;
42pub mod conformance_level;
43pub mod coprocess;
44pub mod cursor;
45#[macro_use]
46pub mod debug;
47pub mod ffi;
48pub mod grapheme;
49pub mod graphics;
50pub mod grid;
51pub mod html_export;
52pub mod macros;
53pub mod mouse;
54pub mod observer;
55pub mod pty_error;
56pub mod pty_session;
57#[cfg(feature = "python")]
58pub mod python_bindings;
59pub mod screenshot;
60pub mod shell_integration;
61pub mod sixel;
62pub mod streaming;
63pub mod terminal;
64pub mod text_utils;
65pub mod tmux_control;
66pub mod unicode_normalization_config;
67pub mod unicode_width_config;
68pub mod zone;
69
70// Re-export commonly used types from unicode_normalization_config
71pub use unicode_normalization_config::NormalizationForm;
72
73// Re-export commonly used types from unicode_width_config
74pub use unicode_width_config::{
75    char_width, char_width_cjk, is_east_asian_ambiguous, str_width, str_width_cjk, AmbiguousWidth,
76    UnicodeVersion, WidthConfig,
77};
78
79// Re-export recording types for session logging/recording
80pub use terminal::{
81    RecordingEvent, RecordingEventType, RecordingExportFormat, RecordingFormat, RecordingSession,
82};
83
84// Re-export badge types for badge format support
85pub use badge::{
86    decode_badge_format, evaluate_badge_format, BadgeFormatChanged, BadgeFormatError,
87    SessionVariables,
88};
89
90#[cfg(feature = "python")]
91use pyo3::exceptions::{PyIOError, PyRuntimeError};
92#[cfg(feature = "python")]
93use pyo3::prelude::*;
94
95// Re-export Python bindings for convenience
96#[cfg(feature = "python")]
97pub use python_bindings::{
98    decode_client_message, decode_server_message, encode_client_message, encode_server_message,
99    py_adjust_contrast_rgb, py_adjust_hue, py_adjust_saturation, py_char_width, py_char_width_cjk,
100    py_color_luminance, py_complementary_color, py_contrast_ratio, py_darken_rgb, py_hex_to_rgb,
101    py_hsl_to_rgb, py_is_dark_color, py_is_east_asian_ambiguous, py_lighten_rgb, py_meets_wcag_aa,
102    py_meets_wcag_aaa, py_mix_colors, py_perceived_brightness_rgb, py_rgb_to_ansi_256,
103    py_rgb_to_hex, py_rgb_to_hsl, py_str_width, py_str_width_cjk, PyAmbiguousWidth, PyAttributes,
104    PyBenchmarkResult, PyBenchmarkSuite, PyBookmark, PyClipboardEntry, PyClipboardHistoryEntry,
105    PyClipboardSyncEvent, PyColorHSL, PyColorHSV, PyColorPalette, PyCommandExecution,
106    PyComplianceReport, PyComplianceTest, PyCoprocessConfig, PyCursorStyle, PyCwdChange,
107    PyDamageRegion, PyDetectedItem, PyEscapeSequenceProfile, PyFrameTiming, PyGraphic,
108    PyImageDimension, PyImageFormat, PyImagePlacement, PyImageProtocol, PyInlineImage,
109    PyJoinedLines, PyLineDiff, PyMacro, PyMacroEvent, PyMouseEncoding, PyMouseEvent,
110    PyMousePosition, PyNormalizationForm, PyNotificationConfig, PyNotificationEvent, PyPaneState,
111    PyPerformanceMetrics, PyProfilingData, PyProgressBar, PyProgressState, PyPtyTerminal,
112    PyRecordingEvent, PyRecordingSession, PyRegexMatch, PyRenderingHint, PyScreenSnapshot,
113    PyScrollbackStats, PySearchMatch, PySelection, PySelectionMode, PySessionState,
114    PyShellIntegration, PyShellIntegrationStats, PySnapshotDiff, PyStreamingConfig,
115    PyStreamingServer, PyTerminal, PyTmuxNotification, PyTrigger, PyTriggerAction, PyTriggerMatch,
116    PyUnderlineStyle, PyUnicodeVersion, PyWidthConfig, PyWindowLayout,
117};
118
119/// Convert PtyError to PyErr
120#[cfg(feature = "python")]
121impl From<pty_error::PtyError> for PyErr {
122    fn from(err: pty_error::PtyError) -> PyErr {
123        match err {
124            pty_error::PtyError::ProcessSpawnError(msg) => {
125                PyRuntimeError::new_err(format!("Failed to spawn process: {}", msg))
126            }
127            pty_error::PtyError::ProcessExitedError(code) => {
128                PyRuntimeError::new_err(format!("Process has exited with code: {}", code))
129            }
130            pty_error::PtyError::IoError(err) => PyIOError::new_err(err.to_string()),
131            pty_error::PtyError::ResizeError(msg) => {
132                PyRuntimeError::new_err(format!("Failed to resize PTY: {}", msg))
133            }
134            pty_error::PtyError::NotStartedError => {
135                PyRuntimeError::new_err("PTY session has not been started")
136            }
137            pty_error::PtyError::LockError(msg) => {
138                PyRuntimeError::new_err(format!("Mutex lock error: {}", msg))
139            }
140        }
141    }
142}
143
144/// A comprehensive terminal emulator library
145#[cfg(feature = "python")]
146#[pymodule(gil_used = true)]
147fn _native(m: &Bound<'_, PyModule>) -> PyResult<()> {
148    // Sixel rendering mode constants
149    m.add("SIXEL_DISABLED", "disabled")?;
150    m.add("SIXEL_PIXELS", "pixels")?;
151    m.add("SIXEL_HALFBLOCKS", "halfblocks")?;
152
153    // Classes
154    m.add_class::<PyTerminal>()?;
155    m.add_class::<PyPtyTerminal>()?;
156    m.add_class::<PyAttributes>()?;
157    m.add_class::<PyScreenSnapshot>()?;
158    m.add_class::<PyShellIntegration>()?;
159    m.add_class::<PyGraphic>()?;
160    m.add_class::<PyImagePlacement>()?;
161    m.add_class::<PyImageDimension>()?;
162    m.add_class::<PyTmuxNotification>()?;
163    m.add_class::<PyCursorStyle>()?;
164    m.add_class::<PyUnderlineStyle>()?;
165    m.add_class::<PyMouseEncoding>()?;
166    m.add_class::<PySearchMatch>()?;
167    m.add_class::<PyDetectedItem>()?;
168    m.add_class::<PySelection>()?;
169    m.add_class::<PySelectionMode>()?;
170    m.add_class::<PyScrollbackStats>()?;
171    m.add_class::<PyBookmark>()?;
172    m.add_class::<PyPerformanceMetrics>()?;
173    m.add_class::<PyFrameTiming>()?;
174    m.add_class::<PyColorHSV>()?;
175    m.add_class::<PyColorHSL>()?;
176    m.add_class::<PyColorPalette>()?;
177    m.add_class::<PyJoinedLines>()?;
178    m.add_class::<PyClipboardEntry>()?;
179    m.add_class::<PyMouseEvent>()?;
180    m.add_class::<PyMousePosition>()?;
181    m.add_class::<PyDamageRegion>()?;
182    m.add_class::<PyRenderingHint>()?;
183    m.add_class::<PyEscapeSequenceProfile>()?;
184    m.add_class::<PyProfilingData>()?;
185    m.add_class::<PyLineDiff>()?;
186    m.add_class::<PySnapshotDiff>()?;
187    m.add_class::<PyRegexMatch>()?;
188    m.add_class::<PyPaneState>()?;
189    m.add_class::<PyWindowLayout>()?;
190    m.add_class::<PySessionState>()?;
191    m.add_class::<PyImageProtocol>()?;
192    m.add_class::<PyImageFormat>()?;
193    m.add_class::<PyInlineImage>()?;
194    m.add_class::<PyBenchmarkResult>()?;
195    m.add_class::<PyBenchmarkSuite>()?;
196    m.add_class::<PyComplianceTest>()?;
197    m.add_class::<PyComplianceReport>()?;
198    m.add_class::<PyClipboardSyncEvent>()?;
199    m.add_class::<PyClipboardHistoryEntry>()?;
200    m.add_class::<PyCommandExecution>()?;
201    m.add_class::<PyShellIntegrationStats>()?;
202    m.add_class::<PyCwdChange>()?;
203    m.add_class::<PyNotificationEvent>()?;
204    m.add_class::<PyNotificationConfig>()?;
205    m.add_class::<PyRecordingEvent>()?;
206    m.add_class::<PyRecordingSession>()?;
207    m.add_class::<PyMacro>()?;
208    m.add_class::<PyMacroEvent>()?;
209    m.add_class::<PyStreamingServer>()?;
210    m.add_class::<PyStreamingConfig>()?;
211    m.add_class::<PyProgressState>()?;
212    m.add_class::<PyProgressBar>()?;
213    m.add_class::<PyUnicodeVersion>()?;
214    m.add_class::<PyAmbiguousWidth>()?;
215    m.add_class::<PyWidthConfig>()?;
216    m.add_class::<PyNormalizationForm>()?;
217    m.add_class::<PyTrigger>()?;
218    m.add_class::<PyTriggerMatch>()?;
219    m.add_class::<PyTriggerAction>()?;
220    m.add_class::<PyCoprocessConfig>()?;
221
222    // Color utility functions
223    m.add_function(wrap_pyfunction!(py_perceived_brightness_rgb, m)?)?;
224    m.add_function(wrap_pyfunction!(py_adjust_contrast_rgb, m)?)?;
225    m.add_function(wrap_pyfunction!(py_lighten_rgb, m)?)?;
226    m.add_function(wrap_pyfunction!(py_darken_rgb, m)?)?;
227    m.add_function(wrap_pyfunction!(py_color_luminance, m)?)?;
228    m.add_function(wrap_pyfunction!(py_is_dark_color, m)?)?;
229    m.add_function(wrap_pyfunction!(py_contrast_ratio, m)?)?;
230    m.add_function(wrap_pyfunction!(py_meets_wcag_aa, m)?)?;
231    m.add_function(wrap_pyfunction!(py_meets_wcag_aaa, m)?)?;
232    m.add_function(wrap_pyfunction!(py_mix_colors, m)?)?;
233    m.add_function(wrap_pyfunction!(py_rgb_to_hsl, m)?)?;
234    m.add_function(wrap_pyfunction!(py_hsl_to_rgb, m)?)?;
235    m.add_function(wrap_pyfunction!(py_adjust_saturation, m)?)?;
236    m.add_function(wrap_pyfunction!(py_adjust_hue, m)?)?;
237    m.add_function(wrap_pyfunction!(py_complementary_color, m)?)?;
238    m.add_function(wrap_pyfunction!(py_rgb_to_hex, m)?)?;
239    m.add_function(wrap_pyfunction!(py_hex_to_rgb, m)?)?;
240    m.add_function(wrap_pyfunction!(py_rgb_to_ansi_256, m)?)?;
241
242    // Unicode width functions
243    m.add_function(wrap_pyfunction!(py_char_width, m)?)?;
244    m.add_function(wrap_pyfunction!(py_char_width_cjk, m)?)?;
245    m.add_function(wrap_pyfunction!(py_str_width, m)?)?;
246    m.add_function(wrap_pyfunction!(py_str_width_cjk, m)?)?;
247    m.add_function(wrap_pyfunction!(py_is_east_asian_ambiguous, m)?)?;
248
249    // Binary protocol functions for streaming
250    m.add_function(wrap_pyfunction!(encode_server_message, m)?)?;
251    m.add_function(wrap_pyfunction!(decode_server_message, m)?)?;
252    m.add_function(wrap_pyfunction!(encode_client_message, m)?)?;
253    m.add_function(wrap_pyfunction!(decode_client_message, m)?)?;
254
255    Ok(())
256}