diff --git a/src/alarm.rs b/src/alarm.rs index 134b2b9..d89888f 100644 --- a/src/alarm.rs +++ b/src/alarm.rs @@ -1,20 +1,19 @@ -use std::io::Write; -use std::process::{Command, Stdio, Child}; -use std::io::BufRead; -use termion::{color, cursor, style}; -use termion::raw::RawTerminal; -use unicode_width::UnicodeWidthStr; -use crate::Config; use crate::clock::Clock; +use crate::consts::{COLOR, LABEL_SIZE_LIMIT}; use crate::layout::{Layout, Position}; use crate::utils::*; -use crate::consts::{COLOR, LABEL_SIZE_LIMIT}; +use crate::Config; +use std::io::BufRead; +use std::io::Write; +use std::process::{Child, Command, Stdio}; +use termion::raw::RawTerminal; +use termion::{color, cursor, style}; +use unicode_width::UnicodeWidthStr; // Delimiter between time and label. Remember to update usage information in // consts.rs when changing this. const DELIMITER: char = '/'; - pub struct Countdown { pub value: u32, position: Option, @@ -42,17 +41,17 @@ impl Countdown { } // Draw countdown. - pub fn draw(&self, stdout: &mut RawTerminal) - -> Result<(), std::io::Error> - { + pub fn draw(&self, stdout: &mut RawTerminal) -> Result<(), std::io::Error> { if let Some(pos) = &self.position { if self.value < 3600 { // Show minutes and seconds. - write!(stdout, + write!( + stdout, "{}(-{:02}:{:02})", cursor::Goto(pos.col, pos.line), (self.value / 60) % 60, - self.value % 60)?; + self.value % 60 + )?; if self.value == 3599 { // Write three additional spaces after switching from hour display to // minute display. @@ -60,29 +59,22 @@ impl Countdown { } } else { // Show hours, minutes and seconds. - write!(stdout, + write!( + stdout, "{}(-{:02}:{:02}:{:02})", cursor::Goto(pos.col, pos.line), self.value / 3600, (self.value / 60) % 60, - self.value % 60)?; + self.value % 60 + )?; } } Ok(()) } - pub fn place( - &mut self, - layout: &Layout, - alarm: &Alarm, - offset: usize, - index: usize, - ) { + pub fn place(&mut self, layout: &Layout, alarm: &Alarm, offset: usize, index: usize) { // Compute position. - let mut col = - layout.roster.col - + 3 - + UnicodeWidthStr::width(alarm.label.as_str()) as u16; + let mut col = layout.roster.col + 3 + UnicodeWidthStr::width(alarm.label.as_str()) as u16; let mut line = layout.roster.line + index as u16; // Compensate for "hidden" items in the alarm roster. @@ -176,8 +168,12 @@ impl AlarmRoster { } // Skip if time is out of boundaries. - if time == 0 { return Err("Evaluates to zero.") }; - if time >= 24 * 60 * 60 { return Err("Values >24h not supported.") }; + if time == 0 { + return Err("Evaluates to zero."); + }; + if time >= 24 * 60 * 60 { + return Err("Values >24h not supported."); + }; // Filter out double entries. if self.list.iter().any(|a| a.time == time) { return Err("Already exists."); @@ -208,7 +204,11 @@ impl AlarmRoster { // Offset ceiling according to layout information. fn adjust_offset(&mut self, layout: &Layout) { - self.offset = self.offset.min(self.list.len().saturating_sub(layout.roster_height as usize)); + self.offset = self.offset.min( + self.list + .len() + .saturating_sub(layout.roster_height as usize), + ); } // Check for active alarms. @@ -217,30 +217,38 @@ impl AlarmRoster { } pub fn scroll_up(&mut self, layout: &Layout) { - let excess = self.list.len().saturating_sub(layout.roster_height as usize); + let excess = self + .list + .len() + .saturating_sub(layout.roster_height as usize); self.offset = excess.min(self.offset.saturating_sub(1)); } pub fn scroll_down(&mut self, layout: &Layout) { - let excess = self.list.len().saturating_sub(layout.roster_height as usize); + let excess = self + .list + .len() + .saturating_sub(layout.roster_height as usize); self.offset = excess.min(self.offset.saturating_add(1)); } // Find and process exceeded alarms. - pub fn check(&mut self, + pub fn check( + &mut self, clock: &mut Clock, layout: &Layout, countdown: &mut Countdown, force_redraw: bool, - ) -> Option<&Alarm> - { + ) -> Option<&Alarm> { let mut ret = None; - for (index, alarm) in self.list.iter_mut() + for (index, alarm) in self + .list + .iter_mut() .enumerate() // Ignore alarms marked exceeded. - .filter(|(_, a)| !a.exceeded) { - + .filter(|(_, a)| !a.exceeded) + { if alarm.time <= clock.elapsed { // Found alarm to raise. alarm.exceeded = true; @@ -267,35 +275,41 @@ impl AlarmRoster { stdout: &mut RawTerminal, layout: &mut Layout, config: &Config, - ) -> Result<(), std::io::Error> - { + ) -> Result<(), std::io::Error> { // Match offset to layout. self.adjust_offset(&layout); - for (i, alarm) in self.list.iter() - .skip(self.offset) - .enumerate() - { + for (i, alarm) in self.list.iter().skip(self.offset).enumerate() { // Add 1 to compensate for the line "[...]". let line = layout.roster.line + i as u16; if self.offset > 0 && i == 0 { // Indicate hidden items at top. - write!(stdout, + write!( + stdout, "{}{}{}{}", cursor::Goto(layout.roster.col, line), style::Faint, - if config.fancy { "╶╴▲╶╴" } else { "[ ^ ]" }, + if config.fancy { + "╶╴▲╶╴" + } else { + "[ ^ ]" + }, style::Reset, )?; continue; } else if i == layout.roster_height as usize { // Indicate hidden items at bottom. - write!(stdout, + write!( + stdout, "{}{}{}{}", cursor::Goto(layout.roster.col, line), style::Faint, - if config.fancy { "╶╴▼╶╴" } else { "[ v ]" }, + if config.fancy { + "╶╴▼╶╴" + } else { + "[ v ]" + }, style::Reset, )?; break; @@ -303,7 +317,8 @@ impl AlarmRoster { match alarm.exceeded { true if config.fancy => { - write!(stdout, + write!( + stdout, "{}{}{}{} {} {}🭬{}{}", cursor::Goto(layout.roster.col, line), color::Fg(COLOR[alarm.color_index]), @@ -314,18 +329,20 @@ impl AlarmRoster { color::Fg(color::Reset), style::Reset, )?; - }, + } false if config.fancy => { - write!(stdout, + write!( + stdout, "{}{}█🭬{}{}", cursor::Goto(layout.roster.col, line), color::Fg(COLOR[alarm.color_index]), color::Fg(color::Reset), &alarm.label, )?; - }, + } true => { - write!(stdout, + write!( + stdout, "{}{}{}{} {} {}{}", cursor::Goto(layout.roster.col, line), color::Fg(COLOR[alarm.color_index]), @@ -335,16 +352,17 @@ impl AlarmRoster { color::Fg(color::Reset), style::Reset, )?; - }, + } false => { - write!(stdout, + write!( + stdout, "{}{} {} {}", cursor::Goto(layout.roster.col, line), color::Bg(COLOR[alarm.color_index]), color::Bg(color::Reset), &alarm.label, )?; - }, + } } } Ok(()) @@ -355,10 +373,16 @@ impl AlarmRoster { let mut width: u16 = 0; for alarm in &self.list { let length = UnicodeWidthStr::width(alarm.label.as_str()) as u16; - if length > width { width = length }; + if length > width { + width = length + }; } // Actual width is 4 columns wider if it's not 0. - if width == 0 { 0 } else { width.saturating_add(4) } + if width == 0 { + 0 + } else { + width.saturating_add(4) + } } // Reset every alarm. @@ -383,19 +407,14 @@ impl AlarmRoster { } // Read alarm times from stdin. - pub fn from_stdin(&mut self, stdin: std::io::Stdin) - -> Result<(), String> - { + pub fn from_stdin(&mut self, stdin: std::io::Stdin) -> Result<(), String> { for line in stdin.lock().lines() { match line { - Ok(line) - if !line.starts_with('#') - && !line.trim().is_empty() - => { + Ok(line) if !line.starts_with('#') && !line.trim().is_empty() => { if let Err(e) = self.add(&line) { return Err(format!("Value \"{}\": {}", line, e)); } - }, + } Ok(_) => (), // Discard comments and empty lines. Err(e) => return Err(e.to_string()), } @@ -409,7 +428,12 @@ pub fn exec_command(command: &Vec, elapsed: u32, label: &String) -> Opti let time = if elapsed < 3600 { format!("{:02}:{:02}", elapsed / 60, elapsed % 60) } else { - 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(); @@ -423,7 +447,8 @@ pub fn exec_command(command: &Vec, elapsed: u32, label: &String) -> Opti .args(args) .stdout(Stdio::null()) .stdin(Stdio::null()) - .spawn() { + .spawn() + { Ok(child) => Some(child), Err(error) => { eprintln!("Error: Could not execute command. ({})", error); @@ -431,4 +456,3 @@ pub fn exec_command(command: &Vec, elapsed: u32, label: &String) -> Opti } } } - diff --git a/src/buffer.rs b/src/buffer.rs index 4ab3a03..0964893 100644 --- a/src/buffer.rs +++ b/src/buffer.rs @@ -1,15 +1,14 @@ extern crate unicode_segmentation; -use std::io::Write; -use termion::{clear, cursor, color}; -use termion::raw::RawTerminal; use crate::layout::Layout; -use unicode_width::UnicodeWidthStr; +use std::io::Write; +use termion::raw::RawTerminal; +use termion::{clear, color, cursor}; use unicode_segmentation::UnicodeSegmentation; +use unicode_width::UnicodeWidthStr; const PROMPT: &str = "Add alarm: "; - // Input buffer. pub struct Buffer { content: String, @@ -50,8 +49,7 @@ impl Buffer { pub fn strip_word(&mut self) { // Reset error message. self.message = None; - let iter = UnicodeSegmentation::split_word_bound_indices( - self.content.as_str().trim_end()); + let iter = UnicodeSegmentation::split_word_bound_indices(self.content.as_str().trim_end()); if let Some((index, _)) = iter.last() { self.content.truncate(index); @@ -78,54 +76,55 @@ impl Buffer { &mut self, stdout: &mut RawTerminal, layout: &mut Layout, - ) -> Result<(), std::io::Error> - { + ) -> Result<(), std::io::Error> { // Write error message if present and return. if let Some(msg) = self.message { - write!(stdout, + write!( + stdout, "{}{}{}{}{}{}{}", cursor::Hide, - cursor::Goto( layout.buffer.col, layout.buffer.line), + cursor::Goto(layout.buffer.col, layout.buffer.line), clear::CurrentLine, PROMPT, color::Fg(color::LightRed), &msg, - color::Fg(color::Reset))?; + color::Fg(color::Reset) + )?; return Ok(()); } if self.content.is_empty() { // Clear buffer display. - write!(stdout, + write!( + stdout, "{}{}{}", cursor::Goto(layout.buffer.col, layout.buffer.line), clear::CurrentLine, - cursor::Hide)?; + cursor::Hide + )?; } else { // Check if buffer exceeds limits. - while UnicodeWidthStr::width(self.content.as_str()) - + UnicodeWidthStr::width(PROMPT) + while UnicodeWidthStr::width(self.content.as_str()) + UnicodeWidthStr::width(PROMPT) > layout.width as usize { self.content.pop(); } - write!(stdout, + write!( + stdout, "{}{}{}{}{}", cursor::Goto(layout.buffer.col, layout.buffer.line), clear::CurrentLine, PROMPT, cursor::Show, - &self.content)?; + &self.content + )?; } Ok(()) } // Draw error message at input buffer position. - pub fn message( - &mut self, - msg: &'static str, - ) { + pub fn message(&mut self, msg: &'static str) { self.message = Some(msg); } } diff --git a/src/clock.rs b/src/clock.rs index ae0eec7..3dfd2b1 100644 --- a/src/clock.rs +++ b/src/clock.rs @@ -1,12 +1,12 @@ pub mod font; -use std::time; -use std::io::Write; -use termion::{color, cursor, style}; -use termion::raw::RawTerminal; use crate::consts::COLOR; -use crate::Config; use crate::layout::{Layout, Position}; +use crate::Config; +use std::io::Write; +use std::time; +use termion::raw::RawTerminal; +use termion::{color, cursor, style}; enum Pause { Instant(time::Instant), @@ -60,10 +60,10 @@ impl Clock { if let Some(start) = self.start.checked_add(delay.elapsed()) { self.start = start; } - }, + } Pause::Time((secs, _days)) => { self.start = time::Instant::now() - time::Duration::from_secs(secs as u64); - }, + } Pause::None => (), // O_o } @@ -126,8 +126,7 @@ impl Clock { mut stdout: &mut RawTerminal, layout: &Layout, force_redraw: bool, - ) -> Result<(), std::io::Error> - { + ) -> Result<(), std::io::Error> { // Setup style and color if appropriate. if self.paused { write!(stdout, "{}", style::Faint)?; @@ -140,17 +139,10 @@ impl Clock { if force_redraw || self.elapsed % 3600 == 0 { // Draw hours if necessary. if self.elapsed >= 3600 { - self.draw_digit_pair( - &mut stdout, - self.elapsed / 3600, - &layout.clock_hr, - )?; + self.draw_digit_pair(&mut stdout, self.elapsed / 3600, &layout.clock_hr)?; // Draw colon. - self.draw_colon( - &mut stdout, - &layout.clock_colon1, - )?; + self.draw_colon(&mut stdout, &layout.clock_colon1)?; } // Draw days. @@ -161,12 +153,10 @@ impl Clock { if self.days == 1 { "DAY" } else { "DAYS" }, ); - write!(stdout, + write!( + stdout, "{}{:>11}", - cursor::Goto( - layout.clock_days.col, - layout.clock_days.line, - ), + cursor::Goto(layout.clock_days.col, layout.clock_days.line,), day_count, )?; } @@ -174,35 +164,20 @@ impl Clock { // Draw minutes if necessary. Once every minute or on request. if force_redraw || self.elapsed % 60 == 0 { - self.draw_digit_pair( - &mut stdout, - (self.elapsed % 3600) / 60, - &layout.clock_min, - )?; + self.draw_digit_pair(&mut stdout, (self.elapsed % 3600) / 60, &layout.clock_min)?; } // Draw colon if necessary. if force_redraw { - self.draw_colon( - &mut stdout, - &layout.clock_colon0, - )?; + self.draw_colon(&mut stdout, &layout.clock_colon0)?; } // Draw seconds. - self.draw_digit_pair( - &mut stdout, - self.elapsed % 60, - &layout.clock_sec, - )?; + self.draw_digit_pair(&mut stdout, self.elapsed % 60, &layout.clock_sec)?; // Reset color and style. if self.paused || self.color_index != None { - write!(stdout, - "{}{}", - style::NoFaint, - color::Fg(color::Reset), - )?; + write!(stdout, "{}{}", style::NoFaint, color::Fg(color::Reset),)?; } Ok(()) } @@ -212,13 +187,13 @@ impl Clock { stdout: &mut RawTerminal, value: u32, pos: &Position, - ) -> Result<(), std::io::Error> - { + ) -> Result<(), std::io::Error> { let left = self.font.digits[value as usize / 10].iter(); let right = self.font.digits[value as usize % 10].iter(); for (i, (left, right)) in left.zip(right).enumerate() { - write!(stdout, + write!( + stdout, "{}{} {}", cursor::Goto(pos.col, pos.line + i as u16), left, @@ -233,9 +208,9 @@ impl Clock { &self, stdout: &mut RawTerminal, pos: &Position, - ) -> Result<(), std::io::Error> - { - write!(stdout, + ) -> Result<(), std::io::Error> { + write!( + stdout, "{}{}{}{}", cursor::Goto(pos.col, pos.line + 1), self.font.dots.0, @@ -245,4 +220,3 @@ impl Clock { Ok(()) } } - diff --git a/src/clock/font.rs b/src/clock/font.rs index c3d8548..9deee3c 100644 --- a/src/clock/font.rs +++ b/src/clock/font.rs @@ -1,4 +1,3 @@ - const DIGIT_HEIGHT: u16 = 5; pub struct Font { @@ -12,230 +11,262 @@ pub const NORMAL: Font = Font { height: DIGIT_HEIGHT, width: 5, dots: ('■', '■'), - digits: [[ - // 0 - "█▀▀▀█", - "█ █", - "█ █", - "█ █", - "█▄▄▄█", - ], [ - // 1 - " ▀█ ", - " █ ", - " █ ", - " █ ", - " █ " - ], [ - // 2 - "▀▀▀▀█", - " █", - "█▀▀▀▀", - "█ ", - "█▄▄▄▄" - ], [ - // 3 - "▀▀▀▀█", - " █", - " ▀▀▀█", - " █", - "▄▄▄▄█" - ], [ - // 4 - "█ ", - "█ █ ", - "▀▀▀█▀", - " █ ", - " █ " - ], [ - // 5 - "█▀▀▀▀", - "█ ", - "▀▀▀▀█", - " █", - "▄▄▄▄█" - ], [ - // 6 - "█ ", - "█ ", - "█▀▀▀█", - "█ █", - "█▄▄▄█" - ], [ - // 7 - "▀▀▀▀█", - " █", - " █ ", - " █ ", - " █ ", - ], [ - // 8 - "█▀▀▀█", - "█ █", - "█▀▀▀█", - "█ █", - "█▄▄▄█" - ], [ - // 9 - "█▀▀▀█", - "█ █", - "▀▀▀▀█", - " █", - " █" - ]], + digits: [ + [ + // 0 + "█▀▀▀█", + "█ █", + "█ █", + "█ █", + "█▄▄▄█", + ], + [ + // 1 + " ▀█ ", + " █ ", + " █ ", + " █ ", + " █ ", + ], + [ + // 2 + "▀▀▀▀█", + " █", + "█▀▀▀▀", + "█ ", + "█▄▄▄▄", + ], + [ + // 3 + "▀▀▀▀█", + " █", + " ▀▀▀█", + " █", + "▄▄▄▄█", + ], + [ + // 4 + "█ ", + "█ █ ", + "▀▀▀█▀", + " █ ", + " █ ", + ], + [ + // 5 + "█▀▀▀▀", + "█ ", + "▀▀▀▀█", + " █", + "▄▄▄▄█", + ], + [ + // 6 + "█ ", + "█ ", + "█▀▀▀█", + "█ █", + "█▄▄▄█", + ], + [ + // 7 + "▀▀▀▀█", + " █", + " █ ", + " █ ", + " █ ", + ], + [ + // 8 + "█▀▀▀█", + "█ █", + "█▀▀▀█", + "█ █", + "█▄▄▄█", + ], + [ + // 9 + "█▀▀▀█", + "█ █", + "▀▀▀▀█", + " █", + " █", + ], + ], }; pub const PLAIN: Font = Font { height: DIGIT_HEIGHT, width: 5, dots: ('█', '█'), - digits: [[ - // 0 - "█████", - "█ █", - "█ █", - "█ █", - "█████" - ], [ - // 1 - " ██ ", - " █ ", - " █ ", - " █ ", - " █ " - ], [ - // 2 - "█████", - " █", - "█████", - "█ ", - "█████" - ], [ - // 3 - "█████", - " █", - " ████", - " █", - "█████" - ], [ - // 4 - "█ ", - "█ █ ", - "█████", - " █ ", - " █ " - ], [ - // 5 - "█████", - "█ ", - "█████", - " █", - "█████" - ], [ - // 6 - "█ ", - "█ ", - "█████", - "█ █", - "█████" - ], [ - // 7 - "█████", - " █", - " █ ", - " █ ", - " █ " - ], [ - // 8 - "█████", - "█ █", - "█████", - "█ █", - "█████" - ], [ - // 9 - "█████", - "█ █", - "█████", - " █", - " █" - ]], + digits: [ + [ + // 0 + "█████", + "█ █", + "█ █", + "█ █", + "█████", + ], + [ + // 1 + " ██ ", + " █ ", + " █ ", + " █ ", + " █ ", + ], + [ + // 2 + "█████", + " █", + "█████", + "█ ", + "█████", + ], + [ + // 3 + "█████", + " █", + " ████", + " █", + "█████", + ], + [ + // 4 + "█ ", + "█ █ ", + "█████", + " █ ", + " █ ", + ], + [ + // 5 + "█████", + "█ ", + "█████", + " █", + "█████", + ], + [ + // 6 + "█ ", + "█ ", + "█████", + "█ █", + "█████", + ], + [ + // 7 + "█████", + " █", + " █ ", + " █ ", + " █ ", + ], + [ + // 8 + "█████", + "█ █", + "█████", + "█ █", + "█████", + ], + [ + // 9 + "█████", + "█ █", + "█████", + " █", + " █", + ], + ], }; pub const CHROME: Font = Font { height: DIGIT_HEIGHT, width: 5, dots: ('▄', '🮏'), - digits: [[ - // 0 - "█▀▀▀█", - "█ █", - "▀ ▀", - "🮐 🮐", - "🮐🮏🮏🮏🮐", - ], [ - // 1 - " ▀█ ", - " █ ", - " ▀ ", - " 🮐 ", - " 🮐 " - ], [ - // 2 - "▀▀▀▀█", - " █", - "▀▀▀▀▀", - "🮐 ", - "🮐🮏🮏🮏🮏" - ], [ - // 3 - "▀▀▀▀█", - " █", - " ▀▀▀▀", - " 🮐", - "🮏🮏🮏🮏🮐" - ], [ - // 4 - "█ ", - "█ █ ", - "▀▀▀▀▀", - " 🮐 ", - " 🮐 " - ], [ - // 5 - "█▀▀▀▀", - "█ ", - "▀▀▀▀▀", - " 🮐", - "🮏🮏🮏🮏🮐" - ], [ - // 6 - "█ ", - "█ ", - "▀▀▀▀▀", - "🮐 🮐", - "🮐🮏🮏🮏🮐" - ], [ - // 7 - "▀▀▀▀█", - " █", - " ▀ ", - " 🮐 ", - " 🮐 ", - ], [ - // 8 - "█▀▀▀█", - "█ █", - "▀▀▀▀▀", - "🮐 🮐", - "🮐🮏🮏🮏🮐" - ], [ - // 9 - "█▀▀▀█", - "█ █", - "▀▀▀▀▀", - " 🮐", - " 🮐" - ]], + digits: [ + [ + // 0 + "█▀▀▀█", + "█ █", + "▀ ▀", + "🮐 🮐", + "🮐🮏🮏🮏🮐", + ], + [ + // 1 + " ▀█ ", + " █ ", + " ▀ ", + " 🮐 ", + " 🮐 ", + ], + [ + // 2 + "▀▀▀▀█", + " █", + "▀▀▀▀▀", + "🮐 ", + "🮐🮏🮏🮏🮏", + ], + [ + // 3 + "▀▀▀▀█", + " █", + " ▀▀▀▀", + " 🮐", + "🮏🮏🮏🮏🮐", + ], + [ + // 4 + "█ ", + "█ █ ", + "▀▀▀▀▀", + " 🮐 ", + " 🮐 ", + ], + [ + // 5 + "█▀▀▀▀", + "█ ", + "▀▀▀▀▀", + " 🮐", + "🮏🮏🮏🮏🮐", + ], + [ + // 6 + "█ ", + "█ ", + "▀▀▀▀▀", + "🮐 🮐", + "🮐🮏🮏🮏🮐", + ], + [ + // 7 + "▀▀▀▀█", + " █", + " ▀ ", + " 🮐 ", + " 🮐 ", + ], + [ + // 8 + "█▀▀▀█", + "█ █", + "▀▀▀▀▀", + "🮐 🮐", + "🮐🮏🮏🮏🮐", + ], + [ + // 9 + "█▀▀▀█", + "█ █", + "▀▀▀▀▀", + " 🮐", + " 🮐", + ], + ], }; - diff --git a/src/consts.rs b/src/consts.rs index b670ceb..1593802 100644 --- a/src/consts.rs +++ b/src/consts.rs @@ -1,4 +1,3 @@ - pub const COLOR: [&dyn termion::color::Color; 6] = [ &termion::color::LightGreen, &termion::color::LightYellow, @@ -14,8 +13,10 @@ pub const LABEL_SIZE_LIMIT: usize = 32; pub mod ui { pub const NAME: &str = env!("CARGO_PKG_NAME"); pub const VERSION: &str = env!("CARGO_PKG_VERSION"); - pub const USAGE: &str = concat!("USAGE: ", env!("CARGO_PKG_NAME"), -" [-h|-v] [-e|--exec COMMAND] [-p] [-q] [ALARM[/LABEL]] + pub const USAGE: &str = concat!( + "USAGE: ", + env!("CARGO_PKG_NAME"), + " [-h|-v] [-e|--exec COMMAND] [-p] [-q] [ALARM[/LABEL]] PARAMETERS: [ALARM TIME[/LABEL]] Any number of alarm times (HH:MM:SS) with optional @@ -32,14 +33,13 @@ OPTIONS: -q, --quit Quit program after last alarm. SIGNALS: Reset clock. - Pause or un-pause clock."); + Pause or un-pause clock." + ); pub const MENUBAR: &str = - "[0-9] Add alarm [d] Delete alarm [SPACE] Pause [r] Reset [c] Clear color [q] Quit"; + "[0-9] Add alarm [d] Delete alarm [SPACE] Pause [r] Reset [c] Clear color [q] Quit"; pub const MENUBAR_SHORT: &str = - "[0-9] Add [d] Delete [SPACE] Pause [r] Reset [c] Clear [q] Quit"; + "[0-9] Add [d] Delete [SPACE] Pause [r] Reset [c] Clear [q] Quit"; pub const MENUBAR_INS: &str = - "Format: HH:MM:SS/LABEL [ENTER] Accept [ESC] Cancel [CTR-C] Quit"; - pub const MENUBAR_PAUSED: &str = - "[SPACE] Continue [r] Reset [UP]/[DOWN] Set clock"; + "Format: HH:MM:SS/LABEL [ENTER] Accept [ESC] Cancel [CTR-C] Quit"; + pub const MENUBAR_PAUSED: &str = "[SPACE] Continue [r] Reset [UP]/[DOWN] Set clock"; } - diff --git a/src/layout.rs b/src/layout.rs index e7dfe89..d3d4338 100644 --- a/src/layout.rs +++ b/src/layout.rs @@ -8,13 +8,13 @@ pub struct Position { impl Position { // Terminal positions are 1-based. pub fn new() -> Position { - Position {col: 1, line: 1} + Position { col: 1, line: 1 } } } pub struct Layout { pub force_redraw: bool, // Redraw elements on screen. - force_recalc: bool, // Recalculate position of elements. + force_recalc: bool, // Recalculate position of elements. pub width: u16, pub height: u16, clock_width: u16, @@ -48,7 +48,7 @@ impl Layout { clock_colon1: Position::new(), clock_hr: Position::new(), clock_days: Position::new(), - roster: Position {col: 1, line: 3}, + roster: Position { col: 1, line: 3 }, roster_width: 0, roster_height: 0, buffer: Position::new(), @@ -56,9 +56,7 @@ impl Layout { } // Update layout. Returns true when changes were made. - pub fn update(&mut self, clock: &Clock, force: bool) - -> Result - { + pub fn update(&mut self, clock: &Clock, force: bool) -> Result { if self.force_recalc || force { self.force_recalc = false; let (width, height) = termion::terminal_size()?; @@ -79,13 +77,7 @@ impl Layout { } #[cfg(test)] - pub fn test_update( - &mut self, - clock: &Clock, - width: u16, - height: u16, - roster_width: u16, - ) { + pub fn test_update(&mut self, clock: &Clock, width: u16, height: u16, roster_width: u16) { self.width = width; self.height = height; self.clock_width = clock.get_width(); @@ -104,7 +96,9 @@ impl Layout { // terminal. fn compute(&mut self, display_hours: bool) { // Prevent integer overflow at very low screen sizes. - if self.width < self.clock_width || self.height < self.clock_height { return; } + if self.width < self.clock_width || self.height < self.clock_height { + return; + } let middle: u16 = self.height / 2 - 1; @@ -163,4 +157,3 @@ impl Layout { } } } - diff --git a/src/lib.rs b/src/lib.rs index ad83bc6..28ee418 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,36 +1,34 @@ -extern crate termion; extern crate signal_hook; +extern crate termion; pub mod alarm; mod buffer; pub mod clock; pub mod consts; pub mod layout; -pub mod utils; #[cfg(test)] mod tests; +pub mod utils; -use std::{env, process, thread, time}; -use std::io::Write; +pub use alarm::AlarmRoster; +use alarm::{exec_command, Countdown}; +use buffer::Buffer; +use clock::{font, Clock}; +pub use consts::ui::*; +use layout::Layout; use signal_hook::consts::signal::*; use signal_hook::iterator::Signals; use signal_hook::low_level; -use termion::{clear, cursor, style}; -use termion::raw::{IntoRawMode, RawTerminal}; +use std::io::Write; +use std::{env, process, thread, time}; use termion::event::Key; use termion::input::TermRead; -use buffer::Buffer; -use clock::{Clock, font}; -use layout::Layout; -use alarm::{Countdown, exec_command}; -pub use alarm::AlarmRoster; -pub use consts::ui::*; - +use termion::raw::{IntoRawMode, RawTerminal}; +use termion::{clear, cursor, style}; pub fn run( config: Config, mut alarm_roster: AlarmRoster, -) -> Result, std::io::Error> -{ +) -> Result, std::io::Error> { let mut layout = Layout::new(); // Initialise roster_width. layout.set_roster_width(alarm_roster.width()); @@ -47,13 +45,7 @@ pub fn run( // Register signals. let mut signals = Signals::new(&[ - SIGTSTP, - SIGCONT, - SIGWINCH, - SIGTERM, - SIGINT, - SIGUSR1, - SIGUSR2, + SIGTSTP, SIGCONT, SIGWINCH, SIGTERM, SIGINT, SIGUSR1, SIGUSR2, ])?; // Main loop entry. @@ -67,7 +59,7 @@ pub fn run( SIGCONT => { restore_after_suspend(&mut stdout)?; force_redraw = true; - }, + } SIGWINCH => layout.schedule_recalc(), // Exit main loop on SIGTERM and SIGINT. SIGTERM | SIGINT => break 'outer, @@ -77,12 +69,12 @@ pub fn run( alarm_roster.reset_all(); layout.schedule_recalc(); force_redraw = true; - }, + } // (Un-)Pause clock on SIGUSR2. SIGUSR2 => { clock.toggle(); force_redraw = true; - }, + } // We didn't register anything else. _ => unreachable!(), } @@ -90,16 +82,16 @@ pub fn run( // Update elapsed time. let elapsed = if clock.paused { - clock.elapsed - } else { - // Should never overflow as we reestablish a new "start" - // instant every 24 hours. - clock.start.elapsed().as_secs() as u32 - }; + clock.elapsed + } else { + // Should never overflow as we reestablish a new "start" + // instant every 24 hours. + clock.start.elapsed().as_secs() as u32 + }; // Conditional inner loop. Runs once every second or when explicitly // requested. - if elapsed != clock.elapsed || force_redraw { + if elapsed != clock.elapsed || force_redraw { // Update clock. Advance one day after 24 hours. if elapsed < 24 * 60 * 60 { clock.elapsed = elapsed; @@ -127,25 +119,25 @@ pub fn run( Ok(Some(status)) if status.success() => child = None, // Abnormal exit. Ok(Some(status)) => { - eprintln!("Spawned process terminated with non-zero exit status. ({})", status); + eprintln!( + "Spawned process terminated with non-zero exit status. ({})", + status + ); child = None; - }, + } // Process is still running. Ok(None) => (), // Other error. Err(error) => { eprintln!("Error executing command. ({})", error); child = None; - }, + } } } // Check for exceeded alarms. - if let Some(alarm) = alarm_roster.check( - &mut clock, - &layout, - &mut countdown, - force_redraw) + if let Some(alarm) = + alarm_roster.check(&mut clock, &layout, &mut countdown, force_redraw) { // Do not react to exceeded alarms if the clock is paused. if !clock.paused { @@ -158,13 +150,17 @@ pub fn run( // Run command if configured and no command is running. Some(ref command) if child.is_none() => { child = exec_command(command, alarm.time, &alarm.label); - }, + } // Last command is still running. - Some(_) => eprintln!("Not executing command, as its predecessor 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; + }; } } @@ -172,7 +168,8 @@ pub fn run( // requested. if force_redraw { // Write menu at the top. - write!(stdout, + write!( + stdout, "{}{}{}{}{}", cursor::Goto(1, 1), style::Faint, @@ -189,7 +186,8 @@ pub fn run( _ => " ", }, clear::AfterCursor, - style::NoFaint)?; + style::NoFaint + )?; // Redraw list of alarms. alarm_roster.draw(&mut stdout, &mut layout, &config)?; @@ -234,13 +232,13 @@ pub fn run( buffer.visible = false; force_redraw = true; } - }, + } // Escape and ^U clear input buffer. Key::Esc | Key::Ctrl('u') => { buffer.reset(); buffer.visible = false; force_redraw = true; - }, + } // ^W removes last word. Key::Ctrl('w') => { buffer.strip_word(); @@ -248,7 +246,7 @@ pub fn run( buffer.visible = false; force_redraw = true; } - }, + } // Backspace. Key::Backspace => { // Delete last char in buffer. @@ -257,7 +255,7 @@ pub fn run( buffer.visible = false; force_redraw = true; } - }, + } // Set clock. Key::Up if clock.paused => { clock.shift(10); @@ -267,43 +265,43 @@ pub fn run( // here. layout.schedule_recalc(); force_redraw = true; - }, + } Key::Down if clock.paused => { clock.shift(-10); alarm_roster.time_travel(&mut clock); layout.schedule_recalc(); force_redraw = true; - }, + } // Scroll alarm roster. Key::PageUp => { alarm_roster.scroll_up(&layout); force_redraw = true; - }, + } Key::PageDown => { alarm_roster.scroll_down(&layout); force_redraw = true; - }, + } // Forward every char if in insert mode. Key::Char(c) if buffer.visible => { buffer.push(c); - }, + } // Reset clock on 'r'. Key::Char('r') => { clock.reset(); alarm_roster.reset_all(); layout.schedule_recalc(); force_redraw = true; - }, + } // (Un-)Pause on space. Key::Char(' ') => { clock.toggle(); force_redraw = true; - }, + } // Clear clock color on 'c'. Key::Char('c') => { clock.color_index = None; force_redraw = true; - }, + } // Delete last alarm on 'd'. Key::Char('d') => { if alarm_roster.pop().is_some() { @@ -313,7 +311,7 @@ pub fn run( countdown.reset(); force_redraw = true; } - }, + } // Exit on q and ^C. Key::Char('q') | Key::Ctrl('c') => break, // Force redraw on ^R. @@ -327,7 +325,7 @@ pub fn run( force_redraw = true; // Jump to the start of the main loop. continue; - }, + } Key::Char(c) => { if c.is_ascii_digit() { buffer.push(c); @@ -336,7 +334,7 @@ pub fn run( } else if !buffer.is_empty() && c == ':' { buffer.push(':'); } - }, + } // Any other key. _ => (), } @@ -347,11 +345,7 @@ pub fn run( } // Main loop exited. Clear screen and restore cursor. - write!(stdout, - "{}{}{}", - clear::All, - cursor::Restore, - cursor::Show)?; + write!(stdout, "{}{}{}", clear::All, cursor::Restore, cursor::Show)?; stdout.flush()?; Ok(child) @@ -366,9 +360,7 @@ pub struct Config { impl Config { // Parse command line arguments into "config". - pub fn new(args: env::Args, alarm_roster: &mut AlarmRoster) - -> Result - { + pub fn new(args: env::Args, alarm_roster: &mut AlarmRoster) -> Result { let mut config = Config { quit: false, fancy: false, @@ -384,16 +376,16 @@ impl Config { // Print usage information and exit println!("{}", USAGE); process::exit(0); - }, + } "-v" | "--version" => { println!("{} {}", NAME, VERSION); process::exit(0); - }, + } "-p" | "--plain" => config.font = &font::PLAIN, "-f" | "--fancy" => { config.fancy = true; config.font = &font::CHROME; - }, + } "-q" | "--quit" => config.quit = true, "-e" | "--exec" => { if let Some(e) = iter.next() { @@ -401,19 +393,21 @@ impl Config { } else { return Err(format!("Missing parameter to \"{}\".", arg)); } - }, + } any if any.starts_with('-') => { // Unrecognized flag. return Err(format!("Unrecognized option: \"{}\"\nUse \"-h\" or \"--help\" for a list of valid command line options.", any)); - }, + } any => { // Alarm to add. if let Err(error) = alarm_roster.add(&String::from(any)) { return Err(format!("Error adding \"{}\" as alarm. ({})", any, error)); } - }, + } } - } else { break; } // All command line parameters processed. + } else { + break; + } // All command line parameters processed. } Ok(config) } @@ -432,23 +426,27 @@ impl Config { // Next char is escaped. (If not escaped itself.) escaped = true; continue; - }, + } // Keep spaces when escaped or quoted. - ' ' if escaped || quoted => { &segment.push(' '); }, + ' ' if escaped || quoted => { + &segment.push(' '); + } // Otherwise end the current segment. ' ' => { if !&segment.is_empty() { command.push(segment.clone()); &segment.clear(); } - }, + } // Quotation marks toggle quote. '"' | '\'' if !escaped => quoted = !quoted, // Carry everything else. Escape if found escaped. _ => { - if escaped { &segment.push('\\'); } + if escaped { + &segment.push('\\'); + } &segment.push(c); - }, + } } escaped = false; } @@ -459,19 +457,21 @@ impl Config { } // Prepare to suspend execution. Called on SIGTSTP. -fn suspend(stdout: &mut RawTerminal) - -> Result<(), std::io::Error> -{ - write!(stdout, +fn suspend(stdout: &mut RawTerminal) -> Result<(), std::io::Error> { + write!( + stdout, "{}{}{}", - cursor::Goto(1,1), + cursor::Goto(1, 1), clear::AfterCursor, - cursor::Show)?; + cursor::Show + )?; stdout.flush()?; - stdout.suspend_raw_mode() - .unwrap_or_else(|error| { - eprintln!("Failed to leave raw terminal mode prior to suspend: {}", error); - }); + stdout.suspend_raw_mode().unwrap_or_else(|error| { + eprintln!( + "Failed to leave raw terminal mode prior to suspend: {}", + error + ); + }); if let Err(error) = low_level::emulate_default_handler(SIGTSTP as i32) { eprintln!("Error raising SIGTSTP: {}", error); @@ -482,14 +482,13 @@ fn suspend(stdout: &mut RawTerminal) } // Set up terminal after SIGTSTP or SIGSTOP. -fn restore_after_suspend(stdout: &mut RawTerminal) - -> Result<(), std::io::Error> -{ - stdout.activate_raw_mode() - .unwrap_or_else(|error| { - eprintln!("Failed to re-enter raw terminal mode after suspend: {}", error); - process::exit(1); - }); +fn restore_after_suspend(stdout: &mut RawTerminal) -> Result<(), std::io::Error> { + stdout.activate_raw_mode().unwrap_or_else(|error| { + eprintln!( + "Failed to re-enter raw terminal mode after suspend: {}", + error + ); + process::exit(1); + }); Ok(()) } - diff --git a/src/main.rs b/src/main.rs index 645fca4..3eb1662 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,16 +1,14 @@ +use kitchentimer::{run, AlarmRoster, Config}; use std::{env, process}; -use kitchentimer::{Config, AlarmRoster, run}; - fn main() { let args = env::args(); let mut alarm_roster = AlarmRoster::new(); // Parse command line arguments into config and alarm roster. - let config = Config::new(args, &mut alarm_roster) - .unwrap_or_else(|e| { - eprintln!("{}", e); - process::exit(1); - }); + let config = Config::new(args, &mut alarm_roster).unwrap_or_else(|e| { + eprintln!("{}", e); + process::exit(1); + }); // Read alarm times from stdin if stdin is not a tty. let stdin = std::io::stdin(); @@ -27,12 +25,15 @@ fn main() { Err(error) => { eprintln!("Main loop exited with error: {}", error); process::exit(1); - }, + } }; // Wait for remaining spawned process to exit. if let Some(mut child) = child { - eprint!("Waiting for spawned process (PID {}) to finish ...", child.id()); + eprint!( + "Waiting for spawned process (PID {}) to finish ...", + child.id() + ); match child.wait() { Ok(status) if status.success() => eprintln!(" ok"), @@ -43,5 +44,3 @@ fn main() { } } } - - diff --git a/src/tests.rs b/src/tests.rs index 3105d00..9b5b84c 100644 --- a/src/tests.rs +++ b/src/tests.rs @@ -1,5 +1,5 @@ -use crate::layout::Layout; use crate::clock::Clock; +use crate::layout::Layout; use crate::Config; fn default_config() -> Config { diff --git a/src/utils.rs b/src/utils.rs index 354f934..43a5302 100644 --- a/src/utils.rs +++ b/src/utils.rs @@ -6,8 +6,7 @@ pub fn grapheme_truncate(input: &mut String, limit: usize, ellipse: char) { Some((i, _)) => { input.truncate(i); input.push(ellipse); - }, + } None => (), } } -