Simple pomodoro timer for command line
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

99 lines
2.6 KiB

5 years ago
  1. use chrono::prelude::*;
  2. use chrono::Duration;
  3. use std::io::{stdout, Result, StdoutLock, Write};
  4. use std::process::{Command, Output};
  5. use std::thread::sleep;
  6. const TIME_FORMAT: &'static str = "%H:%M:%S";
  7. fn main() {
  8. run().unwrap();
  9. }
  10. /// Runs the application
  11. ///
  12. /// Default time settings are 25 minutes for a working block and 5 minutes for a break.
  13. fn run() -> Result<()> {
  14. let work_duration = Duration::seconds(if cfg!(debug_assertions) { 5 } else { 25 * 60 });
  15. let break_duration = Duration::seconds(if cfg!(debug_assertions) { 5 } else { 5 * 60 });
  16. loop {
  17. timer(
  18. "Work",
  19. "The working time is over, have a break now!",
  20. &work_duration,
  21. )?;
  22. timer(
  23. "Break",
  24. "The break is over, get back to work!",
  25. &break_duration,
  26. )?;
  27. }
  28. }
  29. /// Handles a timer block
  30. ///
  31. /// # Arguments
  32. ///
  33. /// * name - The name for this block, e.g. 'Work' or 'Break'
  34. /// * after_msg - The message to be displayed by the Dialog window at the end of the time
  35. /// * duration - How long this block shall be
  36. fn timer(name: &str, after_msg: &str, duration: &Duration) -> Result<()> {
  37. let out = stdout();
  38. let mut out = out.lock();
  39. let start = Local::now();
  40. writeln!(out, "{} start {}", name, start.format(TIME_FORMAT))?;
  41. loop {
  42. reset_line(&mut out)?;
  43. let elapsed: Duration = Local::now().signed_duration_since(start);
  44. if elapsed >= *duration {
  45. break;
  46. }
  47. let elapsed_time: NaiveTime = NaiveTime::from_hms(
  48. elapsed.num_hours() as u32,
  49. elapsed.num_minutes() as u32,
  50. elapsed.num_seconds() as u32,
  51. );
  52. write!(out, "Time elapsed: {}", elapsed_time.format(TIME_FORMAT))?;
  53. out.flush().unwrap();
  54. sleep(Duration::seconds(1).to_std().unwrap());
  55. }
  56. let now = Local::now();
  57. writeln!(out, "{} end {}", name, now.format(TIME_FORMAT))?;
  58. dialog(after_msg).unwrap();
  59. Ok(())
  60. }
  61. /// Shows a dialog
  62. ///
  63. /// Currently only supports KDE dialogs via command line program `kdialgo`.
  64. ///
  65. /// # Arguments
  66. ///
  67. /// * text - The text to be shown in the Dialog
  68. fn dialog(text: &str) -> Result<Output> {
  69. Command::new("sh")
  70. .arg("-c")
  71. .arg(format!(
  72. "kdialog --title 'Pomodoro Timer' --msgbox '{}'",
  73. text
  74. ))
  75. .output()
  76. }
  77. /// Resets the current line on stdout
  78. ///
  79. /// Works for me® but is probably unportable as hell.
  80. ///
  81. /// # Arguments
  82. ///
  83. /// * w - A reference to the locked stdout handle
  84. pub fn reset_line(w: &mut StdoutLock) -> Result<()> {
  85. write!(w, "\r[2K")
  86. }