Use crossbeam for message passing

This commit is contained in:
Austen Adler 2022-12-17 12:02:15 -05:00
parent 00b7620157
commit 6da63b6bed
4 changed files with 69 additions and 6 deletions

View File

@ -1,6 +1,9 @@
use crate::event::EventMessage;
use anyhow::bail; use anyhow::bail;
use anyhow::Context; use anyhow::Context;
use anyhow::Result; use anyhow::Result;
use crossbeam::channel::Receiver;
use crossbeam::channel::Sender;
use std::{ use std::{
io::Write, io::Write,
process::{Command, Stdio}, process::{Command, Stdio},
@ -8,6 +11,10 @@ use std::{
use crate::App; use crate::App;
pub struct CommandRequest {
cmdline: String,
}
pub struct CommandResult { pub struct CommandResult {
pub status_success: bool, pub status_success: bool,
pub stdout: Vec<u8>, pub stdout: Vec<u8>,
@ -24,6 +31,18 @@ impl Default for CommandResult {
} }
} }
// pub fn command_event_loop(command_request_receiver: Receiver<CommandRequest>,event_sender: Sender<EventMessage>) -> Result<()> {
// loop {
// match command_request_receiver.recv() {
// Ok(command_request) => event_sender.send(EventMessage::CrosstermEvent(e))?,
// Err(e) => {
// event_sender.send(EventMessage::CrosstermError(e))?;
// bail!("Crossterm read error");
// }
// }
// }
// }
pub fn run(app: &mut App) { pub fn run(app: &mut App) {
match run_inner(app) { match run_inner(app) {
Ok(c) => { Ok(c) => {

22
src/event.rs Normal file
View File

@ -0,0 +1,22 @@
use crate::command::CommandRequest;
use anyhow::bail;
use anyhow::Result;
use crossbeam::channel::Sender;
pub enum EventMessage {
CommandCompleted,
CrosstermEvent(crossterm::event::Event),
CrosstermError(std::io::Error),
}
pub fn crossterm_event_loop(event_sender: Sender<EventMessage>) -> Result<()> {
loop {
match crossterm::event::read() {
Ok(e) => event_sender.send(EventMessage::CrosstermEvent(e))?,
Err(e) => {
event_sender.send(EventMessage::CrosstermError(e))?;
bail!("Crossterm read error");
}
}
}
}

View File

@ -3,6 +3,7 @@
#![allow(clippy::module_name_repetitions, clippy::cast_possible_truncation)] #![allow(clippy::module_name_repetitions, clippy::cast_possible_truncation)]
mod command; mod command;
mod event;
mod ui; mod ui;
use ansi4tui::bytes_to_text; use ansi4tui::bytes_to_text;
use anyhow::anyhow; use anyhow::anyhow;
@ -11,6 +12,7 @@ use anyhow::Result;
use command::CommandResult; use command::CommandResult;
use crossterm::event::DisableBracketedPaste; use crossterm::event::DisableBracketedPaste;
use crossterm::event::EnableBracketedPaste; use crossterm::event::EnableBracketedPaste;
use event::EventMessage;
use std::str::FromStr; use std::str::FromStr;
use std::{ use std::{
io::{self, Write}, io::{self, Write},
@ -28,7 +30,7 @@ use tui::{
}; };
use crossterm::{ use crossterm::{
event::{self, DisableMouseCapture, EnableMouseCapture, Event, KeyCode}, event::{DisableMouseCapture, EnableMouseCapture, Event, KeyCode},
execute, execute,
terminal::{disable_raw_mode, enable_raw_mode, EnterAlternateScreen, LeaveAlternateScreen}, terminal::{disable_raw_mode, enable_raw_mode, EnterAlternateScreen, LeaveAlternateScreen},
}; };
@ -230,7 +232,7 @@ fn main() -> Result<()> {
fn run_app<B: Backend>( fn run_app<B: Backend>(
terminal: &mut Terminal<B>, terminal: &mut Terminal<B>,
mut app: App, mut app: App,
) -> io::Result<Option<(String, Vec<u8>)>> { ) -> Result<Option<(String, Vec<u8>)>> {
if !app.cmdline.is_empty() { if !app.cmdline.is_empty() {
command::run(&mut app); command::run(&mut app);
} }
@ -239,11 +241,22 @@ fn run_app<B: Backend>(
app.cmdline_position = app.cmdline.len() as u16; app.cmdline_position = app.cmdline.len() as u16;
} }
let (tx, rx) = crossbeam::channel::bounded(100);
// Start the event thread
let crossterm_tx = tx.clone();
std::thread::spawn(move || {
let _result = event::crossterm_event_loop(crossterm_tx);
});
std::mem::drop(tx);
loop { loop {
terminal.draw(|f| ui::draw(f, &app))?; terminal.draw(|f| ui::draw(f, &app))?;
match event::read()? { match rx.recv()? {
Event::Key(key) => match key.code { // match event::read()? {
EventMessage::CrosstermEvent(Event::Key(key)) => match key.code {
KeyCode::Esc => { KeyCode::Esc => {
// TODO: If there is any command line text, ask if the user is sure they want to quit // TODO: If there is any command line text, ask if the user is sure they want to quit
return Ok(None); return Ok(None);
@ -297,7 +310,7 @@ fn run_app<B: Backend>(
} }
_ => {} _ => {}
}, },
Event::Paste(data) => { EventMessage::CrosstermEvent(Event::Paste(data)) => {
app.cmdline.insert_str(app.cmdline_position as usize, &data); app.cmdline.insert_str(app.cmdline_position as usize, &data);
app.cmdline_position = app.cmdline_position.saturating_add(data.len() as u16); app.cmdline_position = app.cmdline_position.saturating_add(data.len() as u16);
@ -306,7 +319,13 @@ fn run_app<B: Backend>(
} }
} }
Event::FocusGained | Event::FocusLost | Event::Mouse(_) | Event::Resize(_, _) => {} EventMessage::CrosstermEvent(Event::FocusGained)
| EventMessage::CrosstermEvent(Event::FocusLost)
| EventMessage::CrosstermEvent(Event::Mouse(_))
| EventMessage::CrosstermEvent(Event::Resize(_, _)) => {}
// TODO
_ => {}
} }
} }
} }

3
src/worker.rs Normal file
View File

@ -0,0 +1,3 @@
struct CommandRunner {
event_sender: Sender<>
}