#[path = "previews/mod.rs"]
mod previews;
use blaeck::{poll_key, Blaeck, Key};
use previews::async_app::{AppState, BackgroundEvent};
use std::io::stdout;
use std::time::{Duration, Instant};
use tokio::sync::mpsc;
fn handle_input(state: &mut AppState, key: Key) {
if key.is_ctrl_c() {
state.should_exit = true;
return;
}
if state.is_loading {
return;
}
if key.is_enter() && !state.input.is_empty() {
let _input = std::mem::take(&mut state.input);
state.is_loading = true;
state.progress = 0;
state.text.clear();
state.spinner_start = Instant::now();
state.status = format!("Processing: {}", _input);
return;
}
if key.is_backspace() {
state.input.pop();
} else if let Some(c) = key.as_char() {
state.input.push(c);
}
}
async fn background_worker(input: String, tx: mpsc::Sender<BackgroundEvent>) {
let words: Vec<&str> = input.split_whitespace().collect();
let total = words.len().max(1);
for (i, word) in words.iter().enumerate() {
tokio::time::sleep(Duration::from_millis(200)).await;
let chunk = format!("{} ", word.to_uppercase());
let _ = tx.send(BackgroundEvent::DataChunk(chunk)).await;
let progress = ((i + 1) * 100 / total) as u32;
let _ = tx.send(BackgroundEvent::Progress(progress)).await;
}
tokio::time::sleep(Duration::from_millis(300)).await;
let _ = tx.send(BackgroundEvent::Done).await;
}
#[tokio::main]
async fn main() -> anyhow::Result<()> {
let mut blaeck = Blaeck::new(stdout())?;
let mut state = AppState::new();
let (bg_tx, mut bg_rx) = mpsc::channel::<BackgroundEvent>(100);
let mut pending_input: Option<String> = None;
crossterm::terminal::enable_raw_mode()?;
loop {
blaeck.render(previews::async_app::render(&state))?;
if state.should_exit {
break;
}
if let Some(input) = pending_input.take() {
let tx = bg_tx.clone();
tokio::spawn(background_worker(input, tx));
}
tokio::select! {
_ = tokio::time::sleep(Duration::from_millis(50)) => {
if let Some(key) = poll_key(Duration::ZERO)? {
handle_input(&mut state, key);
if state.is_loading && state.text.is_empty() && state.progress == 0 {
if let Some(input) = state.status.strip_prefix("Processing: ") {
pending_input = Some(input.to_string());
}
}
}
}
Some(event) = bg_rx.recv() => {
previews::async_app::handle_background_event(&mut state, event);
}
}
}
blaeck.unmount()?;
crossterm::terminal::disable_raw_mode()?;
println!("\nGoodbye!");
Ok(())
}