aboutsummaryrefslogtreecommitdiffstats
path: root/src
diff options
context:
space:
mode:
authorAram Drevekenin <aram@poor.dev>2020-08-20 16:06:38 +0200
committerAram Drevekenin <aram@poor.dev>2020-08-20 16:06:38 +0200
commitb74dca4fa136441b69194614982de09fc47d1e9d (patch)
tree04e492936c51f8dd0dbd9fdc2c72fcc950e76b96 /src
parentcleanup (diff)
downloadsl0ppij-b74dca4fa136441b69194614982de09fc47d1e9d.tar.gz
sl0ppij-b74dca4fa136441b69194614982de09fc47d1e9d.tar.xz
sl0ppij-b74dca4fa136441b69194614982de09fc47d1e9d.zip
channels
Diffstat (limited to 'src')
-rw-r--r--src/main.rs484
1 files changed, 363 insertions, 121 deletions
diff --git a/src/main.rs b/src/main.rs
index c9f69f8d..b9261405 100644
--- a/src/main.rs
+++ b/src/main.rs
@@ -1,5 +1,7 @@
-// use std::time::{Duration, Instant};
+use std::time::{Duration, Instant};
use std::io;
+use futures::future::join_all;
+use std::cell::Cell;
use ::std::fmt::{self, Display, Formatter};
use std::cmp::max;
use std::io::{Read, Write};
@@ -21,8 +23,59 @@ use std::os::unix::io::RawFd;
use std::process::Command;
use ::std::thread;
use ::std::sync::{Arc, Mutex};
-
use vte;
+use async_std::stream::*;
+use async_std::task;
+use async_std::task::*;
+use async_std::prelude::*;
+use ::std::pin::*;
+use std::sync::mpsc::{channel, Sender, Receiver};
+
+
+
+struct ReadFromPid {
+ pid: RawFd,
+ read_buffer: [u8; 115200],
+}
+
+impl ReadFromPid {
+ fn new(pid: &RawFd) -> ReadFromPid {
+ ReadFromPid {
+ pid: *pid,
+ read_buffer: [0; 115200], // TODO: ???
+ }
+ }
+}
+
+impl Stream for ReadFromPid {
+ type Item = Vec<u8>;
+ fn poll_next(mut self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Option<Self::Item>> {
+ let read_result = read(self.pid, &mut self.read_buffer);
+ match read_result {
+ Ok(res) => {
+ // TODO: this might become an issue with multiple panes sending data simultaneously
+ // ...consider returning None if res == 0 and handling it in the task (or sending
+ // Poll::Pending?)
+ let res = Some(self.read_buffer[..=res].to_vec());
+ self.read_buffer = [0; 115200];
+ 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
+ // task::block_on(task::sleep(Duration::from_millis(10)));
+ } else {
+ panic!("error {:?}", e);
+ }
+ },
+ _ => panic!("error {:?}", e)
+ }
+ }
+ }
+ }
+}
fn read_from_pid (pid: RawFd) -> Option<Vec<u8>> {
let mut read_buffer = [0; 115200];
@@ -104,7 +157,8 @@ fn spawn_terminal (ws: &Winsize) -> (RawFd, RawFd) {
let pid_primary = fork_pty_res.master;
let pid_secondary = match fork_pty_res.fork_result {
ForkResult::Parent { child } => {
- fcntl(pid_primary, FcntlArg::F_SETFL(OFlag::O_NONBLOCK)).expect("could not fcntl");
+ fcntl(pid_primary, FcntlArg::F_SETFL(OFlag::empty())).expect("could not fcntl");
+ // fcntl(pid_primary, FcntlArg::F_SETFL(OFlag::O_NONBLOCK)).expect("could not fcntl");
child
},
ForkResult::Child => {
@@ -175,6 +229,7 @@ impl Display for TerminalCharacter {
}
struct TerminalOutput {
+ pub pid: RawFd,
pub characters: Vec<TerminalCharacter>,
pub display_rows: u16,
pub display_cols: u16,
@@ -188,18 +243,47 @@ struct TerminalOutput {
const EMPTY_TERMINAL_CHARACTER: TerminalCharacter = TerminalCharacter { character: ' ', ansi_code: None };
impl TerminalOutput {
- pub fn new () -> TerminalOutput {
+ pub fn new (pid: RawFd, ws: Winsize) -> TerminalOutput {
TerminalOutput {
+ pid,
characters: vec![],
cursor_position: 0,
newline_indices: Vec::new(),
linebreak_indices: Vec::new(),
- display_rows: 0,
- display_cols: 0,
+ display_rows: ws.ws_row,
+ display_cols: ws.ws_col,
should_render: false,
pending_ansi_code: None,
}
}
+ pub fn handle_event(&mut self, event: VteEvent) {
+ match event {
+ VteEvent::Print(c) => {
+ self.print(c);
+ },
+ VteEvent::Execute(byte) => {
+ self.execute(byte);
+ },
+ VteEvent::Hook(params, intermediates, ignore, c) => {
+ self.hook(&params, &intermediates, ignore, c);
+ },
+ VteEvent::Put(byte) => {
+ self.put(byte);
+ },
+ VteEvent::Unhook => {
+ self.unhook();
+ },
+ VteEvent::OscDispatch(params, bell_terminated) => {
+ self.osc_dispatch(params, bell_terminated);
+ },
+ VteEvent::CsiDispatch(params, intermediates, ignore, c) => {
+ self.csi_dispatch(&params, &intermediates, ignore, c);
+ },
+ VteEvent::EscDispatch(intermediates, ignore, byte) => {
+ self.esc_dispatch(&intermediates, ignore, byte);
+ }
+ }
+ }
pub fn reduce_width(&mut self, count: u16) {
self.display_cols -= count;
self.reflow_lines();
@@ -236,10 +320,13 @@ impl TerminalOutput {
x += 1;
}
}
- pub fn read_buffer_as_lines (&mut self) -> Vec<Vec<&TerminalCharacter>> {
+ pub fn read_buffer_as_lines (&self) -> Vec<Vec<&TerminalCharacter>> {
if DEBUGGING {
return vec![];
}
+ if self.characters.len() == 0 {
+ return vec![];
+ }
let mut output: VecDeque<Vec<&TerminalCharacter>> = VecDeque::new();
let mut i = self.characters.len();
let mut current_line: VecDeque<&TerminalCharacter> = VecDeque::new();
@@ -289,7 +376,7 @@ impl TerminalOutput {
output.push_front(Vec::from(empty_line.clone()));
}
}
- self.should_render = false;
+ // self.should_render = false;
Vec::from(output)
}
pub fn cursor_position_in_last_line (&self) -> usize {
@@ -390,7 +477,8 @@ impl TerminalOutput {
const DEBUGGING: bool = false;
-impl vte::Perform for TerminalOutput {
+// vte methods
+impl TerminalOutput {
fn print(&mut self, c: char) {
if DEBUGGING {
println!("\r[print] {:?}", c);
@@ -463,7 +551,9 @@ impl vte::Perform for TerminalOutput {
}
}
- fn osc_dispatch(&mut self, params: &[&[u8]], bell_terminated: bool) {
+ // fn osc_dispatch(&mut self, params: &[&[u8]], bell_terminated: bool) {
+ // TODO: normalize vec/slices for all of these methods and the enum
+ fn osc_dispatch(&mut self, params: Vec<Vec<u8>>, bell_terminated: bool) {
if DEBUGGING {
println!("\r[osc_dispatch] params={:?} bell_terminated={}", params, bell_terminated);
}
@@ -525,6 +615,73 @@ impl vte::Perform for TerminalOutput {
}
}
+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();
+ }
+}
+
// sigwinch stuff
use ::signal_hook::iterator::Signals;
@@ -574,35 +731,92 @@ fn character_is_already_onscreen(
last_character_style == current_character_style && last_character.character == current_character.character
}
+enum ScreenInstruction {
+ Pty(RawFd, VteEvent),
+ Render,
+ AddTerminal(RawFd, Winsize),
+ WriteCharacter(u8),
+ ResizeLeft,
+ ResizeRight,
+ MoveFocus,
+}
+
struct Screen {
+ pub receiver: Receiver<ScreenInstruction>,
+ pub sender: Sender<ScreenInstruction>,
+ full_screen_ws: Winsize,
last_frame: Option<Vec<TerminalCharacter>>,
vertical_separator: TerminalCharacter, // TODO: better
+ active_terminal: Option<RawFd>,
+ terminal1_output: Option<TerminalOutput>,
+ terminal2_output: Option<TerminalOutput>,
}
impl Screen {
pub fn new () -> Self {
+ let (sender, receiver): (Sender<ScreenInstruction>, Receiver<ScreenInstruction>) = channel();
+ let full_screen_ws = get_terminal_size_using_fd(0);
Screen {
+ receiver,
+ sender,
+ full_screen_ws,
last_frame: None,
vertical_separator: TerminalCharacter::new('|').ansi_code(String::from("\u{1b}[m")), // TODO: better
+ terminal1_output: None,
+ terminal2_output: None,
+ active_terminal: None,
}
}
- pub fn render (&mut self, terminal1_output: &mut TerminalOutput, terminal2_output: &mut TerminalOutput, full_screen_ws: &Winsize, terminal1_is_active: bool) {
- if DEBUGGING {
+ pub fn add_terminal(&mut self, pid: RawFd, ws: Winsize) {
+ if self.terminal1_output.is_none() {
+ self.terminal1_output = Some(TerminalOutput::new(pid, ws));
+ self.active_terminal = Some(pid);
+ } else if self.terminal2_output.is_none() {
+ self.terminal2_output = Some(TerminalOutput::new(pid, ws));
+ } else {
+ panic!("cannot support more than 2 terminals atm");
+ }
+ }
+ pub fn handle_pty_event(&mut self, pid: RawFd, event: VteEvent) {
+ if let Some(terminal_output) = self.terminal1_output.as_mut() {
+ if terminal_output.pid == pid {
+ terminal_output.handle_event(event);
+ return;
+ }
+ }
+ if let Some(terminal_output) = self.terminal2_output.as_mut() {
+ if terminal_output.pid == pid {
+ terminal_output.handle_event(event);
+ return;
+ }
+ }
+ }
+ pub fn write_to_active_terminal(&self, byte: u8) {
+ if let Some(active_terminal) = &self.active_terminal {
+ let mut buffer = [byte];
+ write(*active_terminal, &mut buffer).expect("failed to write to terminal");
+ tcdrain(*active_terminal).expect("failed to drain terminal");
+ }
+ }
+ pub fn render (&mut self) {
+ let left_terminal_lines = self.terminal1_output.as_ref().unwrap().read_buffer_as_lines();
+ let right_terminal_lines = self.terminal2_output.as_ref().unwrap().read_buffer_as_lines();
+ if left_terminal_lines.len() < self.full_screen_ws.ws_row as usize || right_terminal_lines.len() < self.full_screen_ws.ws_row as usize {
+ // TODO: this is hacky and is only here(?) for when the terminals are not ready yet
return;
}
- let left_terminal_lines = terminal1_output.read_buffer_as_lines();
- let right_terminal_lines = terminal2_output.read_buffer_as_lines();
let mut frame: Vec<&TerminalCharacter> = vec![];
- for i in 0..full_screen_ws.ws_row {
- let left_terminal_row = left_terminal_lines.get(i as usize).unwrap();
+ let empty_vec = vec![]; // TODO: do not allocate, and less hacky
+ for i in 0..self.full_screen_ws.ws_row {
+ let left_terminal_row = left_terminal_lines.get(i as usize).unwrap_or(&empty_vec);
for terminal_character in left_terminal_row.iter() {
frame.push(terminal_character);
}
frame.push(&self.vertical_separator);
- let right_terminal_row = right_terminal_lines.get(i as usize).unwrap();
+ let right_terminal_row = right_terminal_lines.get(i as usize).unwrap_or(&empty_vec);
for terminal_character in right_terminal_row.iter() {
frame.push(terminal_character);
}
@@ -621,8 +835,8 @@ impl Screen {
for i in 0..last_frame.len() {
let last_character = last_frame.get(i).unwrap();
let current_character = frame.get(i).unwrap();
- let row = i / full_screen_ws.ws_col as usize + 1;
- let col = i % full_screen_ws.ws_col as usize + 1;
+ let row = i / self.full_screen_ws.ws_col as usize + 1;
+ let col = i % self.full_screen_ws.ws_col as usize + 1;
if !character_is_already_onscreen(&last_character, &current_character) {
if !last_character_was_changed {
data_lines.push_str(&format!("\u{1b}[{};{}H\u{1b}[m", row, &col)); // goto row/col
@@ -652,152 +866,180 @@ impl Screen {
// TODO: consider looping through current frame and only updating the cells that changed
self.last_frame = Some(frame.into_iter().cloned().collect::<Vec<_>>());
- let left_terminal_cursor_position = terminal1_output.cursor_position_in_last_line();
- let right_terminal_cursor_position = terminal2_output.cursor_position_in_last_line();
- if terminal1_is_active {
+ let left_terminal_cursor_position = self.terminal1_output.as_ref().unwrap().cursor_position_in_last_line();
+ let right_terminal_cursor_position = self.terminal2_output.as_ref().unwrap().cursor_position_in_last_line();
+
+ let active_terminal = self.active_terminal.unwrap();
+ if active_terminal == self.terminal1_output.as_ref().unwrap().pid {
data_lines.push_str(&format!("\r\u{1b}[{}C", left_terminal_cursor_position));
} else {
- data_lines.push_str(&format!("\r\u{1b}[{}C", right_terminal_cursor_position + (terminal1_output.display_cols + 1) as usize));
+ data_lines.push_str(&format!("\r\u{1b}[{}C", right_terminal_cursor_position + (self.terminal1_output.as_ref().unwrap().display_cols + 1) as usize));
}
::std::io::stdout().write_all(&data_lines.as_bytes()).expect("cannot write to stdout");
::std::io::stdout().flush().expect("could not flush");
}
+ pub fn resize_left (&mut self) {
+ let terminal1_output = self.terminal1_output.as_mut().unwrap();
+ let terminal2_output = self.terminal2_output.as_mut().unwrap();
+ terminal1_output.reduce_width(10);
+ terminal2_output.increase_width(10);
+ set_terminal_size_using_fd(terminal1_output.pid, terminal1_output.display_cols, terminal1_output.display_rows);
+ set_terminal_size_using_fd(terminal2_output.pid, terminal2_output.display_cols, terminal2_output.display_rows);
+ }
+ pub fn resize_right (&mut self) {
+ let terminal1_output = self.terminal1_output.as_mut().unwrap();
+ let terminal2_output = self.terminal2_output.as_mut().unwrap();
+ terminal1_output.increase_width(10);
+ terminal2_output.reduce_width(10);
+ set_terminal_size_using_fd(terminal1_output.pid, terminal1_output.display_cols, terminal1_output.display_rows);
+ set_terminal_size_using_fd(terminal2_output.pid, terminal2_output.display_cols, terminal2_output.display_rows);
+ }
+ pub fn move_focus(&mut self) {
+ let terminal1_output = self.terminal1_output.as_ref().unwrap();
+ let terminal2_output = self.terminal2_output.as_ref().unwrap();
+ let active_terminal = self.active_terminal.unwrap();
+ if active_terminal == terminal1_output.pid {
+ self.active_terminal = Some(terminal2_output.pid);
+ } else {
+ self.active_terminal = Some(terminal1_output.pid);
+ }
+ self.render();
+ }
+}
+
+struct PtyBus {
+ sender: Sender<ScreenInstruction>,
+ active_ptys: Vec<JoinHandle<()>>,
+}
+
+impl PtyBus {
+ pub fn new (sender: Sender<ScreenInstruction>) -> Self {
+ PtyBus {
+ sender,
+ active_ptys: Vec::new()
+ }
+ }
+ pub fn spawn_terminal(&mut self, ws: &Winsize) {
+ let ws = *ws;
+ let (pid_primary, _pid_secondary): (RawFd, RawFd) = spawn_terminal(&ws);
+ let task_handle = task::spawn({
+ // let pid_primary = pid_primary.clone();
+ let sender = self.sender.clone();
+ async move {
+ let mut vte_parser = vte::Parser::new();
+ let mut vte_event_sender = VteEventSender::new(pid_primary, sender.clone());
+ let mut first_terminal_bytes = ReadFromPid::new(&pid_primary);
+ 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 {
+ sender.send(ScreenInstruction::Render).unwrap();
+ }
+ }
+ }
+ });
+ self.sender.send(ScreenInstruction::AddTerminal(pid_primary, ws)).unwrap();
+ self.active_ptys.push(task_handle);
+ }
+ pub async fn wait_for_tasks(&mut self) {
+// let task1 = self.active_ptys.get_mut(0).unwrap();
+// task1.await;
+ let mut v = vec![];
+ for handle in self.active_ptys.iter_mut() {
+ // TODO: better, see commented lines above... can't we do this on the original vec?
+ v.push(handle);
+ }
+ join_all(v).await;
+ }
}
fn main() {
let mut active_threads = vec![];
- let full_screen_ws = get_terminal_size_using_fd(0);
- let (first_terminal_ws, second_terminal_ws) = split_horizontally_with_gap(&full_screen_ws);
- let (first_terminal_pid, _pid_secondary): (RawFd, RawFd) = spawn_terminal(&first_terminal_ws);
- let (second_terminal_pid, _pid_secondary): (RawFd, RawFd) = spawn_terminal(&second_terminal_ws);
let stdin = io::stdin();
into_raw_mode(0);
set_baud_rate(0);
::std::thread::sleep(std::time::Duration::from_millis(2000));
- let active_terminal = Arc::new(Mutex::new(first_terminal_pid));
-
- let first_terminal_ws = Arc::new(Mutex::new(first_terminal_ws));
- let second_terminal_ws = Arc::new(Mutex::new(second_terminal_ws));
-
- let terminal1_output = Arc::new(Mutex::new(TerminalOutput::new()));
- let terminal2_output = Arc::new(Mutex::new(TerminalOutput::new()));
-
- let screen = Arc::new(Mutex::new(Screen::new()));
+ let mut screen = Screen::new();
+ let send_screen_instructions = screen.sender.clone();
active_threads.push(
thread::Builder::new()
- .name("terminal_stdout_handler".to_string())
+ .name("pty".to_string())
.spawn({
-
- let mut vte_parser_terminal1 = vte::Parser::new();
- let mut vte_parser_terminal2 = vte::Parser::new();
-
- let active_terminal = active_terminal.clone();
- let terminal1_output = terminal1_output.clone();
- let terminal2_output = terminal2_output.clone();
+ let full_screen_ws = get_terminal_size_using_fd(0);
+ let (first_terminal_ws, second_terminal_ws) = split_horizontally_with_gap(&full_screen_ws);
let first_terminal_ws = first_terminal_ws.clone();
let second_terminal_ws = second_terminal_ws.clone();
- let screen = screen.clone();
+ let send_screen_instructions = send_screen_instructions.clone();
+ move || {
+ let mut pty_bus = PtyBus::new(send_screen_instructions);
+ // this is done here so that we can add terminals dynamically on a different
+ // thread later
+ pty_bus.spawn_terminal(&first_terminal_ws);
+ pty_bus.spawn_terminal(&second_terminal_ws);
+ task::block_on(pty_bus.wait_for_tasks());
+
+ }
+ }).unwrap()
+ );
+
+ active_threads.push(
+ thread::Builder::new()
+ .name("screen".to_string())
+ .spawn({
move || {
- {
- // TODO: better
- let first_terminal_ws = first_terminal_ws.lock().unwrap();
- let second_terminal_ws = second_terminal_ws.lock().unwrap();
- let mut terminal1_output = terminal1_output.lock().unwrap();
- let mut terminal2_output = terminal2_output.lock().unwrap();
- terminal1_output.set_size(&first_terminal_ws);
- terminal2_output.set_size(&second_terminal_ws);
- }
loop {
- match (read_from_pid(first_terminal_pid), read_from_pid(second_terminal_pid)) {
- (Some(first_terminal_read_bytes), Some(second_terminal_read_bytes)) => {
- let mut terminal1_output = terminal1_output.lock().unwrap();
- let mut terminal2_output = terminal2_output.lock().unwrap();
- for byte in first_terminal_read_bytes.iter() {
- vte_parser_terminal1.advance(&mut *terminal1_output, *byte);
- }
- for byte in second_terminal_read_bytes.iter() {
- vte_parser_terminal2.advance(&mut *terminal2_output, *byte);
- }
+ let event = screen.receiver
+ .recv()
+ .expect("failed to receive event on channel");
+ match event {
+ ScreenInstruction::Pty(pid, vte_event) => {
+ screen.handle_pty_event(pid, vte_event);
+ },
+ ScreenInstruction::Render => {
+ screen.render();
+ },
+ ScreenInstruction::AddTerminal(pid, ws) => {
+ screen.add_terminal(pid, ws);
}
- (Some(first_terminal_read_bytes), None) => {
- let mut terminal1_output = terminal1_output.lock().unwrap();
- // let now = Instant::now();
- for byte in first_terminal_read_bytes.iter() {
- vte_parser_terminal1.advance(&mut *terminal1_output, *byte);
- }
- // println!("\rParsed in {:?}", now.elapsed());
+ ScreenInstruction::WriteCharacter(byte) => {
+ screen.write_to_active_terminal(byte);
}
- (None, Some(second_terminal_read_bytes)) => {
- // let mut terminal1_output = terminal1_output.lock().unwrap();
- let mut terminal2_output = terminal2_output.lock().unwrap();
- for byte in second_terminal_read_bytes.iter() {
- vte_parser_terminal2.advance(&mut *terminal2_output, *byte);
- }
+ ScreenInstruction::ResizeLeft => {
+ screen.resize_left();
}
- (None, None) => {
- ::std::thread::sleep(std::time::Duration::from_millis(50)); // TODO: adjust this
+ ScreenInstruction::ResizeRight => {
+ screen.resize_right();
+ }
+ ScreenInstruction::MoveFocus => {
+ screen.move_focus();
}
- }
- let mut terminal1_output = terminal1_output.lock().unwrap();
- let mut terminal2_output = terminal2_output.lock().unwrap();
- if terminal1_output.should_render || terminal2_output.should_render {
- let active_terminal = active_terminal.lock().unwrap();
- let mut screen = screen.lock().unwrap();
- // let now = Instant::now();
- screen.render(&mut *terminal1_output, &mut *terminal2_output, &full_screen_ws, *active_terminal == first_terminal_pid);
- // println!("\r-------->R rendered in {:?}", now.elapsed());
}
}
}
- })
- .unwrap(),
+ }).unwrap()
);
+
loop {
let mut buffer = [0; 1];
{
let mut handle = stdin.lock();
handle.read(&mut buffer).expect("failed to read stdin");
if buffer[0] == 10 { // ctrl-j
- let mut terminal1_output = terminal1_output.lock().unwrap();
- let mut terminal2_output = terminal2_output.lock().unwrap();
- let active_terminal = active_terminal.lock().unwrap();
- terminal1_output.reduce_width(10);
- terminal2_output.increase_width(10);
- set_terminal_size_using_fd(first_terminal_pid, terminal1_output.display_cols, terminal1_output.display_rows);
- set_terminal_size_using_fd(second_terminal_pid, terminal2_output.display_cols, terminal2_output.display_rows);
- screen.lock().unwrap().render(&mut *terminal1_output, &mut *terminal2_output, &full_screen_ws, *active_terminal == first_terminal_pid);
+ send_screen_instructions.send(ScreenInstruction::ResizeLeft).unwrap();
continue;
} else if buffer[0] == 11 { // ctrl-k
- let mut terminal1_output = terminal1_output.lock().unwrap();
- let mut terminal2_output = terminal2_output.lock().unwrap();
- let active_terminal = active_terminal.lock().unwrap();
- terminal1_output.increase_width(10);
- terminal2_output.reduce_width(10);
- set_terminal_size_using_fd(first_terminal_pid, terminal1_output.display_cols, terminal1_output.display_rows);
- set_terminal_size_using_fd(second_terminal_pid, terminal2_output.display_cols, terminal2_output.display_rows);
- screen.lock().unwrap().render(&mut *terminal1_output, &mut *terminal2_output, &full_screen_ws, *active_terminal == first_terminal_pid);
+ send_screen_instructions.send(ScreenInstruction::ResizeRight).unwrap();
continue;
} else if buffer[0] == 16 { // ctrl-p
- let mut active_terminal = active_terminal.lock().unwrap();
- if *active_terminal == first_terminal_pid {
- *active_terminal = second_terminal_pid;
- let mut terminal1_output = terminal1_output.lock().unwrap();
- let mut terminal2_output = terminal2_output.lock().unwrap();
- screen.lock().unwrap().render(&mut *terminal1_output, &mut *terminal2_output, &full_screen_ws, *active_terminal == first_terminal_pid);
- } else {
- *active_terminal = first_terminal_pid;
- let mut terminal1_output = terminal1_output.lock().unwrap();
- let mut terminal2_output = terminal2_output.lock().unwrap();
- screen.lock().unwrap().render(&mut *terminal1_output, &mut *terminal2_output, &full_screen_ws, *active_terminal == first_terminal_pid);
- }
+ send_screen_instructions.send(ScreenInstruction::MoveFocus).unwrap();
continue;
}
}
- let active_terminal = active_terminal.lock().unwrap();
- write(*active_terminal, &mut buffer).expect("failed to write to terminal");
- tcdrain(*active_terminal).expect("failed to drain terminal");
+ send_screen_instructions.send(ScreenInstruction::WriteCharacter(buffer[0])).unwrap();
};
// cleanup();