colours and formatting fixes
This commit is contained in:
		
							
								
								
									
										230
									
								
								src/colour.rs
									
									
									
									
									
								
							
							
						
						
									
										230
									
								
								src/colour.rs
									
									
									
									
									
								
							@@ -3,59 +3,205 @@ use crate::tasks::Id;
 | 
			
		||||
use colored::Colorize;
 | 
			
		||||
 | 
			
		||||
// Yellow
 | 
			
		||||
pub fn vault(text : &str) -> colored::ColoredString {
 | 
			
		||||
    text.truecolor(243, 156, 18).bold()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Red
 | 
			
		||||
pub fn error(text : &str) -> colored::ColoredString {
 | 
			
		||||
    text.truecolor(192, 57, 43).bold()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Purple
 | 
			
		||||
pub fn command(text : &str) -> colored::ColoredString {
 | 
			
		||||
    text.truecolor(155, 89, 182).bold()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Green
 | 
			
		||||
pub fn task_name(text : &str) -> colored::ColoredString {
 | 
			
		||||
    text.truecolor(39, 174, 96).bold()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
// Beige
 | 
			
		||||
pub fn file(text : &str) -> colored::ColoredString {
 | 
			
		||||
    text.truecolor(255, 184, 184).bold()
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub static VAULT : (u8, u8, u8) = (243, 156, 18);
 | 
			
		||||
// Blue
 | 
			
		||||
pub fn id(id : Id) -> colored::ColoredString {
 | 
			
		||||
    id.to_string().truecolor(52, 152, 219)
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub static ID : (u8, u8, u8) = (52, 152, 219);
 | 
			
		||||
// Red
 | 
			
		||||
pub static ERROR : (u8, u8, u8) = (192, 57, 43);
 | 
			
		||||
// Purple
 | 
			
		||||
pub static COMMAND : (u8, u8, u8) = (155, 89, 182);
 | 
			
		||||
// Green
 | 
			
		||||
pub static TASK : (u8, u8, u8) = (39, 174, 96);
 | 
			
		||||
// Beige
 | 
			
		||||
pub static FILE : (u8, u8, u8) = (255, 184, 184);
 | 
			
		||||
// Grey
 | 
			
		||||
pub fn greyed_out(text : &str) -> colored::ColoredString {
 | 
			
		||||
    text.truecolor(99, 110, 114)
 | 
			
		||||
pub static GREY : (u8, u8, u8) = (99, 110, 114);
 | 
			
		||||
 | 
			
		||||
mod due {
 | 
			
		||||
    pub static OVERDUE : (u8, u8, u8) = (192, 57, 43);
 | 
			
		||||
    pub static VERY_CLOSE : (u8, u8, u8) = (231, 76, 60);
 | 
			
		||||
    pub static CLOSE : (u8, u8, u8) = (241, 196, 15);
 | 
			
		||||
    pub static PLENTY_OF_TIME : (u8, u8, u8) = (46, 204, 113);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub mod priority {
 | 
			
		||||
    pub static LOW : (u8, u8, u8) = (46, 204, 113);
 | 
			
		||||
    pub static MEDIUM : (u8, u8, u8) = (241, 196, 15);
 | 
			
		||||
    pub static HIGH : (u8, u8, u8) = (231, 76, 60);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub mod due_date {
 | 
			
		||||
    use colored::Colorize;
 | 
			
		||||
pub mod cell {
 | 
			
		||||
    use crate::tasks;
 | 
			
		||||
 | 
			
		||||
    pub fn overdue(text : &str) -> colored::ColoredString {
 | 
			
		||||
        text.truecolor(192, 57, 43)
 | 
			
		||||
    use chrono::SubsecRound;
 | 
			
		||||
 | 
			
		||||
    fn cell<T : Into<comfy_table::Cell>>(text : T, colour : (u8, u8, u8)) -> comfy_table::Cell {
 | 
			
		||||
        text.into().fg(comfy_table::Color::from(colour))
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub fn very_close(text : &str) -> colored::ColoredString {
 | 
			
		||||
        text.truecolor(231, 76, 60)
 | 
			
		||||
 | 
			
		||||
    pub fn priority(priority : &tasks::Priority) -> comfy_table::Cell {
 | 
			
		||||
        use tasks::Priority::*;
 | 
			
		||||
        match priority {
 | 
			
		||||
            Low => comfy_table::Cell::new("low").fg(comfy_table::Color::from(super::priority::LOW)),
 | 
			
		||||
            Medium => comfy_table::Cell::new("medium").fg(comfy_table::Color::from(super::priority::MEDIUM)),
 | 
			
		||||
            High => comfy_table::Cell::new("high").fg(comfy_table::Color::from(super::priority::HIGH)),
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub fn close(text : &str) -> colored::ColoredString {
 | 
			
		||||
        text.truecolor(230, 126, 34)
 | 
			
		||||
    pub fn due_date(due : &chrono::NaiveDateTime, include_fuzzy_period : bool, colour : bool) -> comfy_table::Cell {
 | 
			
		||||
 | 
			
		||||
    }
 | 
			
		||||
        let remaining = *due - chrono::Local::now().naive_local();
 | 
			
		||||
 | 
			
		||||
        let fuzzy_period = if remaining.num_days() != 0 {
 | 
			
		||||
            let days = remaining.num_days().abs();
 | 
			
		||||
            format!("{} day{}", days, if days == 1 {""} else {"s"})
 | 
			
		||||
        }
 | 
			
		||||
        else if remaining.num_hours() != 0 {
 | 
			
		||||
            let hours = remaining.num_hours().abs();
 | 
			
		||||
            format!("{} hour{}", hours, if hours == 1 {""} else {"s"})
 | 
			
		||||
        }
 | 
			
		||||
        else if remaining.num_minutes() != 0 {
 | 
			
		||||
            let minutes = remaining.num_minutes().abs();
 | 
			
		||||
            format!("{} minute{}", minutes, if minutes == 1 {""} else {"s"})
 | 
			
		||||
        }
 | 
			
		||||
        else {
 | 
			
		||||
            let seconds = remaining.num_seconds().abs();
 | 
			
		||||
            format!("{} second{}", seconds, if seconds == 1 {""} else {"s"})
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        if include_fuzzy_period {
 | 
			
		||||
            if colour {
 | 
			
		||||
                if remaining < chrono::Duration::zero() {
 | 
			
		||||
                    cell(format!("{} {}", due.round_subsecs(0), format!("({} overdue)", fuzzy_period)), super::due::OVERDUE)
 | 
			
		||||
                }
 | 
			
		||||
                else if remaining < chrono::Duration::days(1) {
 | 
			
		||||
                    cell(format!("{} {}", due.round_subsecs(0), format!("({} remaining)", fuzzy_period)), super::due::VERY_CLOSE)
 | 
			
		||||
 | 
			
		||||
                }
 | 
			
		||||
                else if remaining < chrono::Duration::days(5) {
 | 
			
		||||
                    cell(format!("{} {}", due.round_subsecs(0), format!("({} remaining)", fuzzy_period)), super::due::CLOSE)
 | 
			
		||||
 | 
			
		||||
                }
 | 
			
		||||
                else {
 | 
			
		||||
                    cell(format!("{} {}", due.round_subsecs(0), format!("({} remaining)", fuzzy_period)), super::due::PLENTY_OF_TIME)
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            else {
 | 
			
		||||
                if remaining < chrono::Duration::zero() {
 | 
			
		||||
                    comfy_table::Cell::new(format!("{} ({} overdue)", due.round_subsecs(0), fuzzy_period))
 | 
			
		||||
                }
 | 
			
		||||
                else {
 | 
			
		||||
                    comfy_table::Cell::new(format!("{} ({} remaining)", due.round_subsecs(0), fuzzy_period))
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        else {
 | 
			
		||||
            comfy_table::Cell::new(format!("{}", due.round_subsecs(0)))
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
    pub fn plenty_of_time(text : &str) -> colored::ColoredString {
 | 
			
		||||
        text.truecolor(46, 204, 113)
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
pub mod text {
 | 
			
		||||
    use super::*;
 | 
			
		||||
    use crate::tasks;
 | 
			
		||||
 | 
			
		||||
    use chrono::SubsecRound;
 | 
			
		||||
 | 
			
		||||
    fn text(string : &str, colour : (u8, u8, u8)) -> colored::ColoredString {
 | 
			
		||||
        string.truecolor(colour.0, colour.1, colour.2)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub fn vault(string : &str) -> colored::ColoredString {
 | 
			
		||||
        text(string, VAULT).bold()
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub fn id(id : Id) -> colored::ColoredString {
 | 
			
		||||
        text(&id.to_string(), ID)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub fn error(string : &str) -> colored::ColoredString {
 | 
			
		||||
        text(string, ERROR).bold()
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub fn command(string : &str) -> colored::ColoredString {
 | 
			
		||||
        text(string, COMMAND).bold()
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub fn task(string : &str) -> colored::ColoredString {
 | 
			
		||||
        text(string, TASK).bold()
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub fn file(string : &str) -> colored::ColoredString {
 | 
			
		||||
        text(string, FILE).bold()
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    pub fn greyed_out(string : &str) -> colored::ColoredString {
 | 
			
		||||
        text(string, GREY)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    pub fn priority(priority : &tasks::Priority) -> String {
 | 
			
		||||
        use tasks::Priority::*;
 | 
			
		||||
        let priority = match priority {
 | 
			
		||||
            Low => text("low", super::priority::LOW),
 | 
			
		||||
            Medium => text("medium", super::priority::MEDIUM),
 | 
			
		||||
            High => text("high", super::priority::HIGH),
 | 
			
		||||
        };
 | 
			
		||||
        format!("{}", priority)
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
 | 
			
		||||
    pub fn due_date(due : &chrono::NaiveDateTime, include_fuzzy_period : bool, colour : bool) -> String {
 | 
			
		||||
 | 
			
		||||
        let remaining = *due - chrono::Local::now().naive_local();
 | 
			
		||||
 | 
			
		||||
        let fuzzy_period = if remaining.num_days() != 0 {
 | 
			
		||||
            let days = remaining.num_days().abs();
 | 
			
		||||
            format!("{} day{}", days, if days == 1 {""} else {"s"})
 | 
			
		||||
        }
 | 
			
		||||
        else if remaining.num_hours() != 0 {
 | 
			
		||||
            let hours = remaining.num_hours().abs();
 | 
			
		||||
            format!("{} hour{}", hours, if hours == 1 {""} else {"s"})
 | 
			
		||||
        }
 | 
			
		||||
        else if remaining.num_minutes() != 0 {
 | 
			
		||||
            let minutes = remaining.num_minutes().abs();
 | 
			
		||||
            format!("{} minute{}", minutes, if minutes == 1 {""} else {"s"})
 | 
			
		||||
        }
 | 
			
		||||
        else {
 | 
			
		||||
            let seconds = remaining.num_seconds().abs();
 | 
			
		||||
            format!("{} second{}", seconds, if seconds == 1 {""} else {"s"})
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        if include_fuzzy_period {
 | 
			
		||||
            if colour {
 | 
			
		||||
                if remaining < chrono::Duration::zero() {
 | 
			
		||||
                    format!("{} {}", due.round_subsecs(0), text(&format!("({} overdue)", fuzzy_period), super::due::OVERDUE))
 | 
			
		||||
                }
 | 
			
		||||
                else if remaining < chrono::Duration::days(1) {
 | 
			
		||||
                    format!("{} {}", due.round_subsecs(0), text(&format!("({} remaining)", fuzzy_period), super::due::VERY_CLOSE))
 | 
			
		||||
 | 
			
		||||
                }
 | 
			
		||||
                else if remaining < chrono::Duration::days(5) {
 | 
			
		||||
                    format!("{} {}", due.round_subsecs(0), text(&format!("({} remaining)", fuzzy_period), super::due::CLOSE))
 | 
			
		||||
 | 
			
		||||
                }
 | 
			
		||||
                else {
 | 
			
		||||
                    format!("{} {}", due.round_subsecs(0), text(&format!("({} remaining)", fuzzy_period), super::due::PLENTY_OF_TIME))
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
            else {
 | 
			
		||||
                if remaining < chrono::Duration::zero() {
 | 
			
		||||
                    format!("{} ({} overdue)", due.round_subsecs(0), fuzzy_period)
 | 
			
		||||
                }
 | 
			
		||||
                else {
 | 
			
		||||
                    format!("{} ({} remaining)", due.round_subsecs(0), fuzzy_period)
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        else {
 | 
			
		||||
            format!("{}", due.round_subsecs(0))
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -46,7 +46,7 @@ impl Config {
 | 
			
		||||
 | 
			
		||||
        for (name, _) in &mut self.vaults {
 | 
			
		||||
            if *name == new_name {
 | 
			
		||||
                return Err(error::Error::Generic(format!("A vault named {} already exists", colour::vault(&new_name))));
 | 
			
		||||
                return Err(error::Error::Generic(format!("A vault named {} already exists", colour::text::vault(&new_name))));
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            if name == old_name {
 | 
			
		||||
@@ -60,7 +60,7 @@ impl Config {
 | 
			
		||||
                Ok(())
 | 
			
		||||
            },
 | 
			
		||||
            None => {
 | 
			
		||||
                Err(error::Error::Generic(format!("No vault named {} exists", colour::vault(old_name))))
 | 
			
		||||
                Err(error::Error::Generic(format!("No vault named {} exists", colour::text::vault(old_name))))
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@@ -82,7 +82,7 @@ impl Config {
 | 
			
		||||
                Ok(path)
 | 
			
		||||
            },
 | 
			
		||||
            None => {
 | 
			
		||||
                Err(error::Error::Generic(format!("No vault by the name {} exists", colour::vault(name))))
 | 
			
		||||
                Err(error::Error::Generic(format!("No vault by the name {} exists", colour::text::vault(name))))
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
@@ -94,7 +94,7 @@ impl Config {
 | 
			
		||||
                Ok(())
 | 
			
		||||
            },
 | 
			
		||||
            None => {
 | 
			
		||||
                Err(error::Error::Generic(format!("No vault by the name {} exists", colour::vault(name))))
 | 
			
		||||
                Err(error::Error::Generic(format!("No vault by the name {} exists", colour::text::vault(name))))
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
@@ -105,7 +105,7 @@ impl Config {
 | 
			
		||||
        let width = self.vaults.iter().fold(usize::MIN, |c, (n, _)| c.max(n.len()));
 | 
			
		||||
 | 
			
		||||
        if self.vaults.is_empty() {
 | 
			
		||||
            Err(error::Error::Generic(format!("No vaults currently set up, try running: {}", colour::command("toru vault new <NAME> <PATH>"))))
 | 
			
		||||
            Err(error::Error::Generic(format!("No vaults currently set up, try running: {}", colour::text::command("toru vault new <NAME> <PATH>"))))
 | 
			
		||||
        }
 | 
			
		||||
        else {
 | 
			
		||||
            for (i, (name, path)) in self.vaults.iter().enumerate() {
 | 
			
		||||
@@ -117,7 +117,7 @@ impl Config {
 | 
			
		||||
                    print!("  ");
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
                print!("{}", colour::vault(name));
 | 
			
		||||
                print!("{}", colour::text::vault(name));
 | 
			
		||||
 | 
			
		||||
                let padding = width - name.len() + 1;
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
@@ -89,7 +89,7 @@ pub fn edit_raw(id : Id, vault_folder : path::PathBuf, editor : &str, state : &m
 | 
			
		||||
                        state.data.deps.insert_edge(id, *dependency)?;
 | 
			
		||||
                    }
 | 
			
		||||
                    else {
 | 
			
		||||
                        return Err(error::Error::Generic(format!("No task with an ID of {} exists", colour::id(*dependency))));
 | 
			
		||||
                        return Err(error::Error::Generic(format!("No task with an ID of {} exists", colour::text::id(*dependency))));
 | 
			
		||||
                    }
 | 
			
		||||
                }
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										18
									
								
								src/error.rs
									
									
									
									
									
								
							
							
						
						
									
										18
									
								
								src/error.rs
									
									
									
									
									
								
							@@ -20,15 +20,15 @@ pub enum Error {
 | 
			
		||||
impl fmt::Display for Error {
 | 
			
		||||
    fn fmt(&self, f : &mut fmt::Formatter<'_>) -> fmt::Result {
 | 
			
		||||
        match self {
 | 
			
		||||
            Error::Io(err) => write!(f, "{} {}", colour::error("Internal Error:"), err),
 | 
			
		||||
            Error::Confy(err) => write!(f, "{} {}", colour::error("Internal Error:"), err),
 | 
			
		||||
            Error::Trash(err) => write!(f, "{} {}", colour::error("Internal Error:"), err),
 | 
			
		||||
            Error::TomlDe(err) => write!(f, "{} {}", colour::error("Internal Error:"), err),
 | 
			
		||||
            Error::TomlSer(err) => write!(f, "{} {}", colour::error("Internal Error:"), err),
 | 
			
		||||
            Error::Utf8(err) => write!(f, "{} {}", colour::error("Internal Error:"), err),
 | 
			
		||||
            Error::Fmt(err) => write!(f, "{} {}", colour::error("Internal Error:"), err),
 | 
			
		||||
            Error::Generic(message) => write!(f, "{} {}", colour::error("Error:"), message),
 | 
			
		||||
            Error::Internal(message) => write!(f, "{} {}", colour::error("Internal Error:"), message),
 | 
			
		||||
            Error::Io(err) => write!(f, "{} {}", colour::text::error("Internal Error:"), err),
 | 
			
		||||
            Error::Confy(err) => write!(f, "{} {}", colour::text::error("Internal Error:"), err),
 | 
			
		||||
            Error::Trash(err) => write!(f, "{} {}", colour::text::error("Internal Error:"), err),
 | 
			
		||||
            Error::TomlDe(err) => write!(f, "{} {}", colour::text::error("Internal Error:"), err),
 | 
			
		||||
            Error::TomlSer(err) => write!(f, "{} {}", colour::text::error("Internal Error:"), err),
 | 
			
		||||
            Error::Utf8(err) => write!(f, "{} {}", colour::text::error("Internal Error:"), err),
 | 
			
		||||
            Error::Fmt(err) => write!(f, "{} {}", colour::text::error("Internal Error:"), err),
 | 
			
		||||
            Error::Generic(message) => write!(f, "{} {}", colour::text::error("Error:"), message),
 | 
			
		||||
            Error::Internal(message) => write!(f, "{} {}", colour::text::error("Internal Error:"), message),
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 
 | 
			
		||||
@@ -40,7 +40,7 @@ impl Graph {
 | 
			
		||||
            Err(error::Error::Internal(String::from("Attempt to insert an edge in the dependency graph with a node which wasn't present")))
 | 
			
		||||
        }
 | 
			
		||||
        else if first == second {
 | 
			
		||||
            Err(error::Error::Generic(format!("Note with ID {} cannot depend on itself", colour::id(first))))
 | 
			
		||||
            Err(error::Error::Generic(format!("Note with ID {} cannot depend on itself", colour::text::id(first))))
 | 
			
		||||
        }
 | 
			
		||||
        else {
 | 
			
		||||
            let outgoing = self.edges.get_mut(&first).unwrap();
 | 
			
		||||
@@ -136,7 +136,7 @@ pub fn format_cycle(cycle : &Vec<Id>) -> String {
 | 
			
		||||
    let mut formatted = String::new();
 | 
			
		||||
 | 
			
		||||
    for (index, node) in cycle.iter().enumerate() {
 | 
			
		||||
        write!(&mut formatted, "{}", colour::id(*node)).unwrap();
 | 
			
		||||
        write!(&mut formatted, "{}", colour::text::id(*node)).unwrap();
 | 
			
		||||
 | 
			
		||||
        if index != cycle.len() - 1 {
 | 
			
		||||
            formatted.push_str(" -> ");
 | 
			
		||||
 
 | 
			
		||||
@@ -69,7 +69,7 @@ impl Index {
 | 
			
		||||
                        else {
 | 
			
		||||
                            let coloured_ids : Vec<_> =
 | 
			
		||||
                                ids.iter()
 | 
			
		||||
                                .map(|i| colour::id(*i))
 | 
			
		||||
                                .map(|i| colour::text::id(*i))
 | 
			
		||||
                                .collect();
 | 
			
		||||
 | 
			
		||||
                            let mut display_ids = String::new();
 | 
			
		||||
@@ -86,7 +86,7 @@ impl Index {
 | 
			
		||||
                            Err(error::Error::Generic(format!("Multiple notes (Ids: [{}]) by that name exist", display_ids)))
 | 
			
		||||
                        }
 | 
			
		||||
                    },
 | 
			
		||||
                    None => Err(error::Error::Generic(format!("A note by the name {} does not exist", colour::task_name(name)))),
 | 
			
		||||
                    None => Err(error::Error::Generic(format!("A note by the name {} does not exist", colour::text::task(name)))),
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										22
									
								
								src/main.rs
									
									
									
									
									
								
							
							
						
						
									
										22
									
								
								src/main.rs
									
									
									
									
									
								
							@@ -242,26 +242,26 @@ fn program() -> Result<(), error::Error> {
 | 
			
		||||
        match command {
 | 
			
		||||
            New { name, path } => {
 | 
			
		||||
                vault::new(name.clone(), path, &mut config)?;
 | 
			
		||||
                println!("Created vault {}", colour::vault(&name));
 | 
			
		||||
                println!("Created vault {}", colour::text::vault(&name));
 | 
			
		||||
            },
 | 
			
		||||
            Disconnect { name } => {
 | 
			
		||||
                vault::disconnect(&name, &mut config)?;
 | 
			
		||||
                println!("Disconnected vault {}", colour::vault(&name));
 | 
			
		||||
                println!("Disconnected vault {}", colour::text::vault(&name));
 | 
			
		||||
            },
 | 
			
		||||
            Connect { name , path } => {
 | 
			
		||||
                vault::connect(name.clone(), path, &mut config)?;
 | 
			
		||||
                println!("Connected vault {}", colour::vault(&name));
 | 
			
		||||
                println!("Connected vault {}", colour::text::vault(&name));
 | 
			
		||||
            },
 | 
			
		||||
            Delete { name } => {
 | 
			
		||||
                vault::delete(&name, &mut config)?;
 | 
			
		||||
                println!("Deleted vault {}", colour::vault(&name));
 | 
			
		||||
                println!("Deleted vault {}", colour::text::vault(&name));
 | 
			
		||||
            },
 | 
			
		||||
            List => {
 | 
			
		||||
                config.list_vaults()?;
 | 
			
		||||
            },
 | 
			
		||||
            Rename { old_name, new_name } => {
 | 
			
		||||
                config.rename_vault(&old_name, new_name.clone())?;
 | 
			
		||||
                println!("Renamed vault {} to {}", colour::vault(&old_name), colour::vault(&new_name));
 | 
			
		||||
                println!("Renamed vault {} to {}", colour::text::vault(&old_name), colour::text::vault(&new_name));
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
@@ -283,7 +283,7 @@ fn program() -> Result<(), error::Error> {
 | 
			
		||||
    }
 | 
			
		||||
    else if let Switch { name } = command {
 | 
			
		||||
        config.switch(&name)?;
 | 
			
		||||
        println!("Switched to vault {}", colour::vault(&name));
 | 
			
		||||
        println!("Switched to vault {}", colour::text::vault(&name));
 | 
			
		||||
    }
 | 
			
		||||
    else if let Git { args } = command {
 | 
			
		||||
        let vault_folder = &config.current_vault()?.1;
 | 
			
		||||
@@ -292,7 +292,7 @@ fn program() -> Result<(), error::Error> {
 | 
			
		||||
    else if command == GitIgnore {
 | 
			
		||||
        let vault_folder = &config.current_vault()?.1;
 | 
			
		||||
        vcs::create_gitignore(vault_folder)?;
 | 
			
		||||
        println!("Default {} file created", colour::file(".gitignore"));
 | 
			
		||||
        println!("Default {} file created", colour::text::file(".gitignore"));
 | 
			
		||||
    }
 | 
			
		||||
    else if let Svn { args } = command {
 | 
			
		||||
        let vault_folder = &config.current_vault()?.1;
 | 
			
		||||
@@ -306,7 +306,7 @@ fn program() -> Result<(), error::Error> {
 | 
			
		||||
        match command {
 | 
			
		||||
            New { name, info, tags, dependencies, priority, due } => {
 | 
			
		||||
                let task = tasks::Task::new(name, info, tags, dependencies, priority, due, vault_folder, &mut state)?;
 | 
			
		||||
                println!("Created task {} (ID: {})", colour::task_name(&task.data.name), colour::id(task.data.id));
 | 
			
		||||
                println!("Created task {} (ID: {})", colour::text::task(&task.data.name), colour::text::id(task.data.id));
 | 
			
		||||
            },
 | 
			
		||||
            Delete { id_or_name } => {
 | 
			
		||||
                let id = state.data.index.lookup(&id_or_name)?;
 | 
			
		||||
@@ -316,7 +316,7 @@ fn program() -> Result<(), error::Error> {
 | 
			
		||||
                state.data.deps.remove_node(task.data.id);
 | 
			
		||||
                task.delete()?;
 | 
			
		||||
 | 
			
		||||
                println!("Deleted task {} (ID: {})", colour::task_name(&name), colour::id(id));
 | 
			
		||||
                println!("Deleted task {} (ID: {})", colour::text::task(&name), colour::text::id(id));
 | 
			
		||||
            },
 | 
			
		||||
            View { id_or_name } => {
 | 
			
		||||
                let id = state.data.index.lookup(&id_or_name)?;
 | 
			
		||||
@@ -331,7 +331,7 @@ fn program() -> Result<(), error::Error> {
 | 
			
		||||
                else {
 | 
			
		||||
                    edit::edit_raw(id, vault_folder.clone(), &config.editor, &mut state)?;
 | 
			
		||||
                }
 | 
			
		||||
                println!("Updated task {}", colour::id(id));
 | 
			
		||||
                println!("Updated task {}", colour::text::id(id));
 | 
			
		||||
            },
 | 
			
		||||
            Track { id_or_name, hours, minutes } => {
 | 
			
		||||
                let id = state.data.index.lookup(&id_or_name)?;
 | 
			
		||||
@@ -356,7 +356,7 @@ fn program() -> Result<(), error::Error> {
 | 
			
		||||
                let mut task = tasks::Task::load(id, vault_folder, false)?;
 | 
			
		||||
                task.data.completed = Some(chrono::Local::now().naive_local());
 | 
			
		||||
                task.save()?;
 | 
			
		||||
                println!("Marked task {} as complete", colour::id(id));
 | 
			
		||||
                println!("Marked task {} as complete", colour::text::id(id));
 | 
			
		||||
            },
 | 
			
		||||
            List { options } => {
 | 
			
		||||
                tasks::list(options, vault_folder, &state)?;
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										99
									
								
								src/tasks.rs
									
									
									
									
									
								
							
							
						
						
									
										99
									
								
								src/tasks.rs
									
									
									
									
									
								
							@@ -12,7 +12,6 @@ use std::cmp;
 | 
			
		||||
use std::path;
 | 
			
		||||
use std::io::{Write, Seek};
 | 
			
		||||
use std::collections::{HashSet, HashMap};
 | 
			
		||||
use colored::Colorize;
 | 
			
		||||
use chrono::SubsecRound;
 | 
			
		||||
 | 
			
		||||
pub type Id = u64;
 | 
			
		||||
@@ -43,17 +42,6 @@ impl fmt::Display for Priority {
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
impl Priority {
 | 
			
		||||
    pub fn coloured(&self) -> String {
 | 
			
		||||
        use Priority::*;
 | 
			
		||||
        let priority = match self {
 | 
			
		||||
            Low => "low".truecolor(46, 204, 113),
 | 
			
		||||
            Medium => "medium".truecolor(241, 196, 15),
 | 
			
		||||
            High => "high".truecolor(231, 76, 60),
 | 
			
		||||
        };
 | 
			
		||||
        format!("{}", priority)
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
 | 
			
		||||
pub struct TimeEntry {
 | 
			
		||||
@@ -109,7 +97,7 @@ impl Task {
 | 
			
		||||
                    state.data.deps.insert_edge(id, *dependency)?;
 | 
			
		||||
                }
 | 
			
		||||
                else {
 | 
			
		||||
                    return Err(error::Error::Generic(format!("No task with an ID of {} exists", colour::id(*dependency))));
 | 
			
		||||
                    return Err(error::Error::Generic(format!("No task with an ID of {} exists", colour::text::id(*dependency))));
 | 
			
		||||
                }
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
@@ -214,7 +202,7 @@ impl Task {
 | 
			
		||||
            Ok(path)
 | 
			
		||||
        }
 | 
			
		||||
        else {
 | 
			
		||||
            Err(error::Error::Generic(format!("No task with the ID {} exists", colour::id(id))))
 | 
			
		||||
            Err(error::Error::Generic(format!("No task with the ID {} exists", colour::text::id(id))))
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -262,7 +250,7 @@ impl Task {
 | 
			
		||||
        let (heading, heading_length) = {
 | 
			
		||||
 | 
			
		||||
            (
 | 
			
		||||
                format!("[{}] {} {}", if self.data.completed.is_some() {"X"} else {" "}, colour::id(self.data.id), colour::task_name(&self.data.name)),
 | 
			
		||||
                format!("[{}] {} {}", if self.data.completed.is_some() {"X"} else {" "}, colour::text::id(self.data.id), colour::text::task(&self.data.name)),
 | 
			
		||||
                5 + self.data.name.chars().count() + self.data.id.to_string().chars().count()
 | 
			
		||||
            )
 | 
			
		||||
        };
 | 
			
		||||
@@ -270,12 +258,12 @@ impl Task {
 | 
			
		||||
        println!("{}", heading);
 | 
			
		||||
        line(heading_length);
 | 
			
		||||
 | 
			
		||||
        println!("Priority:     {}", self.data.priority.coloured());
 | 
			
		||||
        println!("Priority:     {}", colour::text::priority(&self.data.priority));
 | 
			
		||||
        println!("Tags:         [{}]", format_hash_set(&self.data.tags)?);
 | 
			
		||||
        println!("Created:      {}", self.data.created.round_subsecs(0));
 | 
			
		||||
        
 | 
			
		||||
        if let Some(due) = self.data.due {
 | 
			
		||||
            let due = format_due_date(&due, self.data.completed.is_none(), true);
 | 
			
		||||
            let due = colour::text::due_date(&due, self.data.completed.is_none(), true);
 | 
			
		||||
            println!("Due:          {}", due);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
@@ -347,17 +335,17 @@ fn dependency_tree(start : Id, prefix : &String, is_last_item : bool, graph : &g
 | 
			
		||||
        let task = tasks.get(&start).unwrap();
 | 
			
		||||
 | 
			
		||||
        let name = if task.data.completed.is_some() {
 | 
			
		||||
            colour::greyed_out(&task.data.name)
 | 
			
		||||
            colour::text::greyed_out(&task.data.name)
 | 
			
		||||
        }
 | 
			
		||||
        else {
 | 
			
		||||
            colour::task_name(&task.data.name)
 | 
			
		||||
            colour::text::task(&task.data.name)
 | 
			
		||||
        };
 | 
			
		||||
 | 
			
		||||
        if is_last_item {
 | 
			
		||||
            println!("{}└──{} (ID: {})", prefix, name, colour::id(start))
 | 
			
		||||
            println!("{}└──{} (ID: {})", prefix, name, colour::text::id(start))
 | 
			
		||||
        }
 | 
			
		||||
        else {
 | 
			
		||||
            println!("{}├──{} (ID: {})", prefix, name, colour::id(start))
 | 
			
		||||
            println!("{}├──{} (ID: {})", prefix, name, colour::text::id(start))
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -377,56 +365,6 @@ fn dependency_tree(start : Id, prefix : &String, is_last_item : bool, graph : &g
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
fn format_due_date(due : &chrono::NaiveDateTime, include_fuzzy_period : bool, colour : bool) -> String {
 | 
			
		||||
    let remaining = *due - chrono::Local::now().naive_local();
 | 
			
		||||
 | 
			
		||||
    let fuzzy_period = if remaining.num_days() != 0 {
 | 
			
		||||
        let days = remaining.num_days().abs();
 | 
			
		||||
        format!("{} day{}", days, if days == 1 {""} else {"s"})
 | 
			
		||||
    }
 | 
			
		||||
    else if remaining.num_hours() != 0 {
 | 
			
		||||
        let hours = remaining.num_hours().abs();
 | 
			
		||||
        format!("{} hour{}", hours, if hours == 1 {""} else {"s"})
 | 
			
		||||
    }
 | 
			
		||||
    else if remaining.num_minutes() != 0 {
 | 
			
		||||
        let minutes = remaining.num_minutes().abs();
 | 
			
		||||
        format!("{} minute{}", minutes, if minutes == 1 {""} else {"s"})
 | 
			
		||||
    }
 | 
			
		||||
    else {
 | 
			
		||||
        let seconds = remaining.num_seconds().abs();
 | 
			
		||||
        format!("{} second{}", seconds, if seconds == 1 {""} else {"s"})
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    if include_fuzzy_period {
 | 
			
		||||
        if colour {
 | 
			
		||||
            if remaining < chrono::Duration::zero() {
 | 
			
		||||
                format!("{} {}", due.round_subsecs(0), colour::due_date::overdue(&format!("({} overdue)", fuzzy_period)))
 | 
			
		||||
            }
 | 
			
		||||
            else if remaining < chrono::Duration::days(1) {
 | 
			
		||||
                format!("{} {}", due.round_subsecs(0), colour::due_date::very_close(&format!("({} remaining)", fuzzy_period)))
 | 
			
		||||
 | 
			
		||||
            }
 | 
			
		||||
            else if remaining < chrono::Duration::days(3) {
 | 
			
		||||
                format!("{} {}", due.round_subsecs(0), colour::due_date::close(&format!("({} remaining)", fuzzy_period)))
 | 
			
		||||
 | 
			
		||||
            }
 | 
			
		||||
            else {
 | 
			
		||||
                format!("{} {}", due.round_subsecs(0), colour::due_date::plenty_of_time(&format!("({} remaining)", fuzzy_period)))
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
        else {
 | 
			
		||||
            if remaining < chrono::Duration::zero() {
 | 
			
		||||
                format!("{} ({} overdue)", due.round_subsecs(0), fuzzy_period)
 | 
			
		||||
            }
 | 
			
		||||
            else {
 | 
			
		||||
                format!("{} ({} remaining)", due.round_subsecs(0), fuzzy_period)
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
    else {
 | 
			
		||||
        format!("{}", due.round_subsecs(0))
 | 
			
		||||
    }
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
fn compare_due_dates<T : Ord>(first : &Option<T>, second : &Option<T>) -> cmp::Ordering {
 | 
			
		||||
    match (first, second) {
 | 
			
		||||
@@ -621,40 +559,41 @@ pub fn list(mut options : super::ListOptions, vault_folder : &path::Path, state
 | 
			
		||||
 | 
			
		||||
    for task in tasks {
 | 
			
		||||
 | 
			
		||||
        let mut row = vec![task.data.id.to_string(), task.data.name.clone()];
 | 
			
		||||
        use comfy_table::Cell;
 | 
			
		||||
        let mut row = vec![Cell::from(task.data.id), Cell::from(task.data.name)];
 | 
			
		||||
 | 
			
		||||
        for column in &options.column {
 | 
			
		||||
            match column {
 | 
			
		||||
                Column::Tracked => {
 | 
			
		||||
                    let duration = TimeEntry::total(&task.data.time_entries);
 | 
			
		||||
                    row.push(
 | 
			
		||||
                        if duration == Duration::zero() { String::new() } else { duration.to_string() }
 | 
			
		||||
                        Cell::from(if duration == Duration::zero() { String::new() } else { duration.to_string() })
 | 
			
		||||
                    );
 | 
			
		||||
                },
 | 
			
		||||
                Column::Due => {
 | 
			
		||||
                    row.push(match task.data.due {
 | 
			
		||||
                        Some(due) => format_due_date(&due, task.data.completed.is_none(), false),
 | 
			
		||||
                        None => String::new()
 | 
			
		||||
                        Some(due) => colour::cell::due_date(&due, task.data.completed.is_none(), true),
 | 
			
		||||
                        None => Cell::from(String::new())
 | 
			
		||||
                    });
 | 
			
		||||
                },
 | 
			
		||||
                Column::Tags => {
 | 
			
		||||
                    row.push(format_hash_set(&task.data.tags)?);
 | 
			
		||||
                    row.push(Cell::new(format_hash_set(&task.data.tags)?));
 | 
			
		||||
                },
 | 
			
		||||
                Column::Priority => {
 | 
			
		||||
                    row.push(task.data.priority.to_string());
 | 
			
		||||
                    row.push(colour::cell::priority(&task.data.priority));
 | 
			
		||||
                },
 | 
			
		||||
                Column::Status => {
 | 
			
		||||
                    row.push(
 | 
			
		||||
                        if task.data.completed.is_some() {
 | 
			
		||||
                        Cell::new(if task.data.completed.is_some() {
 | 
			
		||||
                            String::from("complete")
 | 
			
		||||
                        }
 | 
			
		||||
                        else {
 | 
			
		||||
                            String::from("incomplete")
 | 
			
		||||
                        }
 | 
			
		||||
                        })
 | 
			
		||||
                    );
 | 
			
		||||
                },
 | 
			
		||||
                Column::Created => {
 | 
			
		||||
                    row.push(task.data.created.round_subsecs(0).to_string());
 | 
			
		||||
                    row.push(Cell::new(task.data.created.round_subsecs(0).to_string()));
 | 
			
		||||
                },
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
 
 | 
			
		||||
@@ -68,10 +68,10 @@ pub fn connect(name : String, path : path::PathBuf, config : &mut config::Config
 | 
			
		||||
        if path.exists() && path.is_dir()  {
 | 
			
		||||
            // Vault is missing required metadata files.
 | 
			
		||||
            if !path.join("notes").exists() {
 | 
			
		||||
                Err(error::Error::Generic(format!("Cannot connect the vault as it is missing the {} folder", colour::file("notes"))))
 | 
			
		||||
                Err(error::Error::Generic(format!("Cannot connect the vault as it is missing the {} folder", colour::text::file("notes"))))
 | 
			
		||||
            }
 | 
			
		||||
            else if !path.join("state.toml").exists() {
 | 
			
		||||
                Err(error::Error::Generic(format!("Cannot connect the vault as it is missing the {} file", colour::file("state.toml"))))
 | 
			
		||||
                Err(error::Error::Generic(format!("Cannot connect the vault as it is missing the {} file", colour::text::file("state.toml"))))
 | 
			
		||||
            }
 | 
			
		||||
            // Required metadata exists, so the vault is connected.
 | 
			
		||||
            else {
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user