From 3039af5aeef344e2d3b60ce22f7a7eb8d1dec364 Mon Sep 17 00:00:00 2001 From: shy Date: Wed, 14 Apr 2021 18:09:45 +0200 Subject: [PATCH] Read alarm times from stdin. --- src/alarm.rs | 66 +++++++++++++++++++++++++++++++++++----------------- src/lib.rs | 21 ++++++++--------- src/main.rs | 10 ++++++++ 3 files changed, 65 insertions(+), 32 deletions(-) diff --git a/src/alarm.rs b/src/alarm.rs index 8777652..05b711d 100644 --- a/src/alarm.rs +++ b/src/alarm.rs @@ -316,34 +316,58 @@ impl AlarmRoster { alarm.reset(); } } + + // Read alarm times from stdin. + pub fn from_stdin(&mut self, stdin: std::io::Stdin) + -> Result<(), String> + { + let mut buffer = String::new(); + loop { + match stdin.read_line(&mut buffer) { + Ok(0) => break, // EOF. + Ok(1) => continue, // Empty (newline only). + Ok(_) => (), + Err(e) => return Err(e.to_string()), + } + // Strip newline. + buffer.retain(|c| c != '\n'); + // Ignore lines containing only white spaces. + if buffer.contains(|c: char| !c.is_whitespace()) { + if let Err(e) = self.add(&buffer) { + return Err(e.to_string()); + } + } + buffer.clear(); + } + Ok(()) + } } // Execute the command given on the command line. -pub fn exec_command(config: &Config, elapsed: u32, label: &String) -> Option { - let mut args: Vec = Vec::new(); - let time: String; - - if elapsed < 3600 { - time = format!("{:02}:{:02}", elapsed / 60, elapsed % 60); +pub fn exec_command(command: &Vec, elapsed: u32, label: &String) -> Option { + let time = if elapsed < 3600 { + format!("{:02}:{:02}", elapsed / 60, elapsed % 60) } else { - time = format!("{:02}:{:02}:{:02}", elapsed /3600, (elapsed / 60) % 60, elapsed % 60); + format!("{:02}:{:02}:{:02}", elapsed /3600, (elapsed / 60) % 60, elapsed % 60) + }; + + let mut args: Vec = Vec::new(); + // Build vector of command line arguments. Replace every occurrence of + // "{t}" and "{l}". + for s in command.iter().skip(1) { + args.push(s.replace("{t}", &time).replace("{l}", &label)); } - if let Some(command) = &config.command { - // Replace every occurrence of "{}". - args.reserve_exact(command.len()); - for s in command { - args.push(s.replace("{t}", &time).replace("{l}", &label)); - } - - match Command::new(&command[0]).args(&args[1..]) - .stdout(Stdio::null()).stdin(Stdio::null()).spawn() { - Ok(child) => return Some(child), - Err(error) => { - eprintln!("Error: Could not execute command. ({})", error); - } + match Command::new(&command[0]) + .args(args) + .stdout(Stdio::null()) + .stdin(Stdio::null()) + .spawn() { + Ok(child) => Some(child), + Err(error) => { + eprintln!("Error: Could not execute command. ({})", error); + None } } - None } diff --git a/src/lib.rs b/src/lib.rs index e2d7ce7..a71e987 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -38,6 +38,7 @@ pub fn run( let mut clock = Clock::new(&config); let mut countdown = Countdown::new(); let mut buffer = Buffer::new(); + let async_stdin = termion::async_stdin(); let mut input_keys = async_stdin.keys(); let stdout = std::io::stdout(); @@ -119,19 +120,17 @@ pub fn run( write!(stdout, "{}", 0x07 as char)?; layout.force_redraw = true; - // Run command if configured. - if config.command.is_some() { - if spawned.is_none() { - *spawned = exec_command(&config, time, &label); - } else { - // The last command is still running. - eprintln!("Not executing command, as its predecessor is still running"); - } + match config.command { + // Run command if configured and no command is running. + Some(ref command) if spawned.is_none() => { + *spawned = exec_command(command, time, &label); + }, + // Last command is still running. + Some(_) => eprintln!("Not executing command, as its predecessor is still running"), + None => (), } // Quit if configured. - if config.quit && alarm_roster.idle() { - break; - } + if config.quit && alarm_roster.idle() { break }; } // Clear the window and redraw menu bar, alarm roster and buffer if diff --git a/src/main.rs b/src/main.rs index 2eb2e1c..cfc47e1 100644 --- a/src/main.rs +++ b/src/main.rs @@ -12,6 +12,16 @@ fn main() { process::exit(1); }); + // Read alarm times from stdin if stdin not a tty. + let stdin = std::io::stdin(); + if !termion::is_tty(&stdin) { + stdin.lock(); + if let Err(e) = alarm_roster.from_stdin(stdin) { + eprintln!("Error while reading alarm times from stdin. ({})", e); + process::exit(1); + } + } + // Holds spawned child process if any. let mut spawned: Option = None;