#[non_exhaustive]pub struct PseudoTerminal<'a, S> { /* private fields */ }Expand description
A widget representing a pseudo-terminal screen.
The PseudoTerminal widget displays the contents of a pseudo-terminal screen,
which is typically populated with text and control sequences from a terminal emulator.
It provides a visual representation of the terminal output within a TUI application.
The contents of the pseudo-terminal screen are represented by a vt100::Screen object.
The vt100 library provides functionality for parsing and processing terminal control sequences
and handling terminal state, allowing the PseudoTerminal widget to accurately render the
terminal output.
§Examples
use ratatui::{
style::{Color, Modifier, Style},
widgets::{Block, Borders},
};
use tui_term::widget::PseudoTerminal;
use vt100::Parser;
let mut parser = vt100::Parser::new(24, 80, 0);
let pseudo_term = PseudoTerminal::new(parser.screen())
.block(Block::default().title("Terminal").borders(Borders::ALL))
.style(
Style::default()
.fg(Color::White)
.bg(Color::Black)
.add_modifier(Modifier::BOLD),
);Implementations§
Source§impl<'a, S: Screen> PseudoTerminal<'a, S>
impl<'a, S: Screen> PseudoTerminal<'a, S>
Sourcepub fn new(screen: &'a S) -> Self
pub fn new(screen: &'a S) -> Self
Creates a new instance of PseudoTerminal.
§Arguments
screen: The reference to theScreen.
§Example
use tui_term::widget::PseudoTerminal;
use vt100::Parser;
let mut parser = vt100::Parser::new(24, 80, 0);
let pseudo_term = PseudoTerminal::new(parser.screen());Examples found in repository?
189fn ui(f: &mut Frame, screen: &Screen) {
190 let chunks = ratatui::layout::Layout::default()
191 .direction(ratatui::layout::Direction::Vertical)
192 .margin(1)
193 .constraints(
194 [
195 ratatui::layout::Constraint::Percentage(100),
196 ratatui::layout::Constraint::Min(1),
197 ]
198 .as_ref(),
199 )
200 .split(f.area());
201 let block = Block::default()
202 .borders(Borders::ALL)
203 .style(Style::default().add_modifier(Modifier::BOLD));
204 let pseudo_term = PseudoTerminal::new(screen).block(block);
205 f.render_widget(pseudo_term, chunks[0]);
206 let explanation = "Press q to exit".to_string();
207 let explanation = Paragraph::new(explanation)
208 .style(Style::default().add_modifier(Modifier::BOLD | Modifier::REVERSED))
209 .alignment(Alignment::Center);
210 f.render_widget(explanation, chunks[1]);
211}More examples
192fn ui(f: &mut Frame, screen: &Screen) {
193 let chunks = ratatui::layout::Layout::default()
194 .direction(ratatui::layout::Direction::Vertical)
195 .margin(1)
196 .constraints(
197 [
198 ratatui::layout::Constraint::Percentage(100),
199 ratatui::layout::Constraint::Min(1),
200 ]
201 .as_ref(),
202 )
203 .split(f.area());
204 let block = Block::default()
205 .borders(Borders::ALL)
206 .style(Style::default().add_modifier(Modifier::BOLD));
207 let pseudo_term = PseudoTerminal::new(screen).block(block);
208 f.render_widget(pseudo_term, chunks[0]);
209 let explanation = "Press q to exit".to_string();
210 let explanation = Paragraph::new(explanation)
211 .style(Style::default().add_modifier(Modifier::BOLD | Modifier::REVERSED))
212 .alignment(Alignment::Center);
213 f.render_widget(explanation, chunks[1]);
214}57fn ui(f: &mut Frame, screen: &Screen) {
58 let chunks = ratatui::layout::Layout::default()
59 .direction(ratatui::layout::Direction::Vertical)
60 .margin(1)
61 .constraints(
62 [
63 ratatui::layout::Constraint::Percentage(100),
64 ratatui::layout::Constraint::Min(1),
65 ]
66 .as_ref(),
67 )
68 .split(f.area());
69 let title = Line::from("[ Running: ls ]");
70 let block = Block::default()
71 .borders(Borders::ALL)
72 .title(title)
73 .style(Style::default().add_modifier(Modifier::BOLD));
74 let pseudo_term = PseudoTerminal::new(screen)
75 .cursor(tui_term::widget::Cursor::default().visibility(false))
76 .block(block.clone());
77 f.render_widget(pseudo_term, chunks[0]);
78 let explanation = "Press q to exit";
79 let explanation = Paragraph::new(explanation)
80 .style(Style::default().add_modifier(Modifier::BOLD | Modifier::REVERSED))
81 .alignment(Alignment::Center);
82 f.render_widget(explanation, chunks[1]);
83}122fn ui(f: &mut Frame, screen: &Screen) {
123 let chunks = ratatui::layout::Layout::default()
124 .direction(ratatui::layout::Direction::Vertical)
125 .margin(1)
126 .constraints(
127 [
128 ratatui::layout::Constraint::Percentage(0),
129 ratatui::layout::Constraint::Percentage(100),
130 ratatui::layout::Constraint::Min(1),
131 ]
132 .as_ref(),
133 )
134 .split(f.area());
135 let title = Line::from("[ Running: top ]");
136 let block = Block::default()
137 .borders(Borders::ALL)
138 .title(title)
139 .style(Style::default().add_modifier(Modifier::BOLD));
140 let pseudo_term = PseudoTerminal::new(screen).block(block);
141 f.render_widget(pseudo_term, chunks[1]);
142 let block = Block::default().borders(Borders::ALL);
143 f.render_widget(block, f.area());
144 let explanation = "Press q to exit".to_string();
145 let explanation = Paragraph::new(explanation)
146 .style(Style::default().add_modifier(Modifier::BOLD | Modifier::REVERSED))
147 .alignment(Alignment::Center);
148 f.render_widget(explanation, chunks[2]);
149}87fn ui(f: &mut Frame, screen: &Screen) {
88 let chunks = ratatui::layout::Layout::default()
89 .direction(ratatui::layout::Direction::Vertical)
90 .margin(1)
91 .constraints(
92 [
93 ratatui::layout::Constraint::Percentage(50),
94 ratatui::layout::Constraint::Percentage(50),
95 ratatui::layout::Constraint::Min(1),
96 ]
97 .as_ref(),
98 )
99 .split(f.area());
100 let title = Line::from("[ Running: ls ]");
101 let block = Block::default()
102 .borders(Borders::ALL)
103 .title(title)
104 .style(Style::default().add_modifier(Modifier::BOLD));
105 let pseudo_term = PseudoTerminal::new(screen).block(block.clone());
106 f.render_widget(pseudo_term, chunks[0]);
107 let pseudo_term = PseudoTerminal::new(screen).block(block);
108 f.render_widget(pseudo_term, chunks[1]);
109 let block = Block::default().borders(Borders::ALL);
110 f.render_widget(block, f.area());
111 let explanation = "Press q to exit";
112 let explanation = Paragraph::new(explanation)
113 .style(Style::default().add_modifier(Modifier::BOLD | Modifier::REVERSED))
114 .alignment(Alignment::Center);
115 f.render_widget(explanation, chunks[2]);
116}95fn ui(f: &mut Frame, screen: &Screen) {
96 let chunks = ratatui::layout::Layout::default()
97 .direction(ratatui::layout::Direction::Vertical)
98 .margin(1)
99 .constraints(
100 [
101 ratatui::layout::Constraint::Percentage(50),
102 ratatui::layout::Constraint::Percentage(50),
103 ratatui::layout::Constraint::Min(1),
104 ]
105 .as_ref(),
106 )
107 .split(f.area());
108 let title = Line::from("[ Running: ls ]");
109 let block = Block::default()
110 .borders(Borders::ALL)
111 .title(title)
112 .style(Style::default().add_modifier(Modifier::BOLD));
113 let pseudo_term = PseudoTerminal::new(screen).block(block.clone());
114 f.render_widget(pseudo_term, chunks[0]);
115 let pseudo_term = PseudoTerminal::new(screen).block(block);
116 f.render_widget(pseudo_term, chunks[1]);
117 let block = Block::default().borders(Borders::ALL);
118 f.render_widget(block, f.area());
119 let explanation = "Press q to exit";
120 let explanation = Paragraph::new(explanation)
121 .style(Style::default().add_modifier(Modifier::BOLD | Modifier::REVERSED))
122 .alignment(Alignment::Center);
123 f.render_widget(explanation, chunks[2]);
124}Sourcepub fn block(self, block: Block<'a>) -> Self
pub fn block(self, block: Block<'a>) -> Self
Sets the block for the PseudoTerminal.
§Arguments
block: TheBlockto set.
§Example
use ratatui::widgets::Block;
use tui_term::widget::PseudoTerminal;
use vt100::Parser;
let mut parser = vt100::Parser::new(24, 80, 0);
let block = Block::default();
let pseudo_term = PseudoTerminal::new(parser.screen()).block(block);Examples found in repository?
189fn ui(f: &mut Frame, screen: &Screen) {
190 let chunks = ratatui::layout::Layout::default()
191 .direction(ratatui::layout::Direction::Vertical)
192 .margin(1)
193 .constraints(
194 [
195 ratatui::layout::Constraint::Percentage(100),
196 ratatui::layout::Constraint::Min(1),
197 ]
198 .as_ref(),
199 )
200 .split(f.area());
201 let block = Block::default()
202 .borders(Borders::ALL)
203 .style(Style::default().add_modifier(Modifier::BOLD));
204 let pseudo_term = PseudoTerminal::new(screen).block(block);
205 f.render_widget(pseudo_term, chunks[0]);
206 let explanation = "Press q to exit".to_string();
207 let explanation = Paragraph::new(explanation)
208 .style(Style::default().add_modifier(Modifier::BOLD | Modifier::REVERSED))
209 .alignment(Alignment::Center);
210 f.render_widget(explanation, chunks[1]);
211}More examples
192fn ui(f: &mut Frame, screen: &Screen) {
193 let chunks = ratatui::layout::Layout::default()
194 .direction(ratatui::layout::Direction::Vertical)
195 .margin(1)
196 .constraints(
197 [
198 ratatui::layout::Constraint::Percentage(100),
199 ratatui::layout::Constraint::Min(1),
200 ]
201 .as_ref(),
202 )
203 .split(f.area());
204 let block = Block::default()
205 .borders(Borders::ALL)
206 .style(Style::default().add_modifier(Modifier::BOLD));
207 let pseudo_term = PseudoTerminal::new(screen).block(block);
208 f.render_widget(pseudo_term, chunks[0]);
209 let explanation = "Press q to exit".to_string();
210 let explanation = Paragraph::new(explanation)
211 .style(Style::default().add_modifier(Modifier::BOLD | Modifier::REVERSED))
212 .alignment(Alignment::Center);
213 f.render_widget(explanation, chunks[1]);
214}57fn ui(f: &mut Frame, screen: &Screen) {
58 let chunks = ratatui::layout::Layout::default()
59 .direction(ratatui::layout::Direction::Vertical)
60 .margin(1)
61 .constraints(
62 [
63 ratatui::layout::Constraint::Percentage(100),
64 ratatui::layout::Constraint::Min(1),
65 ]
66 .as_ref(),
67 )
68 .split(f.area());
69 let title = Line::from("[ Running: ls ]");
70 let block = Block::default()
71 .borders(Borders::ALL)
72 .title(title)
73 .style(Style::default().add_modifier(Modifier::BOLD));
74 let pseudo_term = PseudoTerminal::new(screen)
75 .cursor(tui_term::widget::Cursor::default().visibility(false))
76 .block(block.clone());
77 f.render_widget(pseudo_term, chunks[0]);
78 let explanation = "Press q to exit";
79 let explanation = Paragraph::new(explanation)
80 .style(Style::default().add_modifier(Modifier::BOLD | Modifier::REVERSED))
81 .alignment(Alignment::Center);
82 f.render_widget(explanation, chunks[1]);
83}122fn ui(f: &mut Frame, screen: &Screen) {
123 let chunks = ratatui::layout::Layout::default()
124 .direction(ratatui::layout::Direction::Vertical)
125 .margin(1)
126 .constraints(
127 [
128 ratatui::layout::Constraint::Percentage(0),
129 ratatui::layout::Constraint::Percentage(100),
130 ratatui::layout::Constraint::Min(1),
131 ]
132 .as_ref(),
133 )
134 .split(f.area());
135 let title = Line::from("[ Running: top ]");
136 let block = Block::default()
137 .borders(Borders::ALL)
138 .title(title)
139 .style(Style::default().add_modifier(Modifier::BOLD));
140 let pseudo_term = PseudoTerminal::new(screen).block(block);
141 f.render_widget(pseudo_term, chunks[1]);
142 let block = Block::default().borders(Borders::ALL);
143 f.render_widget(block, f.area());
144 let explanation = "Press q to exit".to_string();
145 let explanation = Paragraph::new(explanation)
146 .style(Style::default().add_modifier(Modifier::BOLD | Modifier::REVERSED))
147 .alignment(Alignment::Center);
148 f.render_widget(explanation, chunks[2]);
149}87fn ui(f: &mut Frame, screen: &Screen) {
88 let chunks = ratatui::layout::Layout::default()
89 .direction(ratatui::layout::Direction::Vertical)
90 .margin(1)
91 .constraints(
92 [
93 ratatui::layout::Constraint::Percentage(50),
94 ratatui::layout::Constraint::Percentage(50),
95 ratatui::layout::Constraint::Min(1),
96 ]
97 .as_ref(),
98 )
99 .split(f.area());
100 let title = Line::from("[ Running: ls ]");
101 let block = Block::default()
102 .borders(Borders::ALL)
103 .title(title)
104 .style(Style::default().add_modifier(Modifier::BOLD));
105 let pseudo_term = PseudoTerminal::new(screen).block(block.clone());
106 f.render_widget(pseudo_term, chunks[0]);
107 let pseudo_term = PseudoTerminal::new(screen).block(block);
108 f.render_widget(pseudo_term, chunks[1]);
109 let block = Block::default().borders(Borders::ALL);
110 f.render_widget(block, f.area());
111 let explanation = "Press q to exit";
112 let explanation = Paragraph::new(explanation)
113 .style(Style::default().add_modifier(Modifier::BOLD | Modifier::REVERSED))
114 .alignment(Alignment::Center);
115 f.render_widget(explanation, chunks[2]);
116}95fn ui(f: &mut Frame, screen: &Screen) {
96 let chunks = ratatui::layout::Layout::default()
97 .direction(ratatui::layout::Direction::Vertical)
98 .margin(1)
99 .constraints(
100 [
101 ratatui::layout::Constraint::Percentage(50),
102 ratatui::layout::Constraint::Percentage(50),
103 ratatui::layout::Constraint::Min(1),
104 ]
105 .as_ref(),
106 )
107 .split(f.area());
108 let title = Line::from("[ Running: ls ]");
109 let block = Block::default()
110 .borders(Borders::ALL)
111 .title(title)
112 .style(Style::default().add_modifier(Modifier::BOLD));
113 let pseudo_term = PseudoTerminal::new(screen).block(block.clone());
114 f.render_widget(pseudo_term, chunks[0]);
115 let pseudo_term = PseudoTerminal::new(screen).block(block);
116 f.render_widget(pseudo_term, chunks[1]);
117 let block = Block::default().borders(Borders::ALL);
118 f.render_widget(block, f.area());
119 let explanation = "Press q to exit";
120 let explanation = Paragraph::new(explanation)
121 .style(Style::default().add_modifier(Modifier::BOLD | Modifier::REVERSED))
122 .alignment(Alignment::Center);
123 f.render_widget(explanation, chunks[2]);
124}Sourcepub fn cursor(self, cursor: Cursor) -> Self
pub fn cursor(self, cursor: Cursor) -> Self
Sets the cursor configuration for the PseudoTerminal.
The cursor method allows configuring the appearance of the cursor within the
PseudoTerminal widget.
§Arguments
cursor: TheCursorconfiguration to set.
§Example
use ratatui::style::Style;
use tui_term::widget::{Cursor, PseudoTerminal};
let mut parser = vt100::Parser::new(24, 80, 0);
let cursor = Cursor::default().symbol("|").style(Style::default());
let pseudo_term = PseudoTerminal::new(parser.screen()).cursor(cursor);Examples found in repository?
57fn ui(f: &mut Frame, screen: &Screen) {
58 let chunks = ratatui::layout::Layout::default()
59 .direction(ratatui::layout::Direction::Vertical)
60 .margin(1)
61 .constraints(
62 [
63 ratatui::layout::Constraint::Percentage(100),
64 ratatui::layout::Constraint::Min(1),
65 ]
66 .as_ref(),
67 )
68 .split(f.area());
69 let title = Line::from("[ Running: ls ]");
70 let block = Block::default()
71 .borders(Borders::ALL)
72 .title(title)
73 .style(Style::default().add_modifier(Modifier::BOLD));
74 let pseudo_term = PseudoTerminal::new(screen)
75 .cursor(tui_term::widget::Cursor::default().visibility(false))
76 .block(block.clone());
77 f.render_widget(pseudo_term, chunks[0]);
78 let explanation = "Press q to exit";
79 let explanation = Paragraph::new(explanation)
80 .style(Style::default().add_modifier(Modifier::BOLD | Modifier::REVERSED))
81 .alignment(Alignment::Center);
82 f.render_widget(explanation, chunks[1]);
83}More examples
38async fn main() -> io::Result<()> {
39 init_panic_hook();
40 let (mut terminal, mut size) = setup_terminal().unwrap();
41
42 let cwd = std::env::current_dir().unwrap();
43 let mut cmd = CommandBuilder::new_default_prog();
44 cmd.cwd(cwd);
45
46 let mut panes: Vec<PtyPane> = Vec::new();
47 let mut active_pane: Option<usize> = None;
48
49 // Add a default pane
50 let pane_size = calc_pane_size(size, 1);
51 open_new_pane(&mut panes, &mut active_pane, &cmd, pane_size)?;
52
53 loop {
54 terminal.draw(|f| {
55 let chunks = Layout::default()
56 .direction(Direction::Vertical)
57 .margin(1)
58 .constraints([Constraint::Percentage(100), Constraint::Min(1)].as_ref())
59 .split(f.area());
60
61 let pane_height = if panes.is_empty() {
62 chunks[0].height
63 } else {
64 (chunks[0].height.saturating_sub(1)) / panes.len() as u16
65 };
66
67 for (index, pane) in panes.iter().enumerate() {
68 let block = Block::default()
69 .borders(Borders::ALL)
70 .style(Style::default().add_modifier(Modifier::BOLD));
71 let mut cursor = Cursor::default();
72 let block = if Some(index) == active_pane {
73 block.style(
74 Style::default()
75 .add_modifier(Modifier::BOLD)
76 .fg(Color::LightMagenta),
77 )
78 } else {
79 cursor.hide();
80 block
81 };
82 let parser = pane.parser.read().unwrap();
83 let screen = parser.screen();
84 let pseudo_term = PseudoTerminal::new(screen).block(block).cursor(cursor);
85 let pane_chunk = Rect {
86 x: chunks[0].x,
87 y: chunks[0].y + (index as u16 * pane_height), /* Adjust the y coordinate for
88 * each pane */
89 width: chunks[0].width,
90 height: pane_height, // Use the calculated pane height directly
91 };
92 f.render_widget(pseudo_term, pane_chunk);
93 }
94
95 let explanation =
96 "Ctrl+n to open a new pane | Ctrl+x to close the active pane | Ctrl+q to quit";
97 let explanation = Paragraph::new(explanation)
98 .style(Style::default().add_modifier(Modifier::BOLD | Modifier::REVERSED))
99 .alignment(Alignment::Center);
100 f.render_widget(explanation, chunks[1]);
101 })?;
102
103 if event::poll(Duration::from_millis(10))? {
104 tracing::info!("Terminal Size: {:?}", terminal.size());
105 match event::read()? {
106 Event::Key(key) => match key.code {
107 KeyCode::Char('q') if key.modifiers.contains(KeyModifiers::CONTROL) => {
108 cleanup_terminal(&mut terminal).unwrap();
109 return Ok(());
110 }
111 KeyCode::Char('n') if key.modifiers.contains(KeyModifiers::CONTROL) => {
112 let pane_size = calc_pane_size(size, panes.len() + 1);
113 tracing::info!("Opened new pane with size: {size:?}");
114 resize_all_panes(&mut panes, pane_size);
115 open_new_pane(&mut panes, &mut active_pane, &cmd, pane_size)?;
116 }
117 KeyCode::Char('x') if key.modifiers.contains(KeyModifiers::CONTROL) => {
118 close_active_pane(&mut panes, &mut active_pane).await?;
119 resize_all_panes(&mut panes, pane_size);
120 }
121 KeyCode::Char('k') if key.modifiers.contains(KeyModifiers::CONTROL) => {
122 if let Some(pane) = active_pane {
123 active_pane = Some(pane.saturating_sub(1));
124 }
125 }
126 KeyCode::Char('j') if key.modifiers.contains(KeyModifiers::CONTROL) => {
127 if let Some(pane) = active_pane {
128 if pane < panes.len() - 1 {
129 active_pane = Some(pane.saturating_add(1));
130 }
131 }
132 }
133 _ => {
134 if let Some(index) = active_pane {
135 if handle_pane_key_event(&mut panes[index], &key).await {
136 continue;
137 }
138 }
139 }
140 },
141 Event::Resize(cols, rows) => {
142 tracing::info!("Resized to: rows: {} cols: {}", rows, cols);
143 size.rows = rows;
144 size.cols = cols;
145 let pane_size = calc_pane_size(size, panes.len());
146 resize_all_panes(&mut panes, pane_size);
147 }
148 _ => {}
149 }
150 }
151 }
152}pub const fn screen(&self) -> &S
Trait Implementations§
Auto Trait Implementations§
impl<'a, S> Freeze for PseudoTerminal<'a, S>
impl<'a, S> RefUnwindSafe for PseudoTerminal<'a, S>where
S: RefUnwindSafe,
impl<'a, S> Send for PseudoTerminal<'a, S>where
S: Sync,
impl<'a, S> Sync for PseudoTerminal<'a, S>where
S: Sync,
impl<'a, S> Unpin for PseudoTerminal<'a, S>
impl<'a, S> UnwindSafe for PseudoTerminal<'a, S>where
S: RefUnwindSafe,
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Source§impl<T> Downcast for Twhere
T: Any,
impl<T> Downcast for Twhere
T: Any,
Source§fn into_any(self: Box<T>) -> Box<dyn Any>
fn into_any(self: Box<T>) -> Box<dyn Any>
Box<dyn Trait> (where Trait: Downcast) to Box<dyn Any>. Box<dyn Any> can
then be further downcast into Box<ConcreteType> where ConcreteType implements Trait.Source§fn into_any_rc(self: Rc<T>) -> Rc<dyn Any>
fn into_any_rc(self: Rc<T>) -> Rc<dyn Any>
Rc<Trait> (where Trait: Downcast) to Rc<Any>. Rc<Any> can then be
further downcast into Rc<ConcreteType> where ConcreteType implements Trait.Source§fn as_any(&self) -> &(dyn Any + 'static)
fn as_any(&self) -> &(dyn Any + 'static)
&Trait (where Trait: Downcast) to &Any. This is needed since Rust cannot
generate &Any’s vtable from &Trait’s.Source§fn as_any_mut(&mut self) -> &mut (dyn Any + 'static)
fn as_any_mut(&mut self) -> &mut (dyn Any + 'static)
&mut Trait (where Trait: Downcast) to &Any. This is needed since Rust cannot
generate &mut Any’s vtable from &mut Trait’s.Source§impl<T> DowncastSync for T
impl<T> DowncastSync for T
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self>
fn into_either(self, into_left: bool) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left is true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
self into a Left variant of Either<Self, Self>
if into_left(&self) returns true.
Converts self into a Right variant of Either<Self, Self>
otherwise. Read more