zellij/src/main.rs
2020-09-29 11:43:22 +02:00

170 lines
6.5 KiB
Rust

#[cfg(test)]
mod tests;
mod os_input_output;
mod terminal_pane;
mod pty_bus;
mod screen;
use std::io::{Read, Write};
use ::std::thread;
use crate::os_input_output::{get_os_input, OsApi};
use crate::terminal_pane::TerminalOutput;
use crate::pty_bus::{VteEvent, PtyBus, PtyInstruction};
use crate::screen::{Screen, ScreenInstruction};
// sigwinch stuff
use ::signal_hook::iterator::Signals;
pub type OnSigWinch = dyn Fn(Box<dyn Fn()>) + Send;
pub type SigCleanup = dyn Fn() + Send;
pub fn sigwinch() -> (Box<OnSigWinch>, Box<SigCleanup>) {
let signals = Signals::new(&[signal_hook::SIGWINCH]).unwrap();
let on_winch = {
let signals = signals.clone();
move |cb: Box<dyn Fn()>| {
for signal in signals.forever() {
match signal {
signal_hook::SIGWINCH => cb(),
_ => unreachable!(),
}
}
}
};
let cleanup = move || {
signals.close();
};
(Box::new(on_winch), Box::new(cleanup))
}
pub fn main() {
let os_input = get_os_input();
start(Box::new(os_input));
}
pub fn start(mut os_input: Box<dyn OsApi>) {
let mut active_threads = vec![];
let full_screen_ws = os_input.get_terminal_size_using_fd(0);
os_input.into_raw_mode(0);
let mut screen = Screen::new(&full_screen_ws, os_input.clone());
let send_screen_instructions = screen.send_screen_instructions.clone();
let mut pty_bus = PtyBus::new(send_screen_instructions.clone(), os_input.clone());
let send_pty_instructions = pty_bus.send_pty_instructions.clone();
active_threads.push(
thread::Builder::new()
.name("pty".to_string())
.spawn({
move || {
pty_bus.spawn_terminal_vertically();
loop {
let event = pty_bus.receive_pty_instructions
.recv()
.expect("failed to receive event on channel");
match event {
PtyInstruction::SpawnTerminalVertically => {
pty_bus.spawn_terminal_vertically();
}
PtyInstruction::SpawnTerminalHorizontally => {
pty_bus.spawn_terminal_horizontally();
}
PtyInstruction::Quit => {
break;
}
}
}
}
}).unwrap()
);
active_threads.push(
thread::Builder::new()
.name("screen".to_string())
.spawn({
move || {
loop {
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::HorizontalSplit(pid) => {
screen.horizontal_split(pid);
}
ScreenInstruction::VerticalSplit(pid) => {
screen.vertical_split(pid);
}
ScreenInstruction::WriteCharacter(byte) => {
screen.write_to_active_terminal(byte);
}
ScreenInstruction::ResizeLeft => {
screen.resize_left();
}
ScreenInstruction::ResizeRight => {
screen.resize_right();
}
ScreenInstruction::ResizeDown => {
screen.resize_down();
}
ScreenInstruction::ResizeUp => {
screen.resize_up();
}
ScreenInstruction::MoveFocus => {
screen.move_focus();
}
ScreenInstruction::Quit => {
break;
}
}
}
}
}).unwrap()
);
let mut stdin = os_input.get_stdin_reader();
loop {
let mut buffer = [0; 1];
stdin.read(&mut buffer).expect("failed to read stdin");
if buffer[0] == 10 { // ctrl-j
send_screen_instructions.send(ScreenInstruction::ResizeDown).unwrap();
} else if buffer[0] == 11 { // ctrl-k
send_screen_instructions.send(ScreenInstruction::ResizeUp).unwrap();
} else if buffer[0] == 16 { // ctrl-p
send_screen_instructions.send(ScreenInstruction::MoveFocus).unwrap();
} else if buffer[0] == 8 { // ctrl-h
send_screen_instructions.send(ScreenInstruction::ResizeLeft).unwrap();
} else if buffer[0] == 12 { // ctrl-l
send_screen_instructions.send(ScreenInstruction::ResizeRight).unwrap();
} else if buffer[0] == 14 { // ctrl-n
send_pty_instructions.send(PtyInstruction::SpawnTerminalVertically).unwrap();
} else if buffer[0] == 2 { // ctrl-b
send_pty_instructions.send(PtyInstruction::SpawnTerminalHorizontally).unwrap();
} else if buffer[0] == 17 { // ctrl-q
send_screen_instructions.send(ScreenInstruction::Quit).unwrap();
send_pty_instructions.send(PtyInstruction::Quit).unwrap();
break;
} else {
// println!("\r buffer {:?} ", buffer[0]);
send_screen_instructions.send(ScreenInstruction::WriteCharacter(buffer[0])).unwrap();
}
};
for thread_handler in active_threads {
thread_handler.join().unwrap();
}
// cleanup();
let reset_style = "\u{1b}[m";
let goto_start_of_last_line = format!("\u{1b}[{};{}H", full_screen_ws.ws_row, 1);
let goodbye_message = format!("{}\n{}Bye from Mosaic!", goto_start_of_last_line, reset_style);
os_input.get_stdout_writer().write(goodbye_message.as_bytes()).unwrap();
os_input.get_stdout_writer().flush().unwrap();
}