From a2760bb9fb1df043eccd12b781a43ce4f99947f4 Mon Sep 17 00:00:00 2001 From: Levi Zim Date: Fri, 19 Apr 2024 20:43:21 +0800 Subject: [PATCH 1/5] Fix typo in CONTRIBUTING.md --- docs/CONTRIBUTING.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/CONTRIBUTING.md b/docs/CONTRIBUTING.md index 4270d42..89aa935 100644 --- a/docs/CONTRIBUTING.md +++ b/docs/CONTRIBUTING.md @@ -5,7 +5,7 @@ We are always happy to receive contributions and attempt to process them in a ti ## Branches Releases will be cut on the `release` branch. -Most PR`s and features should land on the `development` branch. +Most PRs and features should land on the `development` branch. ## Issues To get an overview of what can be worked on, please take a look at the [issues](https://github.com/a-kenji/tui-term/issues?q=is%3Aissue+is%3Aopen+sort%3Aupdated-desc). From 70c05fdccaa5c829f06c845e15b24b3b4fe5a715 Mon Sep 17 00:00:00 2001 From: kxxt Date: Fri, 19 Apr 2024 22:52:01 +0800 Subject: [PATCH 2/5] Fix parameter order of crossterm resize event --- examples/nested_shell.rs | 2 +- examples/nested_shell_async.rs | 2 +- examples/smux.rs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/examples/nested_shell.rs b/examples/nested_shell.rs index a865dd4..1b9192d 100644 --- a/examples/nested_shell.rs +++ b/examples/nested_shell.rs @@ -178,7 +178,7 @@ fn run( Event::FocusLost => {} Event::Mouse(_) => {} Event::Paste(_) => todo!(), - Event::Resize(rows, cols) => { + Event::Resize(cols, rows) => { parser.write().unwrap().set_size(rows, cols); } } diff --git a/examples/nested_shell_async.rs b/examples/nested_shell_async.rs index 43af69c..d3ee60f 100644 --- a/examples/nested_shell_async.rs +++ b/examples/nested_shell_async.rs @@ -181,7 +181,7 @@ async fn run( Event::FocusLost => {} Event::Mouse(_) => {} Event::Paste(_) => todo!(), - Event::Resize(rows, cols) => { + Event::Resize(cols, rows) => { parser.write().unwrap().set_size(rows, cols); } } diff --git a/examples/smux.rs b/examples/smux.rs index 310fcee..8dbad26 100644 --- a/examples/smux.rs +++ b/examples/smux.rs @@ -137,7 +137,7 @@ async fn main() -> io::Result<()> { } } }, - Event::Resize(rows, cols) => { + Event::Resize(cols, rows) => { tracing::info!("Resized to: rows: {} cols: {}", rows, cols); for pane in panes.iter_mut() { pane.parser.write().unwrap().set_size(rows, cols); From 3a302288594783c5a29a565cf33bd384251660b6 Mon Sep 17 00:00:00 2001 From: kxxt Date: Sat, 20 Apr 2024 07:35:00 +0800 Subject: [PATCH 3/5] Implement resize for the smux example --- examples/smux.rs | 71 +++++++++++++++++++++++++++++++++--------------- 1 file changed, 49 insertions(+), 22 deletions(-) diff --git a/examples/smux.rs b/examples/smux.rs index 8dbad26..c50ec0e 100644 --- a/examples/smux.rs +++ b/examples/smux.rs @@ -12,7 +12,7 @@ use crossterm::{ execute, terminal::{disable_raw_mode, enable_raw_mode, EnterAlternateScreen, LeaveAlternateScreen}, }; -use portable_pty::{native_pty_system, CommandBuilder, PtySize}; +use portable_pty::{native_pty_system, CommandBuilder, MasterPty, PtySize}; use ratatui::{ backend::CrosstermBackend, layout::{Alignment, Constraint, Direction, Layout, Rect}, @@ -28,7 +28,7 @@ use tracing::Level; use tracing_subscriber::FmtSubscriber; use tui_term::widget::PseudoTerminal; -#[derive(Debug, Clone)] +#[derive(Debug, Clone, Copy)] struct Size { cols: u16, rows: u16, @@ -47,8 +47,7 @@ async fn main() -> io::Result<()> { let mut active_pane: Option = None; // Add a default pane - let mut pane_size = size.clone(); - pane_size.rows -= 2; + let pane_size = calc_pane_size(size, 1); open_new_pane(&mut panes, &mut active_pane, &cmd, pane_size)?; loop { @@ -108,14 +107,14 @@ async fn main() -> io::Result<()> { return Ok(()); } KeyCode::Char('n') if key.modifiers.contains(KeyModifiers::CONTROL) => { - let amount = panes.len() + 1; - let mut pane_size = size.clone(); - pane_size.rows /= amount as u16; + let pane_size = calc_pane_size(size, panes.len() + 1); tracing::info!("Opened new pane with size: {size:?}"); + resize_all_panes(&mut panes, pane_size); open_new_pane(&mut panes, &mut active_pane, &cmd, pane_size)?; } KeyCode::Char('x') if key.modifiers.contains(KeyModifiers::CONTROL) => { close_active_pane(&mut panes, &mut active_pane).await?; + resize_all_panes(&mut panes, pane_size); } KeyCode::Char('k') if key.modifiers.contains(KeyModifiers::CONTROL) => { if let Some(pane) = active_pane { @@ -139,11 +138,10 @@ async fn main() -> io::Result<()> { }, Event::Resize(cols, rows) => { tracing::info!("Resized to: rows: {} cols: {}", rows, cols); - for pane in panes.iter_mut() { - pane.parser.write().unwrap().set_size(rows, cols); - } size.rows = rows; size.cols = cols; + let pane_size = calc_pane_size(size, panes.len()); + resize_all_panes(&mut panes, pane_size); } _ => {} } @@ -151,9 +149,22 @@ async fn main() -> io::Result<()> { } } +fn calc_pane_size(mut size: Size, nr_panes: usize) -> Size { + size.rows -= 2; + size.rows /= nr_panes as u16; + size +} + +fn resize_all_panes(panes: &mut Vec, size: Size) { + for pane in panes.iter() { + pane.resize(size); + } +} + struct PtyPane { parser: Arc>, sender: Sender, + master_pty: Box, } impl PtyPane { @@ -205,19 +216,35 @@ impl PtyPane { let (tx, mut rx) = channel::(32); - { - let mut writer = BufWriter::new(pty_pair.master.take_writer().unwrap()); - // Drop writer on purpose - tokio::spawn(async move { - while let Some(bytes) = rx.recv().await { - writer.write_all(&bytes).unwrap(); - writer.flush().unwrap(); - } - drop(pty_pair.master); - }); - } + let mut writer = BufWriter::new(pty_pair.master.take_writer().unwrap()); + // writer is moved into the tokio task below + tokio::spawn(async move { + while let Some(bytes) = rx.recv().await { + writer.write_all(&bytes).unwrap(); + writer.flush().unwrap(); + } + }); - Ok(Self { parser, sender: tx }) + Ok(Self { + parser, + sender: tx, + master_pty: pty_pair.master, + }) + } + + fn resize(&self, size: Size) { + self.parser + .write() + .unwrap() + .set_size(size.rows - 4, size.cols - 4); + self.master_pty + .resize(PtySize { + rows: size.rows - 4, + cols: size.cols - 4, + pixel_width: 0, + pixel_height: 0, + }) + .unwrap(); } } From ccf73e4d78428ed250384b09f87e60feb3930268 Mon Sep 17 00:00:00 2001 From: a-kenji Date: Sun, 21 Apr 2024 15:13:32 +0200 Subject: [PATCH 4/5] examples: smux handle control characters --- examples/smux.rs | 12 ++++++++---- 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/examples/smux.rs b/examples/smux.rs index c50ec0e..406798a 100644 --- a/examples/smux.rs +++ b/examples/smux.rs @@ -262,11 +262,15 @@ async fn handle_pane_key_event(pane: &mut PtyPane, key: &KeyEvent) -> bool { // Close the pane return false; } - 'l' => { - send = vec![27, 91, 50, 74]; + _ => { + let char = ch.to_ascii_uppercase(); + let ascii_val = char as u8; + // Since char is guaranteed to be an ASCII character, + // we can safely subtract 64 to get + // the corresponding control character + let ascii_to_send = ascii_val - 64; + send = vec![ascii_to_send]; } - - _ => {} } } send From a03ce2837f54680649673568e254ed5b0722c97f Mon Sep 17 00:00:00 2001 From: a-kenji Date: Sun, 21 Apr 2024 15:45:10 +0200 Subject: [PATCH 5/5] examples: show cursor on focused pane in the smux example --- examples/smux.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/examples/smux.rs b/examples/smux.rs index 406798a..c864666 100644 --- a/examples/smux.rs +++ b/examples/smux.rs @@ -26,7 +26,7 @@ use tokio::{ }; use tracing::Level; use tracing_subscriber::FmtSubscriber; -use tui_term::widget::PseudoTerminal; +use tui_term::widget::{Cursor, PseudoTerminal}; #[derive(Debug, Clone, Copy)] struct Size { @@ -68,6 +68,7 @@ async fn main() -> io::Result<()> { let block = Block::default() .borders(Borders::ALL) .style(Style::default().add_modifier(Modifier::BOLD)); + let mut cursor = Cursor::default(); let block = if Some(index) == active_pane { block.style( Style::default() @@ -75,11 +76,12 @@ async fn main() -> io::Result<()> { .fg(Color::LightMagenta), ) } else { + cursor.hide(); block }; let parser = pane.parser.read().unwrap(); let screen = parser.screen(); - let pseudo_term = PseudoTerminal::new(screen).block(block); + let pseudo_term = PseudoTerminal::new(screen).block(block).cursor(cursor); let pane_chunk = Rect { x: chunks[0].x, y: chunks[0].y + (index as u16 * pane_height), /* Adjust the y coordinate for