util.rs 2.8 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889
  1. /* This file is part of DarkFi (https://dark.fi)
  2. *
  3. * Copyright (C) 2020-2022 Dyne.org foundation
  4. *
  5. * This program is free software: you can redistribute it and/or modify
  6. * it under the terms of the GNU Affero General Public License as
  7. * published by the Free Software Foundation, either version 3 of the
  8. * License, or (at your option) any later version.
  9. *
  10. * This program is distributed in the hope that it will be useful,
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  13. * GNU Affero General Public License for more details.
  14. *
  15. * You should have received a copy of the GNU Affero General Public License
  16. * along with this program. If not, see <https://www.gnu.org/licenses/>.
  17. */
  18. use std::{
  19. env,
  20. fs::{self, File},
  21. io::Write,
  22. process::Command,
  23. };
  24. use chrono::{Datelike, Local, NaiveDate};
  25. use log::error;
  26. use darkfi::{util::time::Timestamp, Result};
  27. /// Parse due date (e.g. "1503" for 15 March) as i64 timestamp.
  28. pub fn due_as_timestamp(due: &str) -> Option<i64> {
  29. if due.len() != 4 || due.parse::<u32>().is_err() {
  30. error!("Due date must be digits of length 4 (e.g. \"1503\" for 15 March)");
  31. return None
  32. }
  33. let (day, month) = (due[..2].parse::<u32>().unwrap(), due[2..].parse::<u32>().unwrap());
  34. if day > 31 || month > 12 {
  35. error!("Invalid or out-of-range date");
  36. return None
  37. }
  38. let mut year = Local::today().year();
  39. // Ensure the due date is in future
  40. if month < Local::today().month() {
  41. year += 1;
  42. }
  43. if month == Local::today().month() && day < Local::today().day() {
  44. year += 1;
  45. }
  46. let dt = NaiveDate::from_ymd(year, month, day).and_hms(12, 0, 0);
  47. Some(dt.timestamp())
  48. }
  49. /// Start up the preferred editor to edit a task's description.
  50. pub fn desc_in_editor() -> Result<Option<String>> {
  51. // Create a temporary file with some comments inside.
  52. let mut file_path = env::temp_dir();
  53. let file_name = format!("tau-{}", Timestamp::current_time().0);
  54. file_path.push(file_name);
  55. let mut file = File::create(&file_path)?;
  56. writeln!(file, "\n# Write your task description here.")?;
  57. writeln!(file, "# Lines starting with \"#\" will be removed")?;
  58. // Try $EDITOR, and if not, fallback to xdg-open.
  59. let editor_argv0 = match env::var("EDITOR") {
  60. Ok(v) => v,
  61. Err(_) => "xdg-open".into(),
  62. };
  63. Command::new(editor_argv0).arg(&file_path).status()?;
  64. // Whatever has been written in the temp file will be read here.
  65. let content = fs::read_to_string(&file_path)?;
  66. fs::remove_file(&file_path)?;
  67. let mut lines = vec![];
  68. for i in content.lines() {
  69. if !i.starts_with('#') {
  70. lines.push(i.to_string())
  71. }
  72. }
  73. Ok(Some(lines.join("\n")))
  74. }