diff options
| author | Aram Drevekenin <aram@poor.dev> | 2020-09-16 11:04:16 +0200 |
|---|---|---|
| committer | Aram Drevekenin <aram@poor.dev> | 2020-09-16 11:04:16 +0200 |
| commit | 18413fcaa4e322f58182d72ea0fb3d9ace21bcdc (patch) | |
| tree | 98f61a1225bcd48b2ef84f3a48860d1294df251b /src/main.rs | |
| parent | tests(integration): resize left + up + down (diff) | |
| download | sl0ppij-18413fcaa4e322f58182d72ea0fb3d9ace21bcdc.tar.gz sl0ppij-18413fcaa4e322f58182d72ea0fb3d9ace21bcdc.tar.xz sl0ppij-18413fcaa4e322f58182d72ea0fb3d9ace21bcdc.zip | |
refactor(structure): move stuff out of main
Diffstat (limited to 'src/main.rs')
| -rw-r--r-- | src/main.rs | 2114 |
1 files changed, 6 insertions, 2108 deletions
diff --git a/src/main.rs b/src/main.rs index 30f941c8..18f41d90 100644 --- a/src/main.rs +++ b/src/main.rs @@ -2,726 +2,17 @@ mod tests; mod os_input_output; +mod terminal_pane; +mod pty_bus; +mod screen; -use ::std::fmt::{self, Display, Formatter}; -use std::cmp::max; use std::io::{Read, Write}; -use std::collections::{VecDeque, HashSet, BTreeMap}; -use nix::pty::Winsize; -use std::os::unix::io::RawFd; use ::std::thread; -use vte; -use async_std::stream::*; -use async_std::task; -use async_std::task::*; -use ::std::pin::*; -use std::sync::mpsc::{channel, Sender, Receiver}; use crate::os_input_output::{get_os_input, OsApi}; - -use vte::Perform; - -struct ReadFromPid { - pid: RawFd, - os_input: Box<dyn OsApi>, -} - -impl ReadFromPid { - fn new(pid: &RawFd, os_input: Box<dyn OsApi>) -> ReadFromPid { - ReadFromPid { - pid: *pid, - os_input, - } - } -} - -impl Stream for ReadFromPid { - type Item = Vec<u8>; - fn poll_next(mut self: Pin<&mut Self>, _cx: &mut Context<'_>) -> Poll<Option<Self::Item>> { - let mut read_buffer = [0; 115200]; - let pid = self.pid; - let read_result = &self.os_input.read_from_tty_stdout(pid, &mut read_buffer); - match read_result { - Ok(res) => { - if *res == 0 { - // indicates end of file - return Poll::Ready(None); - } else { - let res = Some(read_buffer[..=*res].to_vec()); - return Poll::Ready(res); - } - }, - Err(e) => { - match e { - nix::Error::Sys(errno) => { - if *errno == nix::errno::Errno::EAGAIN { - return Poll::Ready(Some(vec![])) // TODO: better with timeout waker somehow - } else { - Poll::Ready(None) - } - }, - _ => Poll::Ready(None) - } - } - } - } -} - -#[derive(Clone)] -pub struct TerminalCharacter { - pub character: char, - pub ansi_code: Option<String>, -} - -impl PartialEq for TerminalCharacter { - fn eq(&self, other: &Self) -> bool { - match (&self.ansi_code, &other.ansi_code) { - (Some(self_code), Some(other_code)) => { - self_code == other_code && self.character == other.character - }, - (None, None) => { - self.character == other.character - } - _ => { - false - } - } - } -} - -impl Eq for TerminalCharacter {} - -impl TerminalCharacter { - pub fn new (character: char) -> Self { - TerminalCharacter { - character, - ansi_code: None - } - } - pub fn ansi_code(mut self, ansi_code: String) -> Self { - self.ansi_code = Some(ansi_code); - self - } -} - - -impl Display for TerminalCharacter { - fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { - match &self.ansi_code { - Some(code) => write!(f, "{}{}", code, self.character), - None => write!(f, "{}", self.character) - } - } -} - -impl ::std::fmt::Debug for TerminalCharacter { - fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { - write!(f, "{}", self.character) - } -} - -pub struct TerminalOutput { - pub pid: RawFd, - pub characters: Vec<TerminalCharacter>, - pub display_rows: u16, - pub display_cols: u16, - pub should_render: bool, - cursor_position: usize, - newline_indices: Vec<usize>, // canonical line breaks we get from the vt interpreter - linebreak_indices: Vec<usize>, // linebreaks from line wrapping - pending_ansi_code: Option<String>, // this is used eg. in a carriage return, where we need to preserve the style - x_coords: u16, - y_coords: u16, -} - -const EMPTY_TERMINAL_CHARACTER: TerminalCharacter = TerminalCharacter { character: ' ', ansi_code: None }; - -impl TerminalOutput { - pub fn new (pid: RawFd, ws: Winsize, x_coords: u16, y_coords: u16) -> TerminalOutput { - TerminalOutput { - pid, - characters: vec![], - cursor_position: 0, - newline_indices: Vec::new(), - linebreak_indices: Vec::new(), - display_rows: ws.ws_row, - display_cols: ws.ws_col, - should_render: true, - pending_ansi_code: None, - x_coords, - y_coords, - } - } - pub fn handle_event(&mut self, event: VteEvent) { - self.should_render = true; // TODO: more accurately - match event { - VteEvent::Print(c) => { - self.print(c); - }, - VteEvent::Execute(byte) => { - self.execute(byte); - }, - VteEvent::Hook(params, intermediates, ignore, c) => { - self.hook(¶ms, &intermediates, ignore, c); - }, - VteEvent::Put(byte) => { - self.put(byte); - }, - VteEvent::Unhook => { - self.unhook(); - }, - VteEvent::OscDispatch(params, bell_terminated) => { - let params: Vec<&[u8]> = params.iter().map(|p| &p[..]).collect(); - self.osc_dispatch(¶ms[..], bell_terminated); - }, - VteEvent::CsiDispatch(params, intermediates, ignore, c) => { - self.csi_dispatch(¶ms, &intermediates, ignore, c); - }, - VteEvent::EscDispatch(intermediates, ignore, byte) => { - self.esc_dispatch(&intermediates, ignore, byte); - } - } - } - pub fn reduce_width_right(&mut self, count: u16) { - self.x_coords += count; - self.display_cols -= count; - self.reflow_lines(); - self.should_render = true; - } - pub fn reduce_width_left(&mut self, count: u16) { - self.display_cols -= count; - self.reflow_lines(); - self.should_render = true; - } - pub fn increase_width_left(&mut self, count: u16) { - self.x_coords -= count; - self.display_cols += count; - self.reflow_lines(); - self.should_render = true; - } - pub fn increase_width_right(&mut self, count: u16) { - self.display_cols += count; - self.reflow_lines(); - self.should_render = true; - } - pub fn reduce_height_down(&mut self, count: u16) { - self.y_coords += count; - self.display_rows -= count; - self.reflow_lines(); - self.should_render = true; - } - pub fn increase_height_down(&mut self, count: u16) { - self.display_rows += count; - self.reflow_lines(); - self.should_render = true; - } - pub fn increase_height_up(&mut self, count: u16) { - self.y_coords -= count; - self.display_rows += count; - self.reflow_lines(); - self.should_render = true; - } - pub fn reduce_height_up(&mut self, count: u16) { - self.display_rows -= count; - self.reflow_lines(); - self.should_render = true; - } - pub fn change_size(&mut self, ws: &Winsize) { - self.display_cols = ws.ws_col; - self.display_rows = ws.ws_row; - self.reflow_lines(); - self.should_render = true; - } - fn reflow_lines (&mut self) { - self.linebreak_indices.clear(); - - let mut newline_indices = self.newline_indices.iter(); - let mut next_newline_index = newline_indices.next(); - - let mut x: u64 = 0; - for (i, _c) in self.characters.iter().enumerate() { - if next_newline_index == Some(&i) { - x = 0; - next_newline_index = newline_indices.next(); - } else if x == self.display_cols as u64 && i <= self.cursor_position { - self.linebreak_indices.push(i); - x = 0; - } - x += 1; - } - } - pub fn buffer_as_vte_output(&mut self) -> Option<String> { - if self.should_render { - let mut vte_output = String::new(); - let buffer_lines = &self.read_buffer_as_lines(); - let display_cols = &self.display_cols; - for (row, line) in buffer_lines.iter().enumerate() { - vte_output.push_str(&format!("\u{1b}[{};{}H\u{1b}[m", self.y_coords as usize + row + 1, self.x_coords + 1)); // goto row/col - for (col, t_character) in line.iter().enumerate() { - if (col as u16) < *display_cols { - // in some cases (eg. while resizing) some characters will spill over - // before they are corrected by the shell (for the prompt) or by reflowing - // lines - vte_output.push_str(&t_character.to_string()); - } - } - } - self.should_render = false; - Some(vte_output) - } else { - None - } - } - fn read_buffer_as_lines (&self) -> Vec<Vec<&TerminalCharacter>> { - if DEBUGGING { - return vec![]; - } - if self.characters.len() == 0 { - let mut output = vec![]; - let mut empty_line = vec![]; - for _ in 0..self.display_cols { - empty_line.push(&EMPTY_TERMINAL_CHARACTER); - } - for _ in 0..self.display_rows as usize { - output.push(Vec::from(empty_line.clone())); - } - return output - } - let mut output: VecDeque<Vec<&TerminalCharacter>> = VecDeque::new(); - let mut i = self.characters.len(); - let mut current_line: VecDeque<&TerminalCharacter> = VecDeque::new(); - - let mut newline_indices = self.newline_indices.iter().rev(); - let mut linebreak_indices = self.linebreak_indices.iter().rev(); - - let mut next_newline_index = newline_indices.next(); - let mut next_linebreak_index = linebreak_indices.next(); - - loop { - i -= 1; - if let Some(newline_index) = next_newline_index { - if *newline_index == i + 1 { - // pad line - if current_line.len() > 0 { - for _ in current_line.len()..self.display_cols as usize { - current_line.push_back(&EMPTY_TERMINAL_CHARACTER); - } - output.push_front(Vec::from(current_line.drain(..).collect::<Vec<&TerminalCharacter>>())); - } - next_newline_index = newline_indices.next(); - } - } - if let Some(linebreak_index) = next_linebreak_index { - if *linebreak_index == i + 1 { - // pad line - if current_line.len() > 0 { - for _ in current_line.len()..self.display_cols as usize { - current_line.push_back(&EMPTY_TERMINAL_CHARACTER); - } - output.push_front(Vec::from(current_line.drain(..).collect::<Vec<&TerminalCharacter>>())); - } - next_linebreak_index = linebreak_indices.next(); - } - } - if output.len() == self.display_rows as usize { - if current_line.len() > 0 { - for _ in current_line.len()..self.display_cols as usize { - current_line.push_back(&EMPTY_TERMINAL_CHARACTER); - } - output.push_front(Vec::from(current_line.drain(..).collect::<Vec<&TerminalCharacter>>())); - } - break; - } - let terminal_character = self.characters.get(i).unwrap(); - current_line.push_front(terminal_character); - if i == 0 { - if current_line.len() > 0 { - for _ in current_line.len()..self.display_cols as usize { - current_line.push_back(&EMPTY_TERMINAL_CHARACTER); - } - output.push_front(Vec::from(current_line.drain(..).collect::<Vec<&TerminalCharacter>>())); - } - break; - } - } - if output.len() < self.display_rows as usize { - let mut empty_line = vec![]; - for _ in 0..self.display_cols { - empty_line.push(&EMPTY_TERMINAL_CHARACTER); - } - for _ in output.len()..self.display_rows as usize { - output.push_front(Vec::from(empty_line.clone())); - } - } - - Vec::from(output) - } - pub fn cursor_position_in_last_line (&self) -> usize { - if self.cursor_position <= self.characters.len() { - let start_of_last_line = self.index_of_beginning_of_last_line(); - if self.cursor_position < start_of_last_line { - // TODO: why does this happen? - return self.display_cols as usize - }; - let difference_from_last_newline = self.cursor_position - start_of_last_line; - difference_from_last_newline - } else { - self.display_cols as usize - } - } - pub fn cursor_coordinates (&self) -> (usize, usize) { // (x, y) - let mut lines_from_end = 0; - - let mut newline_indices = self.newline_indices.iter().rev(); - let mut linebreak_indices = self.linebreak_indices.iter().rev(); - - let mut next_newline_index = newline_indices.next().unwrap_or(&0); - let mut next_linebreak_index = linebreak_indices.next().unwrap_or(&0); - - let next_line_start = loop { - let next_line_start = ::std::cmp::max(*next_newline_index, *next_linebreak_index); - if self.cursor_position >= next_line_start { - break next_line_start; - } - if next_line_start == *next_newline_index { - next_newline_index = newline_indices.next().unwrap_or(&0); - lines_from_end += 1; - } - if next_line_start == *next_linebreak_index { - next_linebreak_index = linebreak_indices.next().unwrap_or(&0); - lines_from_end += 1; - } - }; - let y = self.display_rows - lines_from_end; // TODO: this might overflow, fix when introducing scrolling - let x = self.cursor_position - next_line_start; - (x, y as usize) - } - fn index_of_beginning_of_last_line (&self) -> usize { - let last_newline_index = if self.newline_indices.is_empty() { - None - } else { - // return last - Some(*self.newline_indices.last().unwrap()) - }; - let last_linebreak_index = if self.linebreak_indices.is_empty() { - None - } else { - // return last - Some(*self.linebreak_indices.last().unwrap()) - }; - match (last_newline_index, last_linebreak_index) { - (Some(last_newline_index), Some(last_linebreak_index)) => { - max(last_newline_index, last_linebreak_index) - }, - (None, Some(last_linebreak_index)) => last_linebreak_index, - (Some(last_newline_index), None) => last_newline_index, - (None, None) => 0 - } - } - fn index_of_beginning_of_last_canonical_line (&self) -> usize { - if self.newline_indices.is_empty() { - 0 - } else { - // return last - *self.newline_indices.last().unwrap() - } - } - fn index_of_beginning_of_line (&self, index_in_line: usize) -> usize { - let last_newline_index = if self.newline_indices.is_empty() { - None - } else { - // return last less than index_in_line - let last_newline_index = *self.newline_indices.last().unwrap(); - if last_newline_index <= index_in_line { - Some(last_newline_index) - } else { - let mut last_newline_index = 0; - for n_i in self.newline_indices.iter() { - if *n_i > last_newline_index && *n_i <= index_in_line { - last_newline_index = *n_i; - } else if *n_i > index_in_line { - break; - } - } - Some(last_newline_index) - } - }; - let last_linebreak_index = if self.linebreak_indices.is_empty() { - None - } else { - // return last less than index_in_line - let last_linebreak_index = *self.linebreak_indices.last().unwrap(); - if last_linebreak_index <= index_in_line { - Some(last_linebreak_index) - } else { - let mut last_linebreak_index = 0; - for l_i in self.linebreak_indices.iter() { - if *l_i > last_linebreak_index && *l_i <= index_in_line { - last_linebreak_index = *l_i; - } else if *l_i > index_in_line { - break; - } - } - Some(last_linebreak_index) - } - }; - match (last_newline_index, last_linebreak_index) { - (Some(last_newline_index), Some(last_linebreak_index)) => { - max(last_newline_index, last_linebreak_index) - }, - (None, Some(last_linebreak_index)) => last_linebreak_index, - (Some(last_newline_index), None) => last_newline_index, - (None, None) => 0 - } - } - fn add_newline (&mut self) { - self.newline_indices.push(self.characters.len()); - self.cursor_position = self.characters.len(); - self.should_render = true; - self.pending_ansi_code = None; - } - fn move_to_beginning_of_line (&mut self) { - let last_newline_index = if self.newline_indices.is_empty() { - 0 - } else { - *self.newline_indices.last().unwrap() - }; - self.cursor_position = last_newline_index; - self.should_render = true; - } -} - -const DEBUGGING: bool = false; - -impl vte::Perform for TerminalOutput { - fn print(&mut self, c: char) { - if DEBUGGING { - println!("\r[print] {:?}", c); - } else { - let mut terminal_character = TerminalCharacter::new(c); - terminal_character.ansi_code = self.pending_ansi_code.clone(); - if self.characters.len() == self.cursor_position { - self.characters.push(terminal_character); - - let start_of_last_line = self.index_of_beginning_of_line(self.cursor_position); - let difference_from_last_newline = self.cursor_position - start_of_last_line; - if difference_from_last_newline == self.display_cols as usize { - self.linebreak_indices.push(self.cursor_position); - } - - } else if self.characters.len() > self.cursor_position { - self.characters.remove(self.cursor_position); - self.characters.insert(self.cursor_position, terminal_character); - } else { - let mut space_character = TerminalCharacter::new(' '); - space_character.ansi_code = self.pending_ansi_code.clone(); - for _ in self.characters.len()..self.cursor_position { - self.characters.push(space_character.clone()); - }; - self.characters.push(terminal_character); - - let start_of_last_line = self.index_of_beginning_of_line(self.cursor_position); - let difference_from_last_newline = self.cursor_position - start_of_last_line; - if difference_from_last_newline == self.display_cols as usize { - self.linebreak_indices.push(self.cursor_position); - } - } - self.cursor_position += 1; - } - } - - fn execute(&mut self, byte: u8) { - if DEBUGGING { - if byte == 13 { // 0d, carriage return - println!("\rEXECUTE CARRIAGE RETURN"); - } else if byte == 10 { // 0a, newline - println!("\rEXECUTE NEW LINE"); - } else if byte == 08 { // backspace - println!("\rEXECUTE BACKSPACE"); - } else { - println!("\r[execute] {:02x}", byte); - } - } else { - if byte == 13 { // 0d, carriage return - self.move_to_beginning_of_line(); - } else if byte == 08 { // backspace - self.cursor_position -= 1; - } else if byte == 10 { // 0a, newline - self.add_newline(); - } - } - } - - fn hook(&mut self, params: &[i64], intermediates: &[u8], ignore: bool, c: char) { - if DEBUGGING { - println!( - "\r[hook] params={:?}, intermediates={:?}, ignore={:?}, char={:?}", - params, intermediates, ignore, c - ); - } - } - - fn put(&mut self, byte: u8) { - if DEBUGGING { - println!("\r[put] {:02x}", byte); - } - } - - fn unhook(&mut self) { - if DEBUGGING { - println!("\r[unhook]"); - } - } - - fn osc_dispatch(&mut self, params: &[&[u8]], bell_terminated: bool) { - // TODO: normalize vec/slices for all of these methods and the enum - if DEBUGGING { - println!("\r[osc_dispatch] params={:?} bell_terminated={}", params, bell_terminated); - } - } - - fn csi_dispatch(&mut self, params: &[i64], intermediates: &[u8], ignore: bool, c: char) { - if DEBUGGING { - println!( - "\r[csi_dispatch] params={:?}, intermediates={:?}, ignore={:?}, char={:?}", - params, intermediates, ignore, c - ); - } else { - if c == 'm' { - // change foreground color (only?) - if params.len() == 1 && params[0] == 0 { - // eg. \u{1b}[m - self.pending_ansi_code = Some(String::from("\u{1b}[m")); - } else { - // eg. \u{1b}[38;5;0m - let param_string = params.iter().map(|p| p.to_string()).collect::<Vec<String>>().join(";"); - self.pending_ansi_code = Some(format!("\u{1b}[{}m", param_string)); - } - } else if c == 'C' { // move cursor forward - self.cursor_position += params[0] as usize; // TODO: negative value? - } else if c == 'K' { // clear line (0 => right, 1 => left, 2 => all) - if params[0] == 0 { - if let Some(position_of_first_newline_index_to_delete) = self.newline_indices.iter().position(|&ni| ni > self.cursor_position) { - self.newline_indices.truncate(position_of_first_newline_index_to_delete); - } - if let Some(position_of_first_linebreak_index_to_delete) = self.linebreak_indices.iter().position(|&li| li > self.cursor_position) { - self.newline_indices.truncate(position_of_first_linebreak_index_to_delete); - } - self.characters.truncate(self.cursor_position + 1); - } - // TODO: implement 1 and 2 - } else if c == 'J' { // clear all (0 => below, 1 => above, 2 => all, 3 => saved) - if params[0] == 0 { - if let Some(position_of_first_newline_index_to_delete) = self.newline_indices.iter().position(|&ni| ni > self.cursor_position) { - self.newline_indices.truncate(position_of_first_newline_index_to_delete); - } - if let Some(position_of_first_linebreak_index_to_delete) = self.linebreak_indices.iter().position(|&li| li > self.cursor_position) { - self.newline_indices.truncate(position_of_first_linebreak_index_to_delete); - } - self.characters.truncate(self.cursor_position + 1); - } - // TODO: implement 1, 2, and 3 - } else if c == 'H' { // goto row/col - let row = params[0] as usize - 1; // we subtract 1 here because this csi is 1 indexed and we index from 0 - let col = params[1] as usize - 1; - - match self.newline_indices.get(row as usize) { - Some(index_of_next_row) => { - let index_of_row = index_of_next_row - self.display_cols as usize; - self.cursor_position = index_of_row + col as usize; - } - None => { - let start_of_last_line = self.index_of_beginning_of_last_canonical_line(); - let num_of_lines_to_add = row - self.newline_indices.len(); - for i in 0..num_of_lines_to_add { - self.newline_indices.push(start_of_last_line + ((i + 1) * self.display_cols as usize)); - } - let index_of_row = self.newline_indices.last().unwrap_or(&0); // TODO: better - self.cursor_position = index_of_row + col as usize; - } - } - } - } - } - - fn esc_dispatch(&mut self, intermediates: &[u8], ignore: bool, byte: u8) { - if DEBUGGING { - println!( - // "\r[esc_dispatch] intermediates={:?}, ignore={:?}, byte={:02x}", - "\r[esc_dispatch] intermediates={:?}, ignore={:?}, byte={:?}", - intermediates, ignore, byte - ); - } - } -} - -#[derive(Debug)] -pub enum VteEvent { // TODO: try not to allocate Vecs - Print(char), - Execute(u8), // byte - Hook(Vec<i64>, Vec<u8>, bool, char), // params, intermediates, ignore, char - Put(u8), // byte - Unhook, - OscDispatch(Vec<Vec<u8>>, bool), // params, bell_terminated - CsiDispatch(Vec<i64>, Vec<u8>, bool, char), // params, intermediates, ignore, char - EscDispatch(Vec<u8>, bool, u8), // intermediates, ignore, byte -} - -struct VteEventSender { - id: RawFd, - sender: Sender<ScreenInstruction>, -} - -impl VteEventSender { - pub fn new (id: RawFd, sender: Sender<ScreenInstruction>) -> Self { - VteEventSender { id, sender } - } -} - -impl vte::Perform for VteEventSender { - fn print(&mut self, c: char) { - self.sender.send( - ScreenInstruction::Pty(self.id, VteEvent::Print(c)) - ).unwrap(); - } - fn execute(&mut self, byte: u8) { - self.sender.send(ScreenInstruction::Pty(self.id, VteEvent::Execute(byte))).unwrap(); - } - - fn hook(&mut self, params: &[i64], intermediates: &[u8], ignore: bool, c: char) { - let params = params.iter().copied().collect(); - let intermediates = intermediates.iter().copied().collect(); - let instruction = ScreenInstruction::Pty(self.id, VteEvent::Hook(params, intermediates, ignore, c)); - self.sender.send(instruction).unwrap(); - } - - fn put(&mut self, byte: u8) { - self.sender.send(ScreenInstruction::Pty(self.id, VteEvent::Put(byte))).unwrap(); - } - - fn unhook(&mut self) { - self.sender.send(ScreenInstruction::Pty(self.id, VteEvent::Unhook)).unwrap(); - } - - fn osc_dispatch(&mut self, params: &[&[u8]], bell_terminated: bool) { - let params = params.iter().map(|p| p.to_vec()).collect(); - let instruction = ScreenInstruction::Pty(self.id, VteEvent::OscDispatch(params, bell_terminated)); - self.sender.send(instruction).unwrap(); - } - - fn csi_dispatch(&mut self, params: &[i64], intermediates: &[u8], ignore: bool, c: char) { - let params = params.iter().copied().collect(); - let intermediates = intermediates.iter().copied().collect(); - let instruction = ScreenInstruction::Pty(self.id, VteEvent::CsiDispatch(params, intermediates, ignore, c)); - self.sender.send(instruction).unwrap(); - } - - fn esc_dispatch(&mut self, intermediates: &[u8], ignore: bool, byte: u8) { - let intermediates = intermediates.iter().copied().collect(); - let instruction = ScreenInstruction::Pty(self.id, VteEvent::EscDispatch(intermediates, ignore, byte)); - self.sender.send(instruction).unwrap(); - } -} +use crate::terminal_pane::TerminalOutput; +use crate::pty_bus::{VteEvent, PtyBus, PtyInstruction}; +use crate::screen::{Screen, ScreenInstruction}; // sigwinch stuff use ::signal_hook::iterator::Signals; @@ -748,1398 +39,6 @@ pub fn sigwinch() -> (Box<OnSigWinch>, Box<SigCleanup>) { (Box::new(on_winch), Box::new(cleanup)) } -fn split_vertically_with_gap (rect: &Winsize) -> (Winsize, Winsize) { - let width_of_each_half = (rect.ws_col - 1) / 2; - let mut first_rect = rect.clone(); - let mut second_rect = rect.clone(); - if rect.ws_col % 2 == 0 { - first_rect.ws_col = width_of_each_half + 1; - } else { - first_rect.ws_col = width_of_each_half; - } - second_rect.ws_col = width_of_each_half; - (first_rect, second_rect) -} - -fn split_horizontally_with_gap (rect: &Winsize) -> (Winsize, Winsize) { - let height_of_each_half = (rect.ws_row - 1) / 2; - let mut first_rect = rect.clone(); - let mut second_rect = rect.clone(); - if rect.ws_row % 2 == 0 { - first_rect.ws_row = height_of_each_half + 1; - } else { - first_rect.ws_row = height_of_each_half; - } - second_rect.ws_row = height_of_each_half; - (first_rect, second_rect) -} - -#[derive(Debug)] -enum ScreenInstruction { - Pty(RawFd, VteEvent), - Render, - HorizontalSplit(RawFd), - VerticalSplit(RawFd), - WriteCharacter(u8), - ResizeLeft, - ResizeRight, - ResizeDown, - ResizeUp, - MoveFocus, - Quit, -} - -struct Screen { - pub receiver: Receiver<ScreenInstruction>, - pub send_screen_instructions: Sender<ScreenInstruction>, - full_screen_ws: Winsize, - vertical_separator: TerminalCharacter, // TODO: better - horizontal_separator: TerminalCharacter, // TODO: better - terminals: BTreeMap<RawFd, TerminalOutput>, // BTreeMap because we need a predictable order when changing focus - active_terminal: Option<RawFd>, - os_api: Box<dyn OsApi>, -} - -impl Screen { - pub fn new (full_screen_ws: &Winsize, os_api: Box<dyn OsApi>) -> Self { - let (sender, receiver): (Sender<ScreenInstruction>, Receiver<ScreenInstruction>) = channel(); - Screen { - receiver, - send_screen_instructions: sender, - full_screen_ws: full_screen_ws.clone(), - vertical_separator: TerminalCharacter::new('│').ansi_code(String::from("\u{1b}[m")), // TODO: better - horizontal_separator: TerminalCharacter::new('─').ansi_code(String::from("\u{1b}[m")), // TODO: better - terminals: BTreeMap::new(), - active_terminal: None, - os_api, - } - } - pub fn horizontal_split(&mut self, pid: RawFd) { - if self.terminals.is_empty() { - let x = 0; - let y = 0; - let new_terminal = TerminalOutput::new(pid, self.full_screen_ws.clone(), x, y); - self.os_api.set_terminal_size_using_fd(new_terminal.pid, new_terminal.display_cols, new_terminal.display_rows); - self.terminals.insert(pid, new_terminal); - self.active_terminal = Some(pid); - } else { - // TODO: check minimum size of active terminal - let (active_terminal_ws, active_terminal_x_coords, active_terminal_y_coords) = { - let active_terminal = &self.get_active_terminal().unwrap(); - ( - Winsize { - ws_row: active_terminal.display_rows, - ws_col: active_terminal.display_cols, - ws_xpixel: 0, - ws_ypixel: 0, - }, - active_terminal.x_coords, - active_terminal.y_coords - ) - }; - let (top_winsize, bottom_winsize) = split_horizontally_with_gap(&active_terminal_ws); - let bottom_half_y = active_terminal_y_coords + top_winsize.ws_row + 1; - let new_terminal = TerminalOutput::new(pid, bottom_winsize, active_terminal_x_coords, bottom_half_y); - self.os_api.set_terminal_size_using_fd(new_terminal.pid, bottom_winsize.ws_col, bottom_winsize.ws_row); - - { - let active_terminal_id = &self.get_active_terminal_id().unwrap(); - let active_terminal = &mut self.terminals.get_mut(&active_terminal_id).unwrap(); - active_terminal.change_size(&top_winsize); - } - - self.terminals.insert(pid, new_terminal); - let active_terminal_pid = self.get_active_terminal_id().unwrap(); - self.os_api.set_terminal_size_using_fd(active_terminal_pid, top_winsize.ws_col, top_winsize.ws_row); - self.active_terminal = Some(pid); - self.render(); - } - } - pub fn vertical_split(&mut self, pid: RawFd) { - if self.terminals.is_empty() { - let x = 0; - let y = 0; - let new_terminal = TerminalOutput::new(pid, self.full_screen_ws.clone(), x, y); - self.os_api.set_terminal_size_using_fd(new_terminal.pid, new_terminal.display_cols, new_terminal.display_rows); - self.terminals.insert(pid, new_terminal); - self.active_terminal = Some(pid); - } else { - // TODO: check minimum size of active terminal - let (active_terminal_ws, active_terminal_x_coords, active_terminal_y_coords) = { - let active_terminal = &self.get_active_terminal().unwrap(); - ( - Winsize { - ws_row: active_terminal.display_rows, - ws_col: active_terminal.display_cols, - ws_xpixel: 0, - ws_ypixel: 0, - }, - active_terminal.x_coords, - active_terminal.y_coords - ) - }; - let (left_winszie, right_winsize) = split_vertically_with_gap(&active_terminal_ws); - let right_side_x = active_terminal_x_coords + left_winszie.ws_col + 1; - let new_terminal = TerminalOutput::new(pid, right_winsize, right_side_x, active_terminal_y_coords); - self.os_api.set_terminal_size_using_fd(new_terminal.pid, right_winsize.ws_col, right_winsize.ws_row); - - { - let active_terminal_id = &self.get_active_terminal_id().unwrap(); - let active_terminal = &mut self.terminals.get_mut(&active_terminal_id).unwrap(); - active_terminal.change_size(&left_winszie); - } - - self.terminals.insert(pid, new_terminal); - let active_terminal_pid = self.get_active_terminal_id().unwrap(); - self.os_api.set_terminal_size_using_fd(active_terminal_pid, left_winszie.ws_col, left_winszie.ws_row); - self.active_terminal = Some(pid); - self.render(); - } - } - fn get_active_terminal (&self) -> Option<&TerminalOutput> { - match self.active_terminal { - Some(active_terminal) => self.terminals.get(&active_terminal), - None => None - } - } - fn get_active_terminal_id (&self) -> Option<RawFd> { - match self.active_terminal { - Some(active_terminal) => Some(self.terminals.get(&active_terminal).unwrap().pid), - None => None - } - } - pub fn handle_pty_event(&mut self, pid: RawFd, event: VteEvent) { - let terminal_output = self.terminals.get_mut(&pid).unwrap(); - terminal_output.handle_event(event); - } - pub fn write_to_active_terminal(&mut self, byte: u8) { - if let Some(active_terminal_id) = &self.get_active_terminal_id() { - let mut buffer = [byte]; - self.os_api.write_to_tty_stdin(*active_terminal_id, &mut buffer).expect("failed to write to terminal"); - self.os_api.tcdrain(*active_terminal_id).expect("failed to drain terminal"); - } - } - fn get_active_terminal_cursor_position(&self) -> (usize, usize) { // (x, y) - let active_terminal = &self.get_active_terminal().unwrap(); - let x = active_terminal.x_coords as usize + active_terminal.cursor_position_in_last_line(); - let y = active_terminal.y_coords + active_terminal.display_rows - 1; - (x, y as usize) - } - pub fn render (&mut self) { - let mut stdout = self.os_api.get_stdout_writer(); - for (_pid, terminal) in self.terminals.iter_mut() { - if let Some(vte_output) = terminal.buffer_as_vte_output() { - - // write boundaries - if terminal.x_coords + terminal.display_cols < self.full_screen_ws.ws_col { - let boundary_x_coords = terminal.x_coords + terminal.display_cols; - let mut vte_output_boundaries = String::new(); - for row in terminal.y_coords..terminal.y_coords + terminal.display_rows { - vte_output_boundaries.push_str(&format!("\u{1b}[{};{}H\u{1b}[m", row + 1, boundary_x_coords + 1)); // goto row/col - vte_output_boundaries.push_str(&self.vertical_separator.to_string()); - } - stdout.write_all(&vte_output_boundaries.as_bytes()).expect("cannot write to stdout"); - } - if terminal.y_coords + terminal.display_rows < self.full_screen_ws.ws_row { - let boundary_y_coords = terminal.y_coords + terminal.display_rows; - let mut vte_output_boundaries = String::new(); - for col in terminal.x_coords..terminal.x_coords + terminal.display_cols { - vte_output_boundaries.push_str(&format!("\u{1b}[{};{}H\u{1b}[m", boundary_y_coords + 1, col + 1)); // goto row/col - vte_output_boundaries.push_str(&self.horizontal_separator.to_string()); - } - stdout.write_all(&vte_output_boundaries.as_bytes()).expect("cannot write to stdout"); - } - - stdout.write_all(&vte_output.as_bytes()).expect("cannot write to stdout"); - } - } - let (cursor_position_x, cursor_position_y) = self.get_active_terminal_cursor_position(); - let goto_cursor_position = format!("\u{1b}[{};{}H\u{1b}[m", cursor_position_y + 1, cursor_position_x + 1); // goto row/col - stdout.write_all(&goto_cursor_position.as_bytes()).expect("cannot write to stdout"); - stdout.flush().expect("could not flush"); - } - fn terminal_ids_directly_left_of(&self, id: &RawFd) -> Option<Vec<RawFd>> { - let mut ids = vec![]; - let terminal_to_check = self.terminals.get(id).unwrap(); - if terminal_to_check.x_coords == 0 { - return None; - } - for (pid, terminal) in self.terminals.iter() { - if terminal.x_coords + terminal.display_cols == terminal_to_check.x_coords - 1 { - ids.push(*pid); - } - } - if ids.is_empty() { - None - } else { - Some(ids) - } - } - fn terminal_ids_directly_right_of(&self, id: &RawFd) -> Option<Vec<RawFd>> { - let mut ids = vec![]; - let terminal_to_check = self.terminals.get(id).unwrap(); - for (pid, terminal) in self.terminals.iter() { - if terminal.x_coords == terminal_to_check.x_coords + terminal_to_check.display_cols + 1 { - ids.push(*pid); - } - } - if ids.is_empty() { - None - } else { - Some(ids) - } - } - fn terminal_ids_directly_below(&self, id: &RawFd) -> Option<Vec<RawFd>> { - let mut ids = vec![]; - let terminal_to_check = self.terminals.get(id).unwrap(); - for (pid, terminal) in self.terminals.iter() { - if terminal.y_coords == terminal_to_check.y_coords + terminal_to_check.display_rows + 1 { - ids.push(*pid); - } - } - if ids.is_empty() { - None - } else { - Some(ids) - } - } - fn terminal_ids_directly_above(&self, id: &RawFd) -> Option<Vec<RawFd>> { - let mut ids = vec![]; - let terminal_to_check = self.terminals.get(id).unwrap(); - for (pid, terminal) in self.terminals.iter() { - if terminal.y_coords + terminal.display_rows + 1 == terminal_to_check.y_coords { - ids.push(*pid); - } - } - if ids.is_empty() { - None - } else { - Some(ids) - } - } - fn terminal_ids_directly_above_with_same_left_alignment(&self, id: &RawFd) -> Option<Vec<RawFd>> { - let mut ids = vec![]; - let terminal_to_check = self.terminals.get(id).unwrap(); - let mut left_aligned_terminals: Vec<&TerminalOutput> = self.terminals - .keys() - .map(|t_id| self.terminals.get(&t_id).unwrap()) - .filter(|terminal| terminal.pid != *id && terminal.x_coords == terminal_to_check.x_coords) - .collect(); - left_aligned_terminals.sort_by(|a, b| { b.y_coords.cmp(&a.y_coords)}); - - for terminal in left_aligned_terminals { - let terminal_to_check = ids - .last() - .and_then(|id| self.terminals.get(id)) - .unwrap_or(terminal_to_check); - if terminal.y_coords + terminal.display_rows + 1 == terminal_to_check.y_coords { - ids.push(terminal.pid); - } - } - if ids.is_empty() { - None - } else { - Some(ids) - } - } - fn terminal_ids_directly_below_with_same_left_alignment(&self, id: &RawFd) -> Option<Vec<RawFd>> { - let mut ids = vec![]; - let terminal_to_check = self.terminals.get(id).unwrap(); - let mut left_aligned_terminals: Vec<&TerminalOutput> = self.terminals - .keys() - .map(|t_id| self.terminals.get(&t_id).unwrap()) - .filter(|terminal| terminal.pid != *id && terminal.x_coords == terminal_to_check.x_coords) - .collect(); - left_aligned_terminals.sort_by(|a, b| { a.y_coords.cmp(&b.y_coords)}); - - for terminal in left_aligned_terminals { - let terminal_to_check = ids - .last() - .and_then(|id| self.terminals.get(id)) - .unwrap_or(terminal_to_check); - if terminal_to_check.y_coords + terminal_to_check.display_rows + 1 == terminal.y_coords { - ids.push(terminal.pid); - } - } - if ids.is_empty() { - None - } else { - Some(ids) - } - } - fn terminal_ids_directly_above_with_same_right_alignment(&self, id: &RawFd) -> Option<Vec<RawFd>> { - let mut ids = vec![]; - let terminal_to_check = self.terminals.get(id).unwrap(); - let mut right_aligned_terminals: Vec<&TerminalOutput> = self.terminals - .keys() - .map(|t_id| self.terminals.get(&t_id).unwrap()) - .filter(|terminal| terminal.pid != *id && terminal.x_coords + terminal.display_cols == terminal_to_check.x_coords + terminal_to_check.display_cols) - .collect(); - right_aligned_terminals.sort_by(|a, b| { b.y_coords.cmp(&a.y_coords)}); - - for terminal in right_aligned_terminals { - let terminal_to_check = ids - .last() - .and_then(|id| self.terminals.get(id)) - .unwrap_or(terminal_to_check); - if terminal.y_coords + terminal.display_rows + 1 == terminal_to_check.y_coords { - ids.push(terminal.pid); - } - } - if ids.is_empty() { - None - } else { - Some(ids) - } - } - fn terminal_ids_directly_below_with_same_right_alignment(&self, id: &RawFd) -> Option<Vec<RawFd>> { - let mut ids = vec![]; - let terminal_to_check = self.terminals.get(id).unwrap(); - let mut right_aligned_terminals: Vec<&TerminalOutput> = self.terminals - .keys() - .map(|t_id| self.terminals.get(&t_id).unwrap()) - .filter(|terminal| terminal.pid != *id && terminal.x_coords + terminal.display_cols == terminal_to_check.x_coords + terminal_to_check.display_cols) - .collect(); - right_aligned_terminals.sort_by(|a, b| { a.y_coords.cmp(&b.y_coords)}); - - for terminal in right_aligned_terminals { - let terminal_to_check = ids - .last() - .and_then(|id| self.terminals.get(id)) - .unwrap_or(terminal_to_check); - if terminal_to_check.y_coords + terminal_to_check.display_rows + 1 == terminal.y_coords { - ids.push(terminal.pid); - } - } - if ids.is_empty() { - None - } else { - Some(ids) - } - } - fn terminal_ids_directly_to_the_left_with_same_top_alignment(&self, id: &RawFd) -> Option<Vec<RawFd>> { - let mut ids = vec![]; - let terminal_to_check = self.terminals.get(id).unwrap(); - let mut top_aligned_terminals: Vec<&TerminalOutput> = self.terminals - .keys() - .map(|t_id| self.terminals.get(&t_id).unwrap()) - .filter(|terminal| terminal.pid != *id && terminal.y_coords == terminal_to_check.y_coords) - .collect(); - top_aligned_terminals.sort_by(|a, b| { b.x_coords.cmp(&a.x_coords)}); - - for terminal in top_aligned_terminals { - let terminal_to_check = ids - .last() - .and_then(|id| self.terminals.get(id)) - .unwrap_or(terminal_to_check); - if terminal.x_coords + terminal.display_cols + 1 == terminal_to_check.x_coords { - ids.push(terminal.pid); - } - } - if ids.is_empty() { - None - } else { - Some(ids) - } - } - fn terminal_ids_directly_to_the_left_with_same_bottom_alignment(&self, id: &RawFd) -> Option<Vec<RawFd>> { - let mut ids = vec![]; - let terminal_to_check = self.terminals.get(id).unwrap(); - let mut bottom_aligned_terminals: Vec<&TerminalOutput> = self.terminals - .keys() - .map(|t_id| self.terminals.get(&t_id).unwrap()) - .filter(|terminal| terminal.pid != *id && terminal.y_coords + terminal.display_rows == terminal_to_check.y_coords + terminal_to_check.display_rows) - .collect(); - bottom_aligned_terminals.sort_by(|a, b| { b.x_coords.cmp(&a.x_coords)}); - - for terminal in bottom_aligned_terminals { - let terminal_to_check = ids - .last() - .and_then(|id| self.terminals.get(id)) - .unwrap_or(terminal_to_check); - if terminal.x_coords + terminal.display_cols + 1 == terminal_to_check.x_coords { - ids.push(terminal.pid); - } - } - if ids.is_empty() { - None - } else { - Some(ids) - } - } - fn terminal_ids_directly_to_the_right_with_same_top_alignment(&self, id: &RawFd) -> Option<Vec<RawFd>> { - let mut ids = vec![]; - let terminal_to_check = self.terminals.get(id).unwrap(); - let mut top_aligned_terminals: Vec<&TerminalOutput> = self.terminals - .keys() - .map(|t_id| self.terminals.get(&t_id).unwrap()) - .filter(|terminal| terminal.pid != *id && terminal.y_coords == terminal_to_check.y_coords) - .collect(); - top_aligned_terminals.sort_by(|a, b| { a.x_coords.cmp(&b.x_coords)}); - - for terminal in top_aligned_terminals { - let terminal_to_check = ids - .last() - .and_then(|id| self.terminals.get(id)) - .unwrap_or(terminal_to_check); - if terminal_to_check.x_coords + terminal_to_check.display_cols + 1 == terminal.x_coords { - ids.push(terminal.pid); - } - } - if ids.is_empty() { - None - } else { - Some(ids) - } - } - fn terminal_ids_directly_to_the_right_with_same_bottom_alignment(&self, id: &RawFd) -> Option<Vec<RawFd>> { - let mut ids = vec![]; - let terminal_to_check = self.terminals.get(id).unwrap(); - let mut bottom_aligned_terminals: Vec<&TerminalOutput> = self.terminals - .keys() - .map(|t_id| self.terminals.get(&t_id).unwrap()) - .filter(|terminal| terminal.pid != *id && terminal.y_coords + terminal.display_rows == terminal_to_check.y_coords + terminal_to_check.display_rows) - .collect(); - bottom_aligned_terminals.sort_by(|a, b| { a.x_coords.cmp(&b.x_coords)}); - - for terminal in bottom_aligned_terminals { - let terminal_to_check = ids - .last() - .and_then(|id| self.terminals.get(id)) - .unwrap_or(terminal_to_check); - if terminal_to_check.x_coords + terminal_to_check.display_cols + 1 == terminal.x_coords { - ids.push(terminal.pid); - } - } - if ids.is_empty() { - None - } else { - Some(ids) - } - } - pub fn resize_left (&mut self) { - // TODO: find out by how much we actually reduced and only reduce by that much - let count = 10; - if let Some(active_terminal_id) = self.get_active_terminal_id() { - let terminals_to_the_left = self.terminal_ids_directly_left_of(&active_terminal_id); - let terminals_to_the_right = self.terminal_ids_directly_right_of(&active_terminal_id); - match (terminals_to_the_left, terminals_to_the_right) { - (_, Some(mut terminals_to_the_right)) => { - // reduce to the left - let terminal_borders_to_the_right: HashSet<u16> = terminals_to_the_right.iter().map(|t| self.terminals.get(t).unwrap().y_coords).collect(); - let terminals_above_and_upper_resize_border = self.terminal_ids_directly_above_with_same_right_alignment(&active_terminal_id) - .and_then(|t| { - let terminals: Vec<&TerminalOutput> = t.iter().map(|t| self.terminals.get(t).unwrap()).collect(); - Some(terminals) - }) - .and_then(|mut t| { - let mut upper_resize_border = 0; - for terminal in &t { - let lower_terminal_boundary = terminal.y_coords + terminal.display_rows; - if terminal_borders_to_the_right.get(&(lower_terminal_boundary + 1)).is_some() && upper_resize_border < lower_terminal_boundary { - upper_resize_border = lower_terminal_boundary + 1; - } - } - t.retain(|terminal| { - terminal.y_coords >= upper_resize_border - }); - let terminal_ids: Vec<RawFd> = t.iter().map(|t| t.pid).collect(); - Some((terminal_ids, upper_resize_border)) - }); - let terminals_below_and_lower_resize_border = self.terminal_ids_directly_below_with_same_right_alignment(&active_terminal_id) - .and_then(|t| { - let terminals: Vec<&TerminalOutput> = t.iter().map(|t| self.terminals.get(t).unwrap()).collect(); - Some(terminals) - }) - .and_then(|mut t| { - let mut lower_resize_border = self.full_screen_ws.ws_row; - for terminal in &t { - let upper_terminal_boundary = terminal.y_coords; - if terminal_borders_to_the_right.get(&upper_terminal_boundary).is_some() && lower_resize_border > upper_terminal_boundary { - lower_resize_border = upper_terminal_boundary; - } - } - t.retain(|terminal| { - terminal.y_coords + terminal.display_rows <= lower_resize_border - }); - let terminal_ids: Vec<RawFd> = t.iter().map(|t| t.pid).collect(); - Some((terminal_ids, lower_resize_border)) - }); - let (terminals_above, upper_resize_border) = match terminals_above_and_upper_resize_border { - Some((terminals_above, upper_resize_border)) => (Some(terminals_above), Some(upper_resize_border)), - None => (None, None), - }; - let (terminals_below, lower_resize_border) = match terminals_below_and_lower_resize_border { - Some((terminals_below, lower_resize_border)) => (Some(terminals_below), Some(lower_resize_border)), - None => (None, None), - }; - let active_terminal = self.terminals.get_mut(&active_terminal_id).unwrap(); - let upper_resize_border = upper_resize_border.unwrap_or(active_terminal.y_coords); - let lower_resize_border = lower_resize_border.unwrap_or(active_terminal.y_coords + active_terminal.display_rows); - - active_terminal.reduce_width_left(count); - self.os_api.set_terminal_size_using_fd( - active_terminal.pid, - active_terminal.display_cols, - active_terminal.display_rows - ); - - terminals_to_the_right.retain(|t| { - let terminal = self.terminals.get(t).unwrap(); - terminal.y_coords >= upper_resize_border && terminal.y_coords + terminal.display_rows <= lower_resize_border - }); - for terminal_id in terminals_to_the_right { - let terminal = self.terminals.get_mut(&terminal_id).unwrap(); - terminal.increase_width_left(count); - self.os_api.set_terminal_size_using_fd( - terminal.pid, - terminal.display_cols, - terminal.display_rows - ); - } - - if let Some(terminals_above) = terminals_above { - for terminal_id in terminals_above.iter() { - let terminal = self.terminals.get_mut(terminal_id).unwrap(); - terminal.reduce_width_left(count); - self.os_api.set_terminal_size_using_fd( - terminal.pid, - terminal.display_cols, - terminal.display_rows - ); - } - } - - if let Some(terminals_below) = terminals_below { - for terminal_id in terminals_below.iter() { - let terminal = self.terminals.get_mut(terminal_id).unwrap(); - terminal.reduce_width_left(count); - self.os_api.set_terminal_size_using_fd( - terminal.pid, - terminal.display_cols, - terminal.display_rows - ); - } - } - }, - (Some(mut terminals_to_the_left), None) => { - // increase to the left - let terminal_borders_to_the_left: HashSet<u16> = terminals_to_the_left.iter().map(|t| self.terminals.get(t).unwrap().y_coords).collect(); - let terminals_above_and_upper_resize_border = self.terminal_ids_directly_above_with_same_left_alignment(&active_terminal_id) - .and_then(|t| { - let terminals: Vec<&TerminalOutput> = t.iter().map(|t| self.terminals.get(t).unwrap()).collect(); - Some(terminals) - }) - .and_then(|mut t| { - let mut upper_resize_border = 0; - for terminal in &t { - let lower_terminal_boundary = terminal.y_coords + terminal.display_rows; - if terminal_borders_to_the_left.get(&(lower_terminal_boundary + 1)).is_some() && upper_resize_border < lower_terminal_boundary { - upper_resize_border = lower_terminal_boundary + 1; - } - } - t.retain(|terminal| { - terminal.y_coords >= upper_resize_border - }); - let terminal_ids: Vec<RawFd> = t.iter().map(|t| t.pid).collect(); - Some((terminal_ids, upper_resize_border)) - }); - let terminals_below_and_lower_resize_border = self.terminal_ids_directly_below_with_same_left_alignment(&active_terminal_id) - .and_then(|t| { - let terminals: Vec<&TerminalOutput> = t.iter().map(|t| self.terminals.get(t).unwrap()).collect(); - Some(terminals) - }) - .and_then(|mut t| { - let mut lower_resize_border = self.full_screen_ws.ws_row; - for terminal in &t { - let upper_terminal_boundary = terminal.y_coords; - if terminal_borders_to_the_left.get(&upper_terminal_boundary).is_some() && lower_resize_border > upper_terminal_boundary { - lower_resize_border = upper_terminal_boundary; - } - } - t.retain(|terminal| { - terminal.y_coords + terminal.display_rows <= lower_resize_border - }); - let terminal_ids: Vec<RawFd> = t.iter().map(|t| t.pid).collect(); - Some((terminal_ids, lower_resize_border)) - }); - let (terminals_above, upper_resize_border) = match terminals_above_and_upper_resize_border { - Some((terminals_above, upper_resize_border)) => (Some(terminals_above), Some(upper_resize_border)), - None => (None, None), - }; - let (terminals_below, lower_resize_border) = match terminals_below_and_lower_resize_border { - Some((terminals_below, lower_resize_border)) => (Some(terminals_below), Some(lower_resize_border)), - None => (None, None), - }; - let active_terminal = self.terminals.get_mut(&active_terminal_id).unwrap(); - let upper_resize_border = upper_resize_border.unwrap_or(active_terminal.y_coords); - let lower_resize_border = lower_resize_border.unwrap_or(active_terminal.y_coords + active_terminal.display_rows); - - active_terminal.increase_width_left(count); - self.os_api.set_terminal_size_using_fd( - active_terminal.pid, - active_terminal.display_cols, - active_terminal.display_rows - ); - - terminals_to_the_left.retain(|t| { - let terminal = self.terminals.get(t).unwrap(); - terminal.y_coords >= upper_resize_border && terminal.y_coords + terminal.display_rows <= lower_resize_border - }); - for terminal_id in terminals_to_the_left { - let terminal = self.terminals.get_mut(&terminal_id).unwrap(); - terminal.reduce_width_left(count); - self.os_api.set_terminal_size_using_fd( - terminal.pid, - terminal.display_cols, - terminal.display_rows - ); - } - - if let Some(terminals_above) = terminals_above { - for terminal_id in terminals_above.iter() { - let terminal = self.terminals.get_mut(terminal_id).unwrap(); - terminal.increase_width_left(count); - self.os_api.set_terminal_size_using_fd( - terminal.pid, - terminal.display_cols, - terminal.display_rows - ); - } - } - - if let Some(terminals_below) = terminals_below { - for terminal_id in terminals_below.iter() { - let terminal = self.terminals.get_mut(terminal_id).unwrap(); - terminal.increase_width_left(count); - self.os_api.set_terminal_size_using_fd( - terminal.pid, - terminal.display_cols, - terminal.display_rows - ); - } - } - }, - (None, None) => {} - } - self.render(); - } - } - pub fn resize_right (&mut self) { - let count = 10; - if let Some(active_terminal_id) = self.get_active_terminal_id() { - let terminals_to_the_left = self.terminal_ids_directly_left_of(&active_terminal_id); - let terminals_to_the_right = self.terminal_ids_directly_right_of(&active_terminal_id); - match (terminals_to_the_left, terminals_to_the_right) { - (_, Some(mut terminals_to_the_right)) => { - // increase to the right - let terminal_borders_to_the_right: HashSet<u16> = terminals_to_the_right.iter().map(|t| self.terminals.get(t).unwrap().y_coords).collect(); - let terminals_above_and_upper_resize_border = self.terminal_ids_directly_above_with_same_right_alignment(&active_terminal_id) - .and_then(|t| { - let terminals: Vec<&TerminalOutput> = t.iter().map(|t| self.terminals.get(t).unwrap()).collect(); - Some(terminals) - }) - .and_then(|mut t| { - let mut upper_resize_border = 0; - for terminal in &t { - let lower_terminal_boundary = terminal.y_coords + terminal.display_rows; - if terminal_borders_to_the_right.get(&(lower_terminal_boundary + 1)).is_some() && upper_resize_border < lower_terminal_boundary { - upper_resize_border = lower_terminal_boundary + 1; - } - } - t.retain(|terminal| { - terminal.y_coords >= upper_resize_border - }); - let terminal_ids: Vec<RawFd> = t.iter().map(|t| t.pid).collect(); - Some((terminal_ids, upper_resize_border)) - }); - let terminals_below_and_lower_resize_border = self.terminal_ids_directly_below_with_same_right_alignment(&active_terminal_id) - .and_then(|t| { - let terminals: Vec<&TerminalOutput> = t.iter().map(|t| self.terminals.get(t).unwrap()).collect(); - Some(terminals) - }) - .and_then(|mut t| { - let mut lower_resize_border = self.full_screen_ws.ws_row; - for terminal in &t { - let upper_terminal_boundary = terminal.y_coords; - if terminal_borders_to_the_right.get(&upper_terminal_boundary).is_some() && lower_resize_border > upper_terminal_boundary { - lower_resize_border = upper_terminal_boundary; - } - } - t.retain(|terminal| { - terminal.y_coords + terminal.display_rows <= lower_resize_border - }); - let terminal_ids: Vec<RawFd> = t.iter().map(|t| t.pid).collect(); - Some((terminal_ids, lower_resize_border)) - }); - let (terminals_above, upper_resize_border) = match terminals_above_and_upper_resize_border { - Some((terminals_above, upper_resize_border)) => (Some(terminals_above), Some(upper_resize_border)), - None => (None, None), - }; - let (terminals_below, lower_resize_border) = match terminals_below_and_lower_resize_border { - Some((terminals_below, lower_resize_border)) => (Some(terminals_below), Some(lower_resize_border)), - None => (None, None), - }; - - let active_terminal = self.terminals.get_mut(&active_terminal_id).unwrap(); - let upper_resize_border = upper_resize_border.unwrap_or(active_terminal.y_coords); - let lower_resize_border = lower_resize_border.unwrap_or(active_terminal.y_coords + active_terminal.display_rows); - - active_terminal.increase_width_right(count); - self.os_api.set_terminal_size_using_fd( - active_terminal.pid, - active_terminal.display_cols, - active_terminal.display_rows - ); - - terminals_to_the_right.retain(|t| { - let terminal = self.terminals.get(t).unwrap(); - terminal.y_coords >= upper_resize_border && terminal.y_coords + terminal.display_rows <= lower_resize_border - }); - for terminal_id in terminals_to_the_right { - let terminal = self.terminals.get_mut(&terminal_id).unwrap(); - terminal.reduce_width_right(count); - self.os_api.set_terminal_size_using_fd( - terminal.pid, - terminal.display_cols, - terminal.display_rows - ); - } - - if let Some(terminals_above) = terminals_above { - for terminal_id in terminals_above.iter() { - let terminal = self.terminals.get_mut(terminal_id).unwrap(); - terminal.increase_width_right(count); - self.os_api.set_terminal_size_using_fd( - terminal.pid, - terminal.display_cols, - terminal.display_rows - ); - } - } - - if let Some(terminals_below) = terminals_below { - for terminal_id in terminals_below.iter() { - let terminal = self.terminals.get_mut(terminal_id).unwrap(); - terminal.increase_width_right(count); - self.os_api.set_terminal_size_using_fd( - terminal.pid, - terminal.display_cols, - terminal.display_rows - ); - } - } - }, - (Some(mut terminals_to_the_left), None) => { - // reduce to the right - let terminal_borders_to_the_left: HashSet<u16> = terminals_to_the_left.iter().map(|t| self.terminals.get(t).unwrap().y_coords).collect(); - let terminals_above_and_upper_resize_border = self.terminal_ids_directly_above_with_same_left_alignment(&active_terminal_id) - .and_then(|t| { - let terminals: Vec<&TerminalOutput> = t.iter().map(|t| self.terminals.get(t).unwrap()).collect(); - Some(terminals) - }) - .and_then(|mut t| { - let mut upper_resize_border = 0; - for terminal in &t { - let lower_terminal_boundary = terminal.y_coords + terminal.display_rows; - if terminal_borders_to_the_left.get(&(lower_terminal_boundary + 1)).is_some() && upper_resize_border < lower_terminal_boundary { - upper_resize_border = lower_terminal_boundary + 1; - } - } - t.retain(|terminal| { - terminal.y_coords >= upper_resize_border - }); - let terminal_ids: Vec<RawFd> = t.iter().map(|t| t.pid).collect(); - Some((terminal_ids, upper_resize_border)) - }); - let terminals_below_and_lower_resize_border = self.terminal_ids_directly_below_with_same_left_alignment(&active_terminal_id) - .and_then(|t| { - let terminals: Vec<&TerminalOutput> = t.iter().map(|t| self.terminals.get(t).unwrap()).collect(); - Some(terminals) - }) - .and_then(|mut t| { - let mut lower_resize_border = self.full_screen_ws.ws_row; - for terminal in &t { - let upper_terminal_boundary = terminal.y_coords; - if terminal_borders_to_the_left.get(&upper_terminal_boundary).is_some() && lower_resize_border > upper_terminal_boundary { - lower_resize_border = upper_terminal_boundary; - } - } - t.retain(|terminal| { - terminal.y_coords + terminal.display_rows <= lower_resize_border - }); - let terminal_ids: Vec<RawFd> = t.iter().map(|t| t.pid).collect(); - Some((terminal_ids, lower_resize_border)) - }); - let (terminals_above, upper_resize_border) = match terminals_above_and_upper_resize_border { - Some((terminals_above, upper_resize_border)) => (Some(terminals_above), Some(upper_resize_border)), - None => (None, None), - }; - let (terminals_below, lower_resize_border) = match terminals_below_and_lower_resize_border { - Some((terminals_below, lower_resize_border)) => (Some(terminals_below), Some(lower_resize_border)), - None => (None, None), - }; - - let active_terminal = self.terminals.get_mut(&active_terminal_id).unwrap(); - let upper_resize_border = upper_resize_border.unwrap_or(active_terminal.y_coords); - let lower_resize_border = lower_resize_border.unwrap_or(active_terminal.y_coords + active_terminal.display_rows); - - active_terminal.reduce_width_right(count); - self.os_api.set_terminal_size_using_fd( - active_terminal.pid, - active_terminal.display_cols, - active_terminal.display_rows - ); - - terminals_to_the_left.retain(|t| { - let terminal = self.terminals.get(t).unwrap(); - terminal.y_coords >= upper_resize_border && terminal.y_coords + terminal.display_rows <= lower_resize_border - }); - for terminal_id in terminals_to_the_left { - let terminal = self.terminals.get_mut(&terminal_id).unwrap(); - terminal.increase_width_right(count); - self.os_api.set_terminal_size_using_fd( - terminal.pid, - terminal.display_cols, - terminal.display_rows - ); - } - - if let Some(terminals_above) = terminals_above { - for terminal_id in terminals_above.iter() { - let terminal = self.terminals.get_mut(terminal_id).unwrap(); - terminal.reduce_width_right(count); - self.os_api.set_terminal_size_using_fd( - terminal.pid, - terminal.display_cols, - terminal.display_rows - ); - } - } - - if let Some(terminals_below) = terminals_below { - for terminal_id in terminals_below.iter() { - let terminal = self.terminals.get_mut(terminal_id).unwrap(); - terminal.reduce_width_right(count); - self.os_api.set_terminal_size_using_fd( - terminal.pid, - terminal.display_cols, - terminal.display_rows - ); - } - } - }, - (None, None) => {} - } - self.render(); - } - } - pub fn resize_down (&mut self) { - // TODO: find out by how much we actually reduced and only reduce by that much - let count = 2; - if let Some(active_terminal_id) = self.get_active_terminal_id() { - let terminals_below = self.terminal_ids_directly_below(&active_terminal_id); - let terminals_above = self.terminal_ids_directly_above(&active_terminal_id); - match (terminals_below, terminals_above) { - (_, Some(mut terminals_above)) => { - // reduce down - let terminal_borders_above: HashSet<u16> = terminals_above.iter().map(|t| self.terminals.get(t).unwrap().x_coords).collect(); - let terminals_to_the_left_and_left_resize_border = self.terminal_ids_directly_to_the_left_with_same_top_alignment(&active_terminal_id) - .and_then(|t| { - let terminals: Vec<&TerminalOutput> = t.iter().map(|t| self.terminals.get(t).unwrap()).collect(); - Some(terminals) - }) - .and_then(|mut t| { - let mut left_resize_border = 0; - for terminal in &t { - let right_terminal_boundary = terminal.x_coords + terminal.display_cols; - if terminal_borders_above.get(&(right_terminal_boundary + 1)).is_some() && left_resize_border < right_terminal_boundary { - left_resize_border = right_terminal_boundary + 1; - } - } - t.retain(|terminal| { - terminal.x_coords >= left_resize_border - }); - let terminal_ids: Vec<RawFd> = t.iter().map(|t| t.pid).collect(); - Some((terminal_ids, left_resize_border)) - }); - let terminals_to_the_right_and_right_resize_border = self.terminal_ids_directly_to_the_right_with_same_top_alignment(&active_terminal_id) - .and_then(|t| { - let terminals: Vec<&TerminalOutput> = t.iter().map(|t| self.terminals.get(t).unwrap()).collect(); - Some(terminals) - }) - .and_then(|mut t| { - let mut right_resize_border = self.full_screen_ws.ws_col; - for terminal in &t { - let left_terminal_boundary = terminal.x_coords; - if terminal_borders_above.get(&left_terminal_boundary).is_some() && right_resize_border > left_terminal_boundary { - right_resize_border = left_terminal_boundary; - } - } - t.retain(|terminal| { - terminal.x_coords + terminal.display_cols <= right_resize_border - }); - let terminal_ids: Vec<RawFd> = t.iter().map(|t| t.pid).collect(); - Some((terminal_ids, right_resize_border)) - }); - let (terminals_to_the_left, left_resize_border) = match terminals_to_the_left_and_left_resize_border { - Some((terminals_to_the_left, left_resize_border)) => (Some(terminals_to_the_left), Some(left_resize_border)), - None => (None, None), - }; - let (terminals_to_the_right, right_resize_border) = match terminals_to_the_right_and_right_resize_border { - Some((terminals_to_the_right, right_resize_border)) => (Some(terminals_to_the_right), Some(right_resize_border)), - None => (None, None), - }; - let active_terminal = self.terminals.get_mut(&active_terminal_id).unwrap(); - let left_resize_border = left_resize_border.unwrap_or(active_terminal.x_coords); - let right_resize_border = right_resize_border.unwrap_or(active_terminal.x_coords + active_terminal.display_cols); - - active_terminal.reduce_height_down(count); - self.os_api.set_terminal_size_using_fd( - active_terminal.pid, - active_terminal.display_cols, - active_terminal.display_rows - ); - - terminals_above.retain(|t| { - let terminal = self.terminals.get(t).unwrap(); - terminal.x_coords >= left_resize_border && terminal.x_coords + terminal.display_cols <= right_resize_border - }); - for terminal_id in terminals_above { - let terminal = self.terminals.get_mut(&terminal_id).unwrap(); - terminal.increase_height_down(count); - self.os_api.set_terminal_size_using_fd( - terminal.pid, - terminal.display_cols, - terminal.display_rows - ); - } - - if let Some(terminals_to_the_left) = terminals_to_the_left { - for terminal_id in terminals_to_the_left.iter() { - let terminal = self.terminals.get_mut(terminal_id).unwrap(); - terminal.reduce_height_down(count); - self.os_api.set_terminal_size_using_fd( - terminal.pid, - terminal.display_cols, - terminal.display_rows - ); - } - } - - if let Some(terminals_to_the_right) = terminals_to_the_right { - for terminal_id in terminals_to_the_right.iter() { - let terminal = self.terminals.get_mut(terminal_id).unwrap(); - terminal.reduce_height_down(count); - self.os_api.set_terminal_size_using_fd( - terminal.pid, - terminal.display_cols, - terminal.display_rows - ); - } - } - }, - (Some(mut terminals_below), None) => { - // increase down - let terminal_borders_below: HashSet<u16> = terminals_below.iter().map(|t| self.terminals.get(t).unwrap().x_coords).collect(); - let terminals_to_the_left_and_left_resize_border = self.terminal_ids_directly_to_the_left_with_same_bottom_alignment(&active_terminal_id) - .and_then(|t| { - let terminals: Vec<&TerminalOutput> = t.iter().map(|t| self.terminals.get(t).unwrap()).collect(); - Some(terminals) - }) - .and_then(|mut t| { - let mut left_resize_border = 0; - for terminal in &t { - let right_terminal_boundary = terminal.x_coords + terminal.display_cols; - if terminal_borders_below.get(&(right_terminal_boundary + 1)).is_some() && left_resize_border < right_terminal_boundary { - left_resize_border = right_terminal_boundary + 1; - } - } - t.retain(|terminal| { - terminal.x_coords >= left_resize_border - }); - let terminal_ids: Vec<RawFd> = t.iter().map(|t| t.pid).collect(); - Some((terminal_ids, left_resize_border)) - }); - let terminals_to_the_right_and_right_resize_border = self.terminal_ids_directly_to_the_right_with_same_bottom_alignment(&active_terminal_id) - .and_then(|t| { - let terminals: Vec<&TerminalOutput> = t.iter().map(|t| self.terminals.get(t).unwrap()).collect(); - Some(terminals) - }) - .and_then(|mut t| { - let mut right_resize_border = self.full_screen_ws.ws_col; - for terminal in &t { - let left_terminal_boundary = terminal.x_coords; - if terminal_borders_below.get(&left_terminal_boundary).is_some() && right_resize_border > left_terminal_boundary { - right_resize_border = left_terminal_boundary; - } - } - t.retain(|terminal| { - terminal.x_coords + terminal.display_cols <= right_resize_border - }); - let terminal_ids: Vec<RawFd> = t.iter().map(|t| t.pid).collect(); - Some((terminal_ids, right_resize_border)) - }); - let (terminals_to_the_left, left_resize_border) = match terminals_to_the_left_and_left_resize_border { - Some((terminals_to_the_left, left_resize_border)) => (Some(terminals_to_the_left), Some(left_resize_border)), - None => (None, None), - }; - let (terminals_to_the_right, right_resize_border) = match terminals_to_the_right_and_right_resize_border { - Some((terminals_to_the_right, right_resize_border)) => (Some(terminals_to_the_right), Some(right_resize_border)), - None => (None, None), - }; - let active_terminal = self.terminals.get_mut(&active_terminal_id).unwrap(); - let left_resize_border = left_resize_border.unwrap_or(active_terminal.x_coords); - let right_resize_border = right_resize_border.unwrap_or(active_terminal.x_coords + active_terminal.display_cols); - - active_terminal.increase_height_down(count); - self.os_api.set_terminal_size_using_fd( - active_terminal.pid, - active_terminal.display_cols, - active_terminal.display_rows - ); - - terminals_below.retain(|t| { - let terminal = self.terminals.get(t).unwrap(); - terminal.x_coords >= left_resize_border && terminal.x_coords + terminal.display_cols <= right_resize_border - }); - for terminal_id in terminals_below { - let terminal = self.terminals.get_mut(&terminal_id).unwrap(); - terminal.reduce_height_down(count); - self.os_api.set_terminal_size_using_fd( - terminal.pid, - terminal.display_cols, - terminal.display_rows - ); - } - - if let Some(terminals_to_the_left) = terminals_to_the_left { - for terminal_id in terminals_to_the_left.iter() { - let terminal = self.terminals.get_mut(terminal_id).unwrap(); - terminal.increase_height_down(count); - self.os_api.set_terminal_size_using_fd( - terminal.pid, - terminal.display_cols, - terminal.display_rows - ); - } - } - - if let Some(terminals_to_the_right) = terminals_to_the_right { - for terminal_id in terminals_to_the_right.iter() { - let terminal = self.terminals.get_mut(terminal_id).unwrap(); - terminal.increase_height_down(count); - self.os_api.set_terminal_size_using_fd( - terminal.pid, - terminal.display_cols, - terminal.display_rows - ); - } - } - }, - (None, None) => {} - } - self.render(); - } - } - pub fn resize_up (&mut self) { - // TODO: find out by how much we actually reduced and only reduce by that much - let count = 2; - if let Some(active_terminal_id) = self.get_active_terminal_id() { - let terminals_below = self.terminal_ids_directly_below(&active_terminal_id); - let terminals_above = self.terminal_ids_directly_above(&active_terminal_id); - match (terminals_below, terminals_above) { - (_, Some(mut terminals_above)) => { - // reduce down - let terminal_borders_above: HashSet<u16> = terminals_above.iter().map(|t| self.terminals.get(t).unwrap().x_coords).collect(); - let terminals_to_the_left_and_left_resize_border = self.terminal_ids_directly_to_the_left_with_same_top_alignment(&active_terminal_id) - .and_then(|t| { - let terminals: Vec<&TerminalOutput> = t.iter().map(|t| self.terminals.get(t).unwrap()).collect(); - Some(terminals) - }) - .and_then(|mut t| { - let mut left_resize_border = 0; - for terminal in &t { - let right_terminal_boundary = terminal.x_coords + terminal.display_cols; - if terminal_borders_above.get(&(right_terminal_boundary + 1)).is_some() && left_resize_border < right_terminal_boundary { - left_resize_border = right_terminal_boundary + 1; - } - } - t.retain(|terminal| { - terminal.x_coords >= left_resize_border - }); - let terminal_ids: Vec<RawFd> = t.iter().map(|t| t.pid).collect(); - Some((terminal_ids, left_resize_border)) - }); - let terminals_to_the_right_and_right_resize_border = self.terminal_ids_directly_to_the_right_with_same_top_alignment(&active_terminal_id) - .and_then(|t| { - let terminals: Vec<&TerminalOutput> = t.iter().map(|t| self.terminals.get(t).unwrap()).collect(); - Some(terminals) - }) - .and_then(|mut t| { - let mut right_resize_border = self.full_screen_ws.ws_col; - for terminal in &t { - let left_terminal_boundary = terminal.x_coords; - if terminal_borders_above.get(&left_terminal_boundary).is_some() && right_resize_border > left_terminal_boundary { - right_resize_border = left_terminal_boundary; - } - } - t.retain(|terminal| { - terminal.x_coords + terminal.display_cols <= right_resize_border - }); - let terminal_ids: Vec<RawFd> = t.iter().map(|t| t.pid).collect(); - Some((terminal_ids, right_resize_border)) - }); - let (terminals_to_the_left, left_resize_border) = match terminals_to_the_left_and_left_resize_border { - Some((terminals_to_the_left, left_resize_border)) => (Some(terminals_to_the_left), Some(left_resize_border)), - None => (None, None), - }; - let (terminals_to_the_right, right_resize_border) = match terminals_to_the_right_and_right_resize_border { - Some((terminals_to_the_right, right_resize_border)) => (Some(terminals_to_the_right), Some(right_resize_border)), - None => (None, None), - }; - let active_terminal = self.terminals.get_mut(&active_terminal_id).unwrap(); - let left_resize_border = left_resize_border.unwrap_or(active_terminal.x_coords); - let right_resize_border = right_resize_border.unwrap_or(active_terminal.x_coords + active_terminal.display_cols); - - active_terminal.increase_height_up(count); - self.os_api.set_terminal_size_using_fd( - active_terminal.pid, - active_terminal.display_cols, - active_terminal.display_rows - ); - - terminals_above.retain(|t| { - let terminal = self.terminals.get(t).unwrap(); - terminal.x_coords >= left_resize_border && terminal.x_coords + terminal.display_cols <= right_resize_border - }); - for terminal_id in terminals_above { - let terminal = self.terminals.get_mut(&terminal_id).unwrap(); - terminal.reduce_height_up(count); - self.os_api.set_terminal_size_using_fd( - terminal.pid, - terminal.display_cols, - terminal.display_rows - ); - } - - if let Some(terminals_to_the_left) = terminals_to_the_left { - for terminal_id in terminals_to_the_left.iter() { - let terminal = self.terminals.get_mut(terminal_id).unwrap(); - terminal.increase_height_up(count); - self.os_api.set_terminal_size_using_fd( - terminal.pid, - terminal.display_cols, - terminal.display_rows - ); - } - } - - if let Some(terminals_to_the_right) = terminals_to_the_right { - for terminal_id in terminals_to_the_right.iter() { - let terminal = self.terminals.get_mut(terminal_id).unwrap(); - terminal.increase_height_up(count); - self.os_api.set_terminal_size_using_fd( - terminal.pid, - terminal.display_cols, - terminal.display_rows - ); - } - } - }, - (Some(mut terminals_below), None) => { - // increase down - let terminal_borders_below: HashSet<u16> = terminals_below.iter().map(|t| self.terminals.get(t).unwrap().x_coords).collect(); - let terminals_to_the_left_and_left_resize_border = self.terminal_ids_directly_to_the_left_with_same_bottom_alignment(&active_terminal_id) - .and_then(|t| { - let terminals: Vec<&TerminalOutput> = t.iter().map(|t| self.terminals.get(t).unwrap()).collect(); - Some(terminals) - }) - .and_then(|mut t| { - let mut left_resize_border = 0; - for terminal in &t { - let right_terminal_boundary = terminal.x_coords + terminal.display_cols; - if terminal_borders_below.get(&(right_terminal_boundary + 1)).is_some() && left_resize_border < right_terminal_boundary { - left_resize_border = right_terminal_boundary + 1; - } - } - t.retain(|terminal| { - terminal.x_coords >= left_resize_border - }); - let terminal_ids: Vec<RawFd> = t.iter().map(|t| t.pid).collect(); - Some((terminal_ids, left_resize_border)) - }); - let terminals_to_the_right_and_right_resize_border = self.terminal_ids_directly_to_the_right_with_same_bottom_alignment(&active_terminal_id) - .and_then(|t| { - let terminals: Vec<&TerminalOutput> = t.iter().map(|t| self.terminals.get(t).unwrap()).collect(); - Some(terminals) - }) - .and_then(|mut t| { - let mut right_resize_border = self.full_screen_ws.ws_col; - for terminal in &t { - let left_terminal_boundary = terminal.x_coords; - if terminal_borders_below.get(&left_terminal_boundary).is_some() && right_resize_border > left_terminal_boundary { - right_resize_border = left_terminal_boundary; - } - } - t.retain(|terminal| { - terminal.x_coords + terminal.display_cols <= right_resize_border - }); - let terminal_ids: Vec<RawFd> = t.iter().map(|t| t.pid).collect(); - Some((terminal_ids, right_resize_border)) - }); - let (terminals_to_the_left, left_resize_border) = match terminals_to_the_left_and_left_resize_border { - Some((terminals_to_the_left, left_resize_border)) => (Some(terminals_to_the_left), Some(left_resize_border)), - None => (None, None), - }; - let (terminals_to_the_right, right_resize_border) = match terminals_to_the_right_and_right_resize_border { - Some((terminals_to_the_right, right_resize_border)) => (Some(terminals_to_the_right), Some(right_resize_border)), - None => (None, None), - }; - let active_terminal = self.terminals.get_mut(&active_terminal_id).unwrap(); - let left_resize_border = left_resize_border.unwrap_or(active_terminal.x_coords); - let right_resize_border = right_resize_border.unwrap_or(active_terminal.x_coords + active_terminal.display_cols); // TODO: + 1? - - active_terminal.reduce_height_up(count); - self.os_api.set_terminal_size_using_fd( - active_terminal.pid, - active_terminal.display_cols, - active_terminal.display_rows - ); - - terminals_below.retain(|t| { - let terminal = self.terminals.get(t).unwrap(); - terminal.x_coords >= left_resize_border && terminal.x_coords + terminal.display_cols <= right_resize_border - }); - for terminal_id in terminals_below { - let terminal = self.terminals.get_mut(&terminal_id).unwrap(); - terminal.increase_height_up(count); - self.os_api.set_terminal_size_using_fd( - terminal.pid, - terminal.display_cols, - terminal.display_rows - ); - } - - if let Some(terminals_to_the_left) = terminals_to_the_left { - for terminal_id in terminals_to_the_left.iter() { - let terminal = self.terminals.get_mut(terminal_id).unwrap(); - terminal.reduce_height_up(count); - self.os_api.set_terminal_size_using_fd( - terminal.pid, - terminal.display_cols, - terminal.display_rows - ); - } - } - - if let Some(terminals_to_the_right) = terminals_to_the_right { - for terminal_id in terminals_to_the_right.iter() { - let terminal = self.terminals.get_mut(terminal_id).unwrap(); - terminal.reduce_height_up(count); - self.os_api.set_terminal_size_using_fd( - terminal.pid, - terminal.display_cols, - terminal.display_rows - ); - } - } - }, - (None, None) => {} - } - self.render(); - } - } - pub fn move_focus(&mut self) { - if self.terminals.is_empty() { - return; - } - let active_terminal_id = self.get_active_terminal_id().unwrap(); - let terminal_ids: Vec<RawFd> = self.terminals.keys().copied().collect(); // TODO: better, no allocations - let first_terminal = terminal_ids.get(0).unwrap(); - let active_terminal_id_position = terminal_ids.iter().position(|id| id == &active_terminal_id).unwrap(); - if let Some(next_terminal) = terminal_ids.get(active_terminal_id_position + 1) { - self.active_terminal = Some(*next_terminal); - } else { - self.active_terminal = Some(*first_terminal); - } - self.render(); - } -} - -enum PtyInstruction { - SpawnTerminalVertically, - SpawnTerminalHorizontally, - Quit -} - -struct PtyBus { - receive_pty_instructions: Receiver<PtyInstruction>, - send_pty_instructions: Sender<PtyInstruction>, - send_screen_instructions: Sender<ScreenInstruction>, - os_input: Box<dyn OsApi>, -} - -impl PtyBus { - pub fn new (send_screen_instructions: Sender<ScreenInstruction>, os_input: Box<dyn OsApi>) -> Self { - let (send_pty_instructions, receive_pty_instructions): (Sender<PtyInstruction>, Receiver<PtyInstruction>) = channel(); - PtyBus { - send_pty_instructions, - send_screen_instructions, - receive_pty_instructions, - os_input, - } - } - pub fn spawn_terminal_vertically(&mut self) { - let (pid_primary, _pid_secondary): (RawFd, RawFd) = self.os_input.spawn_terminal(); - task::spawn({ - let send_screen_instructions = self.send_screen_instructions.clone(); - let os_input = self.os_input.clone(); - async move { - let mut vte_parser = vte::Parser::new(); - let mut vte_event_sender = VteEventSender::new(pid_primary, send_screen_instructions.clone()); - let mut first_terminal_bytes = ReadFromPid::new(&pid_primary, os_input); - while let Some(bytes) = first_terminal_bytes.next().await { - let bytes_is_empty = bytes.is_empty(); - for byte in bytes { - vte_parser.advance(&mut vte_event_sender, byte); - } - if !bytes_is_empty { - send_screen_instructions.send(ScreenInstruction::Render).unwrap(); - } else { - task::sleep(::std::time::Duration::from_millis(10)).await; - } - } - } - }); - self.send_screen_instructions.send(ScreenInstruction::VerticalSplit(pid_primary)).unwrap(); - } - pub fn spawn_terminal_horizontally(&mut self) { - let (pid_primary, _pid_secondary): (RawFd, RawFd) = self.os_input.spawn_terminal(); - task::spawn({ - let send_screen_instructions = self.send_screen_instructions.clone(); - let os_input = self.os_input.clone(); - async move { - let mut vte_parser = vte::Parser::new(); - let mut vte_event_sender = VteEventSender::new(pid_primary, send_screen_instructions.clone()); - let mut first_terminal_bytes = ReadFromPid::new(&pid_primary, os_input); - while let Some(bytes) = first_terminal_bytes.next().await { - let bytes_is_empty = bytes.is_empty(); - for byte in bytes { - vte_parser.advance(&mut vte_event_sender, byte); - } - if !bytes_is_empty { - send_screen_instructions.send(ScreenInstruction::Render).unwrap(); - } else { - task::sleep(::std::time::Duration::from_millis(10)).await; - } - } - } - }); - self.send_screen_instructions.send(ScreenInstruction::HorizontalSplit(pid_primary)).unwrap(); - } -} - pub fn main() { let os_input = get_os_input(); start(Box::new(os_input)); @@ -2267,5 +166,4 @@ pub fn start(mut os_input: Box<dyn OsApi>) { os_input.get_stdout_writer().write(goodbye_message.as_bytes()).unwrap(); os_input.get_stdout_writer().flush().unwrap(); - } |
