🧰 Improvements to code and dates
This commit is contained in:
parent
19e5011f27
commit
102123b688
88
src/cli.rs
88
src/cli.rs
@ -1,12 +1,14 @@
|
|||||||
use chrono::NaiveDateTime;
|
use chrono::{NaiveDateTime, Local};
|
||||||
use crate::args::{TasksArgs, Commands};
|
use crate::args::{TasksArgs, Commands};
|
||||||
use crate::args::{CreateTask, DeleteTask, ShowTask, StartTask, StopTask, CompleteTask};
|
use crate::args::{CreateTask, DeleteTask, ShowTask, StartTask, StopTask, CompleteTask};
|
||||||
use crate::tasks::{Tasks, Task, Status};
|
use crate::tasks::{Tasks, Task, Status, TasksError};
|
||||||
use prettytable::{Table, Row, row, format};
|
use prettytable::{Table, Row, row, format};
|
||||||
use colored::*;
|
use colored::*;
|
||||||
use fuzzydate;
|
use fuzzydate;
|
||||||
|
use std::panic;
|
||||||
|
|
||||||
pub fn success(msg: String) {
|
|
||||||
|
fn success(msg: String) {
|
||||||
println!("{} {}", "success:".green().bold(), msg);
|
println!("{} {}", "success:".green().bold(), msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -14,26 +16,20 @@ pub fn warning(msg: &str) {
|
|||||||
println!("{} {}", "warning:".yellow().bold(), msg);
|
println!("{} {}", "warning:".yellow().bold(), msg);
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(dead_code)]
|
pub fn info(msg: &str) {
|
||||||
pub fn error(msg: String) {
|
println!("{} {}", "info:".blue().bold(), msg);
|
||||||
println!("{} {}", "error:".red().bold(), msg);
|
|
||||||
panic!();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn task_msg(msg: &str, task: &Task, id: usize) -> String {
|
fn task_msg(msg: &str, task: &Task, id: usize) -> String {
|
||||||
format!("{} task: {}({})", msg, task.title.blue(), id.to_string().cyan())
|
format!("{} task: {}({})", msg, task.title.blue(), id.to_string().cyan())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn get_task(tasks: &mut Tasks, id: usize) -> Task {
|
|
||||||
match tasks.get_task(id) {
|
|
||||||
Ok(task) => task.clone(),
|
|
||||||
Err(error) => panic!("error: {}", error),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn parse_date(date_string: Option<String>) -> Option<NaiveDateTime> {
|
fn parse_date(date_string: Option<String>) -> Option<NaiveDateTime> {
|
||||||
if date_string.is_some() {
|
if date_string.is_some() {
|
||||||
Some(fuzzydate::parse(date_string.unwrap()).unwrap())
|
match fuzzydate::parse(date_string.unwrap()) {
|
||||||
|
Ok(date) => Some(date),
|
||||||
|
Err(err) => panic!("{:?}", err),
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
None
|
None
|
||||||
}
|
}
|
||||||
@ -44,12 +40,23 @@ fn calc_row(task: &Task, id: usize) -> Row {
|
|||||||
// Generate greyed out rows for complete tasks
|
// Generate greyed out rows for complete tasks
|
||||||
Row::from([id.to_string().bright_black().italic(),
|
Row::from([id.to_string().bright_black().italic(),
|
||||||
task.status.as_string().bright_black().italic(),
|
task.status.as_string().bright_black().italic(),
|
||||||
|
"N/A".bright_black(),
|
||||||
task.title.clone().bright_black().italic()])
|
task.title.clone().bright_black().italic()])
|
||||||
|
|
||||||
} else {
|
} else {
|
||||||
let when = if task.when.is_some() {
|
let when = if task.when.is_some() {
|
||||||
format!("{}", task.when.unwrap().format("%Y-%m-%d")).bright_black()
|
let date = format!("{}", task.when.unwrap().format("%Y-%m-%d"));
|
||||||
|
let now = Local::now().date_naive();
|
||||||
|
|
||||||
|
if now == task.when.unwrap().date() {
|
||||||
|
date.bright_red()
|
||||||
|
} else if now.succ_opt().unwrap() == task.when.unwrap().date() {
|
||||||
|
date.yellow()
|
||||||
|
} else {
|
||||||
|
date.white()
|
||||||
|
}
|
||||||
} else {
|
} else {
|
||||||
String::from("N/A").bright_black()
|
"N/A".bright_black()
|
||||||
};
|
};
|
||||||
|
|
||||||
// Generate normal colored rows for uncompleted tasks
|
// Generate normal colored rows for uncompleted tasks
|
||||||
@ -57,7 +64,7 @@ fn calc_row(task: &Task, id: usize) -> Row {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn execute(tasks: &mut Tasks, arguments: TasksArgs) -> &mut Tasks {
|
pub fn execute(tasks: &mut Tasks, arguments: TasksArgs) -> Result<&mut Tasks, TasksError> {
|
||||||
match arguments.command {
|
match arguments.command {
|
||||||
Commands::Add(CreateTask { title, notes, tags, when, deadline, reminder, ..}) => {
|
Commands::Add(CreateTask { title, notes, tags, when, deadline, reminder, ..}) => {
|
||||||
let when = parse_date(when);
|
let when = parse_date(when);
|
||||||
@ -70,53 +77,58 @@ pub fn execute(tasks: &mut Tasks, arguments: TasksArgs) -> &mut Tasks {
|
|||||||
};
|
};
|
||||||
|
|
||||||
let task = Task::new(title, notes, tags, when, deadline, reminder);
|
let task = Task::new(title, notes, tags, when, deadline, reminder);
|
||||||
tasks.add(task.clone());
|
tasks.push(task.clone());
|
||||||
|
|
||||||
let id = tasks.len() - 1;
|
let id = tasks.len() - 1;
|
||||||
success(task_msg("created", &task, id));
|
success(task_msg("created", &task, id));
|
||||||
|
|
||||||
|
Ok(tasks)
|
||||||
}
|
}
|
||||||
|
|
||||||
Commands::Del(DeleteTask { id }) => {
|
Commands::Del(DeleteTask { id }) => {
|
||||||
let task = get_task(tasks, id);
|
let mut binding = tasks.clone();
|
||||||
|
let task = binding.get_task(id)?;
|
||||||
|
tasks.remove(id)?;
|
||||||
|
|
||||||
tasks.del(id);
|
|
||||||
success(task_msg("deleted", &task, id));
|
success(task_msg("deleted", &task, id));
|
||||||
|
Ok(tasks)
|
||||||
}
|
}
|
||||||
|
|
||||||
Commands::Done(CompleteTask { id }) => {
|
Commands::Done(CompleteTask { id }) => {
|
||||||
let task = get_task(&mut tasks.clone(), id);
|
let task = tasks.get_task(id)?;
|
||||||
|
task.complete();
|
||||||
|
|
||||||
tasks.set_status(id, Status::Complete);
|
|
||||||
success(task_msg("completed", &task, id));
|
success(task_msg("completed", &task, id));
|
||||||
|
Ok(tasks)
|
||||||
}
|
}
|
||||||
|
|
||||||
Commands::Start(StartTask { id }) => {
|
Commands::Start(StartTask { id }) => {
|
||||||
let task = get_task(&mut tasks.clone(), id);
|
let task = tasks.get_task(id)?;
|
||||||
|
task.start();
|
||||||
|
|
||||||
tasks.set_status(id, Status::Active);
|
|
||||||
success(task_msg("started", &task, id));
|
success(task_msg("started", &task, id));
|
||||||
|
Ok(tasks)
|
||||||
}
|
}
|
||||||
|
|
||||||
Commands::Stop(StopTask { id }) => {
|
Commands::Stop(StopTask { id }) => {
|
||||||
let task = get_task(&mut tasks.clone(), id);
|
let task = tasks.get_task(id)?;
|
||||||
|
task.stop();
|
||||||
|
|
||||||
if task.when.is_none() {
|
|
||||||
tasks.set_status(id, Status::Inbox);
|
|
||||||
} else {
|
|
||||||
tasks.set_status(id, Status::Pending);
|
|
||||||
};
|
|
||||||
success(task_msg("stopped", &task, id));
|
success(task_msg("stopped", &task, id));
|
||||||
|
Ok(tasks)
|
||||||
}
|
}
|
||||||
|
|
||||||
Commands::Clear => {
|
Commands::Clear => {
|
||||||
tasks.clear();
|
tasks.clear()?;
|
||||||
|
|
||||||
success(String::from("cleared all tasks"));
|
success(String::from("cleared all tasks"));
|
||||||
|
Ok(tasks)
|
||||||
}
|
}
|
||||||
|
|
||||||
Commands::Show(ShowTask { id }) => {
|
Commands::Show(ShowTask { id }) => {
|
||||||
if id.is_none() {
|
if id.is_none() {
|
||||||
if tasks.tasks.is_none() {
|
if tasks.is_empty() {
|
||||||
warning("no tasks available to show")
|
info("no tasks found")
|
||||||
} else {
|
} else {
|
||||||
// Create the table for printing
|
// Create the table for printing
|
||||||
let mut table = Table::new();
|
let mut table = Table::new();
|
||||||
@ -134,8 +146,9 @@ pub fn execute(tasks: &mut Tasks, arguments: TasksArgs) -> &mut Tasks {
|
|||||||
println!("{}", table);
|
println!("{}", table);
|
||||||
};
|
};
|
||||||
} else {
|
} else {
|
||||||
|
// Get the task
|
||||||
let id = id.unwrap();
|
let id = id.unwrap();
|
||||||
let task = get_task(&mut tasks.clone(), id);
|
let task = tasks.get_task(id)?;
|
||||||
|
|
||||||
// Generate and print the table
|
// Generate and print the table
|
||||||
let mut table = Table::new();
|
let mut table = Table::new();
|
||||||
@ -144,9 +157,10 @@ pub fn execute(tasks: &mut Tasks, arguments: TasksArgs) -> &mut Tasks {
|
|||||||
table.add_row(calc_row(&task, id));
|
table.add_row(calc_row(&task, id));
|
||||||
println!("{}", table)
|
println!("{}", table)
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Ok(tasks)
|
||||||
}
|
}
|
||||||
|
|
||||||
_ => todo!()
|
_ => todo!()
|
||||||
};
|
}
|
||||||
tasks
|
|
||||||
}
|
}
|
@ -7,6 +7,7 @@ use crate::tasks::Tasks;
|
|||||||
use crate::args::TasksArgs;
|
use crate::args::TasksArgs;
|
||||||
use std::path::Path;
|
use std::path::Path;
|
||||||
use clap::Parser;
|
use clap::Parser;
|
||||||
|
use colored::*;
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
// Generate the file path for tasks
|
// Generate the file path for tasks
|
||||||
@ -22,12 +23,15 @@ fn main() {
|
|||||||
// Load tasks and check for any errors when loading the tasks
|
// Load tasks and check for any errors when loading the tasks
|
||||||
let mut tasks = match data::load_tasks(&tasks_file_path) {
|
let mut tasks = match data::load_tasks(&tasks_file_path) {
|
||||||
Ok(tasks) => tasks,
|
Ok(tasks) => tasks,
|
||||||
Err(_error) => panic!("error: couldn't open file {} - likely corrupted", &tasks_file_path),
|
Err(error) => panic!("{} {:?}", "error:".red().bold(), error),
|
||||||
};
|
};
|
||||||
|
|
||||||
// Parse command line arguments
|
// Parse command line arguments
|
||||||
let arguments = TasksArgs::parse();
|
let arguments = TasksArgs::parse();
|
||||||
let tasks = cli::execute(&mut tasks, arguments);
|
let tasks = match cli::execute(&mut tasks, arguments) {
|
||||||
|
Ok(tasks) => tasks,
|
||||||
|
Err(error) => panic!("{} {:?}", "error:".red().bold(), error),
|
||||||
|
};
|
||||||
|
|
||||||
// Save any changes
|
// Save any changes
|
||||||
data::save_tasks(tasks_file_path, &tasks).unwrap()
|
data::save_tasks(tasks_file_path, &tasks).unwrap()
|
||||||
|
124
src/tasks.rs
124
src/tasks.rs
@ -1,8 +1,11 @@
|
|||||||
use serde::{Deserialize, Serialize};
|
use serde::{Deserialize, Serialize};
|
||||||
use chrono::{NaiveDateTime, Utc};
|
use chrono::NaiveDateTime;
|
||||||
use colored::*;
|
use colored::*;
|
||||||
|
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct TasksError(String);
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
|
#[derive(Serialize, Deserialize, Debug, Clone, PartialEq)]
|
||||||
pub enum Status {
|
pub enum Status {
|
||||||
Inbox,
|
Inbox,
|
||||||
@ -11,17 +14,6 @@ pub enum Status {
|
|||||||
Complete,
|
Complete,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Status {
|
|
||||||
pub fn as_string(&self) -> ColoredString {
|
|
||||||
match self {
|
|
||||||
Status::Inbox => "📮 Inbox".blue(),
|
|
||||||
Status::Pending => "📅 Pending".yellow(),
|
|
||||||
Status::Active => "✍️ Active".red(),
|
|
||||||
Status::Complete => "📗 Complete".green(),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Serialize, Deserialize, Debug, Clone)]
|
#[derive(Serialize, Deserialize, Debug, Clone)]
|
||||||
pub struct Task {
|
pub struct Task {
|
||||||
pub title: String, // The required title of the task
|
pub title: String, // The required title of the task
|
||||||
@ -41,24 +33,29 @@ pub struct Tasks {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl Task {
|
impl Task {
|
||||||
pub fn new(title: String, notes: Option<String>, tags: Option<Vec<String>>, when: Option<NaiveDateTime>, deadline: Option<NaiveDateTime>, reminder: Option<NaiveDateTime>) -> Self {
|
pub fn new(title: String, notes: Option<String>, tags: Option<Vec<String>>,
|
||||||
let status = if when.is_some() {
|
when: Option<NaiveDateTime>, deadline: Option<NaiveDateTime>,
|
||||||
Status::Pending
|
reminder: Option<NaiveDateTime>) -> Self {
|
||||||
} else {
|
let status = if when.is_some() { Status::Pending } else { Status::Inbox };
|
||||||
Status::Inbox
|
|
||||||
};
|
|
||||||
|
|
||||||
Self {
|
Self { title, status, notes, tags, subtasks: None, when, deadline, reminder, }
|
||||||
title,
|
}
|
||||||
status,
|
|
||||||
notes,
|
pub fn start(&mut self) {
|
||||||
tags,
|
self.status = Status::Active;
|
||||||
subtasks: None,
|
}
|
||||||
when,
|
|
||||||
deadline,
|
pub fn stop(&mut self) {
|
||||||
reminder,
|
if self.when.is_none() {
|
||||||
|
self.status = Status::Inbox;
|
||||||
|
} else {
|
||||||
|
self.status = Status::Pending;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn complete(&mut self) {
|
||||||
|
self.status = Status::Complete;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Tasks {
|
impl Tasks {
|
||||||
@ -69,43 +66,78 @@ impl Tasks {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn get_task(&mut self, id: usize) -> Result<&mut Task, &str> {
|
fn task_not_found(&self, id: usize) -> TasksError {
|
||||||
if self.tasks.is_none() {
|
TasksError(format!("couldn't find task with id {}", id))
|
||||||
Err("there are no tasks")
|
}
|
||||||
|
|
||||||
|
fn task_exists(&self, id: usize) -> bool{
|
||||||
|
if id >= self.len() { false } else { true }
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn is_empty(&self) -> bool {
|
||||||
|
if self.len() == 0 {
|
||||||
|
true
|
||||||
} else {
|
} else {
|
||||||
if id >= self.tasks.as_ref().unwrap().len() {
|
false
|
||||||
Err("couldn't find task")
|
}
|
||||||
} else {
|
}
|
||||||
|
|
||||||
|
pub fn get_task(&mut self, id: usize) -> Result<&mut Task, TasksError> {
|
||||||
|
if self.is_empty() {
|
||||||
|
Err(TasksError(format!("no tasks available")))
|
||||||
|
} else {
|
||||||
|
if self.task_exists(id) {
|
||||||
let task = &mut self.tasks.as_mut().unwrap()[id];
|
let task = &mut self.tasks.as_mut().unwrap()[id];
|
||||||
Ok(task)
|
Ok(task)
|
||||||
|
} else {
|
||||||
|
Err(TasksError(format!("couldn't find task with id {}", id)))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[allow(dead_code)]
|
pub fn push(&mut self, task: Task) {
|
||||||
pub fn set_status(&mut self, id: usize, status: Status) {
|
if self.is_empty() {
|
||||||
let mut task: &mut Task = self.get_task(id).unwrap();
|
|
||||||
task.status = status;
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn add(&mut self, task: Task) {
|
|
||||||
if self.tasks.is_none() {
|
|
||||||
self.tasks = Some(vec![task]);
|
self.tasks = Some(vec![task]);
|
||||||
} else {
|
} else {
|
||||||
self.tasks.as_mut().unwrap().push(task);
|
self.tasks.as_mut().unwrap().push(task);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn del(&mut self, id: usize) {
|
pub fn remove(&mut self, id: usize) -> Result<(), TasksError> {
|
||||||
self.tasks.as_mut().unwrap().remove(id);
|
if self.task_exists(id) {
|
||||||
|
self.tasks.as_mut().unwrap().remove(id);
|
||||||
|
Ok(())
|
||||||
|
} else {
|
||||||
|
Err(self.task_not_found(id))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn len(&self) -> usize {
|
pub fn len(&self) -> usize {
|
||||||
self.tasks.as_ref().unwrap().len()
|
if self.tasks.is_none() {
|
||||||
|
0
|
||||||
|
} else {
|
||||||
|
self.tasks.as_ref().unwrap().len()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn clear(&mut self) {
|
pub fn clear(&mut self) -> Result<(), TasksError> {
|
||||||
self.tasks = None;
|
if self.is_empty() {
|
||||||
|
Err(TasksError(String::from("no tasks available")))
|
||||||
|
} else {
|
||||||
|
self.tasks = None;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Status {
|
||||||
|
pub fn as_string(&self) -> ColoredString {
|
||||||
|
match self {
|
||||||
|
Status::Inbox => "📮 Inbox".blue(),
|
||||||
|
Status::Pending => "📅 Pending".yellow(),
|
||||||
|
Status::Active => "✍️ Active".red(),
|
||||||
|
Status::Complete => "📗 Complete".green(),
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user