accept a command to run when the timer ends

This commit is contained in:
race604 2022-08-04 23:21:20 +08:00
parent 684384c3ee
commit 254b6c84cf
2 changed files with 52 additions and 4 deletions

View file

@ -27,12 +27,17 @@ pub(crate) enum Mode {
}, },
/// The timer mode displays the remaining time until the timer is finished. /// The timer mode displays the remaining time until the timer is finished.
Timer { Timer {
/// Initial duration for timer, value can be 10s for 10 seconds, 1m for 1 minute, etc.
#[clap(short, long, value_parser = parse_duration, default_value = "5m")] #[clap(short, long, value_parser = parse_duration, default_value = "5m")]
duration: Duration, duration: Duration,
/// Hide milliseconds /// Hide milliseconds
#[clap(long = "no-millis", short = 'M', takes_value = false)] #[clap(long = "no-millis", short = 'M', takes_value = false)]
no_millis: bool, no_millis: bool,
/// Command to run when the timer ends
#[clap(long, short, multiple = true, allow_hyphen_values = true)]
execute: Vec<String>,
}, },
/// The stopwatch mode displays the elapsed time since it was started. /// The stopwatch mode displays the elapsed time since it was started.
Stopwatch, Stopwatch,
@ -79,13 +84,20 @@ impl App {
Mode::Timer { Mode::Timer {
duration, duration,
no_millis, no_millis,
execute,
} => { } => {
let format = if *no_millis { let format = if *no_millis {
DurationFormat::HourMinSec DurationFormat::HourMinSec
} else { } else {
DurationFormat::HourMinSecDeci DurationFormat::HourMinSecDeci
}; };
self.timer = Some(Timer::new(duration.to_owned(), self.size, style, format)); self.timer = Some(Timer::new(
duration.to_owned(),
self.size,
style,
format,
execute.to_owned(),
));
} }
Mode::Stopwatch => { Mode::Stopwatch => {
self.stopwatch = Some(Stopwatch::new(self.size, style)); self.stopwatch = Some(Stopwatch::new(self.size, style));

View file

@ -1,3 +1,5 @@
use std::{cell::RefCell, process::Command};
use chrono::{DateTime, Duration, Local}; use chrono::{DateTime, Duration, Local};
use clock_tui::bricks_text::BricksText; use clock_tui::bricks_text::BricksText;
use tui::{buffer::Buffer, layout::Rect, style::Style, widgets::Widget}; use tui::{buffer::Buffer, layout::Rect, style::Style, widgets::Widget};
@ -7,19 +9,29 @@ use super::{format_duration, render_centered, DurationFormat};
pub struct Timer { pub struct Timer {
pub size: u16, pub size: u16,
pub style: Style, pub style: Style,
pub execute: Vec<String>,
format: DurationFormat, format: DurationFormat,
duration: Duration, duration: Duration,
ended_at: Option<DateTime<Local>>, ended_at: Option<DateTime<Local>>,
execute_result: RefCell<Option<String>>,
} }
impl Timer { impl Timer {
pub(crate) fn new(duration: Duration, size: u16, style: Style, format: DurationFormat) -> Self { pub(crate) fn new(
duration: Duration,
size: u16,
style: Style,
format: DurationFormat,
execute: Vec<String>,
) -> Self {
Self { Self {
duration, duration,
size, size,
execute,
style, style,
format, format,
ended_at: Some(Local::now() + duration), ended_at: Some(Local::now() + duration),
execute_result: RefCell::new(None),
} }
} }
@ -33,10 +45,10 @@ impl Timer {
self.duration = Duration::zero(); self.duration = Duration::zero();
} else { } else {
self.duration = end_at - Local::now(); self.duration = end_at - Local::now();
}
self.ended_at = None; self.ended_at = None;
} }
} }
}
pub(crate) fn resume(&mut self) { pub(crate) fn resume(&mut self) {
if self.ended_at.is_none() { if self.ended_at.is_none() {
@ -54,10 +66,34 @@ impl Timer {
} }
} }
fn execute(execute: &Vec<String>) -> String {
let mut cmd = Command::new("sh");
cmd.arg("-c");
let cmd_str = execute.join(" ");
cmd.arg(cmd_str);
let output = cmd.output();
match output {
Ok(output) => {
if !output.status.success() {
format!("[ERROR] {}", String::from_utf8_lossy(&output.stderr))
} else {
format!("[SUCCEED] {}", String::from_utf8_lossy(&output.stdout))
}
}
Err(e) => {
format!("[FAILED] {}", e)
}
}
}
impl Widget for &Timer { impl Widget for &Timer {
fn render(self, area: Rect, buf: &mut Buffer) { fn render(self, area: Rect, buf: &mut Buffer) {
let remaining_time = self.remaining_time(); let remaining_time = self.remaining_time();
let time_str = if remaining_time < Duration::zero() { let time_str = if remaining_time < Duration::zero() {
if self.execute.len() > 0 && self.execute_result.borrow().is_none() {
let result = execute(&self.execute);
*self.execute_result.borrow_mut() = Some(result);
}
if remaining_time.num_seconds() % 2 == 0 { if remaining_time.num_seconds() % 2 == 0 {
return; return;
} else { } else {
@ -71,7 +107,7 @@ impl Widget for &Timer {
let footer = if self.is_paused() { let footer = if self.is_paused() {
Some("PAUSED (press <SPACE> to resume)".to_string()) Some("PAUSED (press <SPACE> to resume)".to_string())
} else { } else {
None self.execute_result.borrow().clone()
}; };
render_centered(area, buf, &text, None, footer); render_centered(area, buf, &text, None, footer);
} }