From 7fb37a8f35fe68e13c8c1e435264645e5e1de4e2 Mon Sep 17 00:00:00 2001 From: Thomas Forgione Date: Sat, 21 Oct 2023 16:15:15 +0200 Subject: [PATCH] Fix terminal sizes --- Cargo.lock | 121 ++++++++++++++++++++++++++++++- Cargo.toml | 1 + src/lib.rs | 205 ++++++++++++++++++++++++++++++++++------------------- 3 files changed, 252 insertions(+), 75 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index c510720..fbbbd99 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -8,16 +8,45 @@ version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" +[[package]] +name = "bitflags" +version = "2.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "327762f6e5a765692301e5bb513e0d9fef63be86bbc14528052b1cd3e6f03e07" + +[[package]] +name = "errno" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ac3e13f66a2f95e32a39eaa81f6b95d42878ca0e1db0c7543723dfe12557e860" +dependencies = [ + "libc", + "windows-sys", +] + +[[package]] +name = "itoa" +version = "1.0.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "af150ab688ff2122fcef229be89cb50dd66af9e01a4ff320cc137eecc9bacc38" + [[package]] name = "libc" version = "0.2.149" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "a08173bc88b7955d1b3145aa561539096c421ac8debde8cbc3612ec635fee29b" +[[package]] +name = "linux-raw-sys" +version = "0.4.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "da2479e8c062e40bf0066ffa0bc823de0a9368974af99c9f6df941d2c231e03f" + [[package]] name = "multiview" version = "0.1.0" dependencies = [ + "pty-process", "termion", ] @@ -27,13 +56,23 @@ version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "b8f8bdf33df195859076e54ab11ee78a1b208382d3a26ec40d142ffc1ecc49ef" +[[package]] +name = "pty-process" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8749b545e244c90bf74a5767764cc2194f1888bb42f84015486a64c82bea5cc0" +dependencies = [ + "libc", + "rustix", +] + [[package]] name = "redox_syscall" version = "0.2.16" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a" dependencies = [ - "bitflags", + "bitflags 1.3.2", ] [[package]] @@ -45,6 +84,20 @@ dependencies = [ "redox_syscall", ] +[[package]] +name = "rustix" +version = "0.38.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "67ce50cb2e16c2903e30d1cbccfd8387a74b9d4c938b6a4c5ec6cc7556f7a8a0" +dependencies = [ + "bitflags 2.4.1", + "errno", + "itoa", + "libc", + "linux-raw-sys", + "windows-sys", +] + [[package]] name = "termion" version = "2.0.1" @@ -56,3 +109,69 @@ dependencies = [ "redox_syscall", "redox_termios", ] + +[[package]] +name = "windows-sys" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" +dependencies = [ + "windows-targets", +] + +[[package]] +name = "windows-targets" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" +dependencies = [ + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" + +[[package]] +name = "windows_i686_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" + +[[package]] +name = "windows_i686_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" diff --git a/Cargo.toml b/Cargo.toml index 159b6d6..fc2ea01 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,4 +6,5 @@ edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] +pty-process = "0.4.0" termion = "2.0.1" diff --git a/src/lib.rs b/src/lib.rs index 654dcac..dc2d71d 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,8 +1,11 @@ -use std::io::{self, stdin, stdout, BufRead, BufReader, Write}; -use std::process::{Command, Stdio}; +use std::io::{self, stdin, stdout, Read, Write}; +use std::process::Stdio; use std::sync::mpsc::{channel, Sender}; use std::{env, thread}; +use pty_process::blocking::Command; +use pty_process::blocking::Pty; + use termion::event::{Event, Key, MouseEvent}; use termion::input::{MouseTerminal, TermRead}; use termion::raw::IntoRawMode; @@ -136,73 +139,103 @@ pub struct Tile { /// /// We put both stdout and stderr here to avoid dealing with order between stdout and stderr. pub stdout: Vec, + + /// The sender for the communication with the multiview. + pub sender: Sender, + + /// Coordinates of the tile. + pub coords: (u16, u16), } impl Tile { /// Creates a new empty tile. pub fn new(command: &[String], i: u16, j: u16, sender: Sender) -> Tile { - let command = command - .into_iter() + Tile { + command: command + .into_iter() + .map(|x| x.to_string()) + .collect::>(), + stdout: vec![], + sender, + coords: (i, j), + } + } + + /// Starts the commands. + pub fn start(&mut self, width: u16, height: u16) { + let command = self + .command + .iter() .map(|x| x.to_string()) .collect::>(); + let coords = self.coords; let clone = command.clone(); + let sender = self.sender.clone(); thread::spawn(move || { + let pty = Pty::new().unwrap(); + pty.resize(pty_process::Size::new(height - 4, width - 4)) + .unwrap(); + let mut child = Command::new(&clone[0]) .args(&clone[1..]) .stdout(Stdio::piped()) .stderr(Stdio::piped()) - .spawn() + .spawn(&pty.pts().unwrap()) .unwrap(); - let stdout = child.stdout.take().unwrap(); - - let stderr = child.stderr.take().unwrap(); + let mut stdout = child.stdout.take().unwrap(); + let mut stderr = child.stderr.take().unwrap(); let stderr_sender = sender.clone(); - thread::spawn(move || { - let reader = BufReader::new(stderr); - let mut lines = reader.lines(); + let coords = coords; - loop { - match lines.next() { - Some(Ok(line)) => { - stderr_sender.send(Msg::Stderr(i, j, line)).unwrap(); - } + thread::spawn(move || loop { + let mut buffer = [0; 256]; + let result = stderr.read(&mut buffer); - Some(Err(_)) => { - break; - } + match result { + Ok(0) => break, - None => break, + Ok(n) => { + stderr_sender + .send(Msg::Stderr( + coords.0, + coords.1, + String::from_utf8_lossy(&buffer[0..n]).to_string(), + )) + .unwrap(); } - } - stderr_sender - .send(Msg::Stdout(i, j, String::new())) - .unwrap(); + Err(_) => break, + } }); - let reader = BufReader::new(stdout); - - let mut lines = reader.lines(); - loop { - match lines.next() { - Some(Ok(line)) => { - sender.send(Msg::Stdout(i, j, line)).unwrap(); + let mut buffer = [0; 256]; + let result = stdout.read(&mut buffer); + + match result { + Ok(0) => break, + + Ok(n) => { + sender + .send(Msg::Stderr( + coords.0, + coords.1, + String::from_utf8_lossy(&buffer[0..n]).to_string(), + )) + .unwrap(); } - Some(Err(_)) => { - break; - } - - None => break, + Err(_) => break, } } - sender.send(Msg::Stdout(i, j, String::new())).unwrap(); + sender + .send(Msg::Stdout(coords.0, coords.1, String::new())) + .unwrap(); let code = child.wait().unwrap().code().unwrap(); @@ -219,16 +252,10 @@ impl Tile { color::Reset.fg_str() ); - sender.send(Msg::Stdout(i, j, exit_string)).unwrap(); + sender + .send(Msg::Stdout(coords.0, coords.1, exit_string)) + .unwrap(); }); - - Tile { - command: command - .into_iter() - .map(|x| x.to_string()) - .collect::>(), - stdout: vec![], - } } } @@ -346,47 +373,66 @@ impl Multiview { write!( self.stdout, - "{}{} {}Command: {}{}", + "{}{} {}Command: {}{}{}", color::Reset.fg_str(), cursor::Goto(x1 + 1, y1 + 1), style::Bold, command_str, style::Reset, + cursor::Goto(x1 + 2, y1 + 3), )?; + let mut counting = true; let mut line_index = 0; + let mut current_char_index = 0; + for line in lines { - let mut len = str_len(&line) as i32; - let mut current_char_index = 0; + for c in line.chars() { + if c == '\x1b' { + counting = false; + } - if len == 0 { - line_index += 1; - continue; - } + match c { + '\n' => { + line_index += 1; + current_char_index = 0; + write!( + self.stdout, + "{}", + cursor::Goto(x1 + 2, y1 + 3 + line_index as u16) + )?; + } - while len > 0 { - let sub = sub_str( - &line, - current_char_index, - current_char_index + term_size.0 - 4, - ); - write!( - self.stdout, - "{}{}", - cursor::Goto(x1 + 2, y1 + 3 + line_index as u16), - sub.replace( - "\r", - &format!("{}", cursor::Goto(x1 + 2, y1 + 3 + line_index as u16)) - ), - )?; + '\r' => { + current_char_index = 0; + write!( + self.stdout, + "{}", + cursor::Goto(x1 + 2, y1 + 3 + line_index as u16) + )?; + } - // if sub.contains(|x| x == '\r') { - // line_index -= 1; - // } + _ => { + if counting { + current_char_index += 1; + } - line_index += 1; - len -= (term_size.0 - 4) as i32; - current_char_index += term_size.0 - 4; + if current_char_index == w - 3 { + line_index += 1; + current_char_index = 1; + write!( + self.stdout, + "{}", + cursor::Goto(x1 + 2, y1 + 3 + line_index as u16) + )?; + } + write!(self.stdout, "{}", c)?; + } + } + + if c == 'm' { + counting = true; + } } } @@ -470,6 +516,17 @@ pub fn main() -> io::Result<()> { let mut multiview = Multiview::new(stdout, tiles)?; multiview.render(term_size)?; + let tile_size = ( + term_size.0 / multiview.tiles[0].len() as u16, + term_size.1 / multiview.tiles.len() as u16, + ); + + for row in &mut multiview.tiles { + for tile in row { + tile.start(tile_size.0, tile_size.1); + } + } + thread::spawn(move || { for c in stdin.events() { let evt = c.unwrap();