extern crate mortal;
extern crate rand;
use std::io;
use std::sync::Arc;
use std::sync::mpsc::{sync_channel, SyncSender, TrySendError};
use std::thread::{spawn, sleep};
use std::time::Duration;
use mortal::{Color, Cursor, Event, Key, PrepareConfig, Screen};
use rand::{Rng, seq::SliceRandom, thread_rng};
const COLORS: &[Color] = &[
Color::Blue,
Color::Red,
Color::Green,
Color::Cyan,
Color::Magenta,
];
fn main() -> io::Result<()> {
let screen = Arc::new(Screen::new(PrepareConfig{
block_signals: true,
.. PrepareConfig::default()
})?);
let mut handles = Vec::new();
let (shutdown_tx, shutdown_rx) = sync_channel(0);
let mut colors = COLORS.to_vec();
colors.shuffle(&mut thread_rng());
screen.write_at((0, 0), "Running threads. Press 'q' to stop.");
screen.set_cursor((0, 0));
screen.refresh()?;
for i in 0..5 {
let name = format!("child{}", i);
let screen = screen.clone();
let color = colors[i];
let line = 2 + i * 2;
let chan = shutdown_tx.clone();
let handle = spawn(move || {
run_task(&name, line, color, &screen, &chan).unwrap()
});
handles.push(handle);
}
let mut read = screen.lock_read().unwrap();
loop {
let ev = read.read_event(None)?;
if let Some(Event::Key(Key::Char('q'))) = ev {
break;
}
}
drop(shutdown_rx);
for handle in handles {
handle.join().unwrap();
}
Ok(())
}
fn run_task(name: &str, line: usize, color: Color, screen: &Screen,
sender: &SyncSender<()>) -> io::Result<()> {
let mut rng = thread_rng();
loop {
match sender.try_send(()) {
Err(TrySendError::Disconnected(_)) => break,
_ => ()
}
sleep(Duration::from_millis(rng.gen_range(300..500)));
let mut lock = screen.lock_write().unwrap();
lock.set_cursor(Cursor{line, column: 0});
lock.write_str("[");
lock.bold();
lock.set_fg(color);
lock.write_str(name);
lock.clear_attributes();
writeln!(lock, "]: random output: {:>3}", rng.gen::<u8>());
lock.set_cursor((0, 0));
lock.refresh()?;
}
Ok(())
}