From ae7887fd35594de9d6c6be185989a9fe8d75d045 Mon Sep 17 00:00:00 2001 From: aaron-jack-manning Date: Sat, 3 Sep 2022 12:28:25 +1000 Subject: [PATCH] list profiles --- src/args.rs | 26 ++++++++++++++++++++++-- src/config.rs | 56 +++++++++++++++++++++++++++++++++++++++++++++++++-- src/format.rs | 7 ++++++- src/main.rs | 28 +++++++++++++++++++++++--- src/tasks.rs | 12 +++++------ 5 files changed, 115 insertions(+), 14 deletions(-) diff --git a/src/args.rs b/src/args.rs index 9dab6df..720eb03 100644 --- a/src/args.rs +++ b/src/args.rs @@ -69,6 +69,9 @@ pub enum Command { GitIgnore, /// Lists tasks according to the specified fields, ordering and filters. List { + /// Use an existing profile for list options, ignoring other arguments. + #[clap(long)] + profile : Option, #[clap(flatten)] options : ListOptions, }, @@ -104,7 +107,7 @@ pub enum Command { }, } -#[derive(clap::StructOpt, Debug, PartialEq, Eq)] +#[derive(clap::StructOpt, Debug, PartialEq, Eq, serde::Serialize, serde::Deserialize)] pub struct ListOptions { /// Which columns to include. #[clap(short, value_enum)] @@ -195,7 +198,26 @@ pub enum ConfigCommand { Editor { /// Command to launch editor. Omit to view current editor. editor : Option, - } + }, + /// For working with profiles for the list command. + #[clap(subcommand)] + Profile(ProfileCommand), +} + +#[derive(clap::Subcommand, Debug, PartialEq, Eq)] +pub enum ProfileCommand { + New { + /// Name of the new profile. + name : String, + #[clap(flatten)] + options : ListOptions, + }, + Delete { + /// Name of the profile to delete. + name : String, + }, + /// List names of currently set up profiles. + List, } #[derive(clap::Subcommand, Debug, PartialEq, Eq)] diff --git a/src/config.rs b/src/config.rs index dc9153f..80b9fda 100755 --- a/src/config.rs +++ b/src/config.rs @@ -1,3 +1,4 @@ +use crate::args; use crate::error; use crate::format; @@ -8,6 +9,13 @@ pub struct Config { /// Paths for all vaults, ordered according to recent usage, with current at the front. pub vaults : Vec<(String, path::PathBuf)>, pub editor : String, + pub profiles : Vec, +} + +#[derive(Debug, serde::Serialize, serde::Deserialize)] +pub struct Profile { + name : String, + options : args::ListOptions, } impl Default for Config { @@ -15,6 +23,7 @@ impl Default for Config { Self { vaults : Vec::default(), editor : String::from("vim"), + profiles : Vec::default(), } } } @@ -62,8 +71,6 @@ impl Config { Err(error::Error::Generic(format!("No vault named {} exists", format::vault(old_name)))) } } - - } /// Adds the vault to the configuration. @@ -132,6 +139,51 @@ impl Config { Ok(()) } } + + pub fn create_profile(&mut self, name : String, options : args::ListOptions) -> Result<(), error::Error> { + if self.profiles.iter().any(|Profile { name : n, options : _ }| n == &name) { + Err(error::Error::Generic(format!("A profile by the name {} already exists", format::profile(&name)))) + } + else { + self.profiles.push(Profile { name, options }); + Ok(()) + } + } + + pub fn get_profile(&self, name : &String) -> Result<&args::ListOptions, error::Error> { + self.profiles + .iter() + .find(|Profile { name : n, options : _ }| n == name) + .map(|Profile { name : _, options : o }| o) + .ok_or(error::Error::Generic(format!("No profile by the name {} exists", format::profile(name)))) + } + + pub fn delete_profile(&mut self, name : &String) -> Result<(), error::Error> { + match self.profiles.iter().position(|Profile { name : n, options : _ }| n == name) { + Some(index) => { + let _ = self.profiles.swap_remove(index); + Ok(()) + }, + None => { + Err(error::Error::Generic(format!("No profile by the name {} exists", format::profile(name)))) + } + } + } + + + /// Lists all profiles to stdout. + pub fn list_profiles(&self) -> Result<(), error::Error> { + if self.profiles.is_empty() { + Err(error::Error::Generic(format!("No profiles currently set up, try running: {}", format::command("toru config profile new ")))) + } + else { + for Profile { name, options : _ } in self.profiles.iter() { + println!("{}", format::profile(name)); + } + + Ok(()) + } + } } diff --git a/src/format.rs b/src/format.rs index 4e75804..3f16742 100755 --- a/src/format.rs +++ b/src/format.rs @@ -23,6 +23,8 @@ pub static TASK : (u8, u8, u8) = (39, 174, 96); pub static FILE : (u8, u8, u8) = (255, 184, 184); // Grey pub static GREY : (u8, u8, u8) = (99, 110, 114); +// Pink +pub static PROFILE : (u8, u8, u8) = (253, 121, 168); mod due { pub static OVERDUE : (u8, u8, u8) = (192, 57, 43); @@ -65,11 +67,14 @@ pub fn file(string : &str) -> colored::ColoredString { text(string, FILE).bold() } - pub fn greyed_out(string : &str) -> colored::ColoredString { text(string, GREY) } +pub fn profile(string : &str) -> colored::ColoredString { + text(string, PROFILE) +} + pub fn priority(priority : &tasks::Priority) -> String { use tasks::Priority::*; let priority = match priority { diff --git a/src/main.rs b/src/main.rs index 5dc7486..48c8fb3 100755 --- a/src/main.rs +++ b/src/main.rs @@ -60,9 +60,8 @@ fn program() -> Result<(), error::Error> { } } else if let Command::Config(command) = command { - use ConfigCommand::*; match command { - Editor { editor } => { + ConfigCommand::Editor { editor } => { match editor { Some(editor) => { config.editor = editor; @@ -72,6 +71,21 @@ fn program() -> Result<(), error::Error> { println!("Current editor command: {}", config.editor); } } + }, + ConfigCommand::Profile(command) => { + match command { + ProfileCommand::New { name, options } => { + config.create_profile(name.clone(), options)?; + println!("Created profile {}", format::profile(&name)) + }, + ProfileCommand::Delete { name } => { + config.delete_profile(&name)?; + println!("Deleted profile {}", format::profile(&name)) + }, + ProfileCommand::List => { + config.list_profiles()?; + } + } } } } @@ -157,7 +171,15 @@ fn program() -> Result<(), error::Error> { task.save()?; println!("Marked task {} as complete", format::id(id)); }, - Command::List { options } => { + Command::List { profile, options } => { + let options = match profile { + Some(profile) => { + config.get_profile(&profile)? + }, + None => { + &options + } + }; tasks::list(options, vault_folder, &state)?; }, // All commands which are dealt with in if let chain at start. diff --git a/src/tasks.rs b/src/tasks.rs index ceb5019..378f018 100755 --- a/src/tasks.rs +++ b/src/tasks.rs @@ -355,7 +355,7 @@ fn compare_due_dates(first : &Option, second : &Option) -> cmp::O } /// Lists all tasks in the specified vault. -pub fn list(mut options : super::ListOptions, vault_folder : &path::Path, state : &state::State) -> Result<(), error::Error> { +pub fn list(options : &super::ListOptions, vault_folder : &path::Path, state : &state::State) -> Result<(), error::Error> { let mut table = comfy_table::Table::new(); table @@ -512,10 +512,10 @@ pub fn list(mut options : super::ListOptions, vault_folder : &path::Path, state let mut headers = vec!["Id", "Name"]; // Remove duplicate columns. - { + let unique_columns : Vec<_> = { let mut columns = HashSet::new(); - options.column = options.column + options.column.clone() .into_iter() .filter(|c| { if columns.contains(c) { @@ -526,11 +526,11 @@ pub fn list(mut options : super::ListOptions, vault_folder : &path::Path, state true } }) - .collect(); - } + .collect() + }; use super::Column; - for column in &options.column { + for column in &unique_columns { match column { Column::Tracked => { headers.push("Tracked");