diff --git a/Cargo.lock b/Cargo.lock index e5b797644a9eb..00bf8bce7125a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3121,6 +3121,7 @@ checksum = "e64e6c0fbe2c17357405f7c758c1ef960fce08bdfb2c03d88d2a18d7e09c4b67" dependencies = [ "bitflags 1.3.2", "crossterm_winapi", + "futures-core", "libc", "mio", "parking_lot 0.12.1", @@ -5143,9 +5144,9 @@ checksum = "38d84fa142264698cdce1a9f9172cf383a0c82de1bddcf3092901442c4097004" [[package]] name = "futures-timer" -version = "3.0.2" +version = "3.0.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e64b03909df88034c26dc1547e8970b91f98bdb65165d6a4e9110d94263dbb2c" +checksum = "f288b0a4f20f9a56b5d1da57e2227c661b7b16168e2f72365f57b63326e29b24" dependencies = [ "gloo-timers", "send_wrapper 0.4.0", @@ -15373,10 +15374,12 @@ dependencies = [ "chrono", "clap", "colored", + "crossterm", "dirs 4.0.0", "docker-api", "field_names", "futures", + "futures-timer", "include_dir", "inquire", "itertools 0.13.0", diff --git a/crates/suiop-cli/Cargo.toml b/crates/suiop-cli/Cargo.toml index a2a5a16428225..0c39aa9b6e3a3 100644 --- a/crates/suiop-cli/Cargo.toml +++ b/crates/suiop-cli/Cargo.toml @@ -24,6 +24,7 @@ base64.workspace = true chrono.workspace = true clap.workspace = true colored.workspace = true +crossterm = { workspace = true, features = ["event-stream"] } dirs.workspace = true docker-api.workspace = true field_names.workspace = true @@ -54,6 +55,7 @@ once_cell.workspace = true futures.workspace = true thiserror.workspace = true strsim = "0.11.1" +futures-timer = "3.0.3" [dev-dependencies] diff --git a/crates/suiop-cli/src/cli/ci/image.rs b/crates/suiop-cli/src/cli/ci/image.rs index 001a6456b26cb..fbc100acbb79b 100644 --- a/crates/suiop-cli/src/cli/ci/image.rs +++ b/crates/suiop-cli/src/cli/ci/image.rs @@ -7,8 +7,16 @@ use anyhow::Result; use chrono::{DateTime, Local, Utc}; use clap::{Parser, ValueEnum}; use colored::Colorize; +use crossterm::{ + cursor::MoveTo, + event::{Event, EventStream, KeyCode}, + terminal::{disable_raw_mode, enable_raw_mode, Clear, ClearType}, + ExecutableCommand, +}; +use futures::StreamExt; +use futures::{select, FutureExt}; use serde::{self, Deserialize, Serialize}; -use std::{fmt::Display, str::FromStr}; +use std::{fmt::Display, str::FromStr, time::Duration}; use tabled::{settings::Style, Table, Tabled}; use tracing::debug; @@ -370,16 +378,47 @@ async fn send_image_request(token: &str, action: &ImageAction) -> Result<()> { let status_table = get_status_table(resp).await?.to_string(); println!("{}", status_table); } else { + enable_raw_mode()?; loop { - print!("{}[2J", 27 as char); - let req = generate_image_request(token, action); - - let resp = req.send().await?; - let status_table = get_status_table(resp).await?.to_string(); - println!("{}", status_table); - let half_sec = std::time::Duration::from_millis(500); - std::thread::sleep(half_sec); + let mut reader = EventStream::new(); + let mut delay = futures_timer::Delay::new(Duration::from_secs(1)).fuse(); + let mut event = reader.next().fuse(); + + select! { + _ = delay => { + let req = generate_image_request(token, action); + + let resp = req.send().await?; + let status_table = get_status_table(resp).await?.to_string(); + std::io::stdout().execute(Clear(ClearType::All))?.execute(MoveTo(0,0))?; + print!("press 'q' or 'esc' to quit"); + for (i, line )in status_table.lines().enumerate() { + std::io::stdout().execute(MoveTo(0,(i + 1) as u16))?; + println!("{}", line); + } + }, + maybe_event = event => { + println!("checking event"); + match maybe_event { + Some(Ok(event)) => { + if event == Event::Key(KeyCode::Char('q').into()) { + std::io::stdout().execute(Clear(ClearType::All))?.execute(MoveTo(0,0))?; + println!("q pressed, quitting 🫡"); + break + } else if event == Event::Key(KeyCode::Esc.into()) { + std::io::stdout().execute(Clear(ClearType::All))?.execute(MoveTo(0,0))?; + println!("esc pressed, quitting 🫡"); + break; + } + + } + Some(Err(e)) => println!("Error: {:?}\r", e), + None => println!("no event"), + } + } + }; } + disable_raw_mode()?; } } ImageAction::Status {