changes to list command line options
This commit is contained in:
parent
083d276252
commit
c547fb8997
0
.gitignore
vendored
Normal file → Executable file
0
.gitignore
vendored
Normal file → Executable file
2
Cargo.lock
generated
Normal file → Executable file
2
Cargo.lock
generated
Normal file → Executable file
@ -775,7 +775,7 @@ dependencies = [
|
|||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "toru"
|
name = "toru"
|
||||||
version = "0.2.0"
|
version = "0.2.1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"chrono",
|
"chrono",
|
||||||
"clap",
|
"clap",
|
||||||
|
0
Cargo.toml
Normal file → Executable file
0
Cargo.toml
Normal file → Executable file
0
src/colour.rs
Normal file → Executable file
0
src/colour.rs
Normal file → Executable file
0
src/config.rs
Normal file → Executable file
0
src/config.rs
Normal file → Executable file
0
src/edit.rs
Normal file → Executable file
0
src/edit.rs
Normal file → Executable file
0
src/error.rs
Normal file → Executable file
0
src/error.rs
Normal file → Executable file
13
src/graph.rs
Normal file → Executable file
13
src/graph.rs
Normal file → Executable file
@ -71,6 +71,19 @@ impl Graph {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Gets all tasks which have dependents.
|
||||||
|
pub fn get_tasks_with_dependents(&self) -> HashSet<Id> {
|
||||||
|
let mut tasks_with_dependents = HashSet::new();
|
||||||
|
|
||||||
|
for (_, outgoing) in &self.edges {
|
||||||
|
for edge in outgoing {
|
||||||
|
tasks_with_dependents.insert(*edge);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
tasks_with_dependents
|
||||||
|
}
|
||||||
|
|
||||||
pub fn find_cycle(&self) -> Option<Vec<Id>> {
|
pub fn find_cycle(&self) -> Option<Vec<Id>> {
|
||||||
|
|
||||||
// All unvisited nodes, populated with all nodes at the start, to not miss disconnected
|
// All unvisited nodes, populated with all nodes at the start, to not miss disconnected
|
||||||
|
0
src/index.rs
Normal file → Executable file
0
src/index.rs
Normal file → Executable file
96
src/main.rs
Normal file → Executable file
96
src/main.rs
Normal file → Executable file
@ -101,82 +101,68 @@ enum Command {
|
|||||||
|
|
||||||
#[derive(clap::StructOpt, Debug, PartialEq, Eq)]
|
#[derive(clap::StructOpt, Debug, PartialEq, Eq)]
|
||||||
pub struct ListOptions {
|
pub struct ListOptions {
|
||||||
/// Include name column.
|
/// Which columns to include.
|
||||||
#[clap(long)]
|
#[clap(short, value_enum)]
|
||||||
name : bool,
|
column : Vec<Column>,
|
||||||
/// Include tracked time column.
|
/// Field to order by.
|
||||||
#[clap(long)]
|
#[clap(long, value_enum, default_value_t=OrderBy::Id)]
|
||||||
tracked : bool,
|
order_by : OrderBy,
|
||||||
/// Include due date column.
|
|
||||||
#[clap(long)]
|
|
||||||
due : bool,
|
|
||||||
/// Include tags column.
|
|
||||||
#[clap(long)]
|
|
||||||
tags : bool,
|
|
||||||
/// Include priority column.
|
|
||||||
#[clap(long)]
|
|
||||||
priority : bool,
|
|
||||||
/// Include status column.
|
|
||||||
#[clap(long)]
|
|
||||||
status : bool,
|
|
||||||
/// Include created date column.
|
|
||||||
#[clap(long)]
|
|
||||||
created : bool,
|
|
||||||
/// The field to sort by.
|
|
||||||
#[clap(long, value_enum, default_value_t=SortBy::Id)]
|
|
||||||
sort_by : SortBy,
|
|
||||||
/// Sort ascending on descending.
|
/// Sort ascending on descending.
|
||||||
#[clap(long, value_enum, default_value_t=SortType::Asc)]
|
#[clap(long, value_enum, default_value_t=Order::Asc)]
|
||||||
sort_type : SortType,
|
order : Order,
|
||||||
/// Only include tasks created before a certain date.
|
/// Tags to include.
|
||||||
|
#[clap(short, long)]
|
||||||
|
tag : Vec<String>,
|
||||||
|
/// Only include tasks due before a certain date (inclusive).
|
||||||
#[clap(long)]
|
#[clap(long)]
|
||||||
before : Option<chrono::NaiveDateTime>,
|
due_before : Option<chrono::NaiveDate>,
|
||||||
/// Only include tasks created after a certain date.
|
/// Only include tasks due after a certain date (inclusive).
|
||||||
#[clap(long)]
|
#[clap(long)]
|
||||||
after : Option<chrono::NaiveDateTime>,
|
due_after : Option<chrono::NaiveDate>,
|
||||||
/// Only include tasks due within a certain number of days.
|
/// Only include tasks created before a certain date (inclusive).
|
||||||
#[clap(long)]
|
#[clap(long)]
|
||||||
due_in : Option<u16>,
|
created_before : Option<chrono::NaiveDate>,
|
||||||
|
/// Only include tasks created after a certain date (inclusive).
|
||||||
|
#[clap(long)]
|
||||||
|
created_after : Option<chrono::NaiveDate>,
|
||||||
/// Include completed tasks in the list.
|
/// Include completed tasks in the list.
|
||||||
#[clap(long)]
|
#[clap(long)]
|
||||||
include_completed : bool,
|
include_completed : bool,
|
||||||
}
|
/// Only include notes with no dependencies [alias: bottom-level].
|
||||||
|
#[clap(long, alias="bottom-level")]
|
||||||
impl Default for ListOptions {
|
no_dependencies : bool,
|
||||||
fn default() -> Self {
|
/// Only include notes with no dependents [alias: top-level].
|
||||||
Self {
|
#[clap(long, alias="top-level")]
|
||||||
name : true,
|
no_dependents : bool,
|
||||||
tracked : true,
|
|
||||||
due : true,
|
|
||||||
tags : true,
|
|
||||||
priority : true,
|
|
||||||
status : false,
|
|
||||||
created : false,
|
|
||||||
sort_by : SortBy::Created,
|
|
||||||
sort_type : SortType::Desc,
|
|
||||||
before : None,
|
|
||||||
after : None,
|
|
||||||
due_in : None,
|
|
||||||
include_completed : false,
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Default, Clone, Debug, PartialEq, Eq, clap::ValueEnum, serde::Serialize, serde::Deserialize)]
|
#[derive(Default, Clone, Debug, PartialEq, Eq, clap::ValueEnum, serde::Serialize, serde::Deserialize)]
|
||||||
pub enum SortType {
|
pub enum Order {
|
||||||
#[default]
|
#[default]
|
||||||
Asc,
|
Asc,
|
||||||
Desc,
|
Desc,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Default, Hash, Clone, Debug, PartialEq, Eq, clap::ValueEnum, serde::Serialize, serde::Deserialize)]
|
||||||
|
pub enum Column {
|
||||||
|
#[default]
|
||||||
|
Due,
|
||||||
|
Priority,
|
||||||
|
Created,
|
||||||
|
Tags,
|
||||||
|
Status,
|
||||||
|
Tracked,
|
||||||
|
}
|
||||||
|
|
||||||
#[derive(Default, Clone, Debug, PartialEq, Eq, clap::ValueEnum, serde::Serialize, serde::Deserialize)]
|
#[derive(Default, Clone, Debug, PartialEq, Eq, clap::ValueEnum, serde::Serialize, serde::Deserialize)]
|
||||||
pub enum SortBy {
|
pub enum OrderBy {
|
||||||
#[default]
|
#[default]
|
||||||
Id,
|
Id,
|
||||||
Name,
|
Name,
|
||||||
Due,
|
Due,
|
||||||
Priority,
|
Priority,
|
||||||
Created,
|
Created,
|
||||||
|
Tracked,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(clap::Subcommand, Debug, PartialEq, Eq)]
|
#[derive(clap::Subcommand, Debug, PartialEq, Eq)]
|
||||||
@ -373,7 +359,7 @@ fn program() -> Result<(), error::Error> {
|
|||||||
println!("Marked task {} as complete", colour::id(id));
|
println!("Marked task {} as complete", colour::id(id));
|
||||||
},
|
},
|
||||||
List { options } => {
|
List { options } => {
|
||||||
tasks::list(options, vault_folder)?;
|
tasks::list(options, vault_folder, &state)?;
|
||||||
},
|
},
|
||||||
// All commands which are dealt with in if let chain at start.
|
// All commands which are dealt with in if let chain at start.
|
||||||
Vault(_) | Config(_) | Git { args : _ } | Svn { args : _ } | Switch { name : _ } | GitIgnore => unreachable!(),
|
Vault(_) | Config(_) | Git { args : _ } | Svn { args : _ } | Switch { name : _ } | GitIgnore => unreachable!(),
|
||||||
|
0
src/state.rs
Normal file → Executable file
0
src/state.rs
Normal file → Executable file
0
src/stats.rs
Normal file → Executable file
0
src/stats.rs
Normal file → Executable file
273
src/tasks.rs
Normal file → Executable file
273
src/tasks.rs
Normal file → Executable file
@ -8,6 +8,7 @@ use std::fs;
|
|||||||
use std::fmt;
|
use std::fmt;
|
||||||
use std::ops;
|
use std::ops;
|
||||||
use std::mem;
|
use std::mem;
|
||||||
|
use std::cmp;
|
||||||
use std::path;
|
use std::path;
|
||||||
use std::io::{Write, Seek};
|
use std::io::{Write, Seek};
|
||||||
use std::collections::{HashSet, HashMap};
|
use std::collections::{HashSet, HashMap};
|
||||||
@ -61,7 +62,7 @@ pub struct TimeEntry {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Needs to preserve representation invariant of minutes < 60
|
// Needs to preserve representation invariant of minutes < 60
|
||||||
#[derive(Debug, Copy, Clone, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
|
#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, serde::Serialize, serde::Deserialize)]
|
||||||
pub struct Duration {
|
pub struct Duration {
|
||||||
hours : u16,
|
hours : u16,
|
||||||
minutes : u16,
|
minutes : u16,
|
||||||
@ -427,35 +428,17 @@ fn format_due_date(due : &chrono::NaiveDateTime, include_fuzzy_period : bool, co
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn compare_due_dates<T : Ord>(first : &Option<T>, second : &Option<T>) -> cmp::Ordering {
|
||||||
|
match (first, second) {
|
||||||
|
(None, None) => cmp::Ordering::Equal,
|
||||||
|
(Some(_), None) => cmp::Ordering::Less,
|
||||||
pub fn list(options : super::ListOptions, vault_folder : &path::Path) -> Result<(), error::Error> {
|
(None, Some(_)) => cmp::Ordering::Greater,
|
||||||
|
(Some(first), Some(second)) => first.cmp(second),
|
||||||
let expected = super::ListOptions {
|
|
||||||
name : false,
|
|
||||||
tracked : false,
|
|
||||||
due : false,
|
|
||||||
tags : false,
|
|
||||||
priority : false,
|
|
||||||
status : false,
|
|
||||||
created : false,
|
|
||||||
sort_by : super::SortBy::Id,
|
|
||||||
sort_type : super::SortType::Asc,
|
|
||||||
before : None,
|
|
||||||
after : None,
|
|
||||||
due_in : None,
|
|
||||||
include_completed : false,
|
|
||||||
};
|
|
||||||
|
|
||||||
// If the arguments are not given, use a set of defaults.
|
|
||||||
let options = if options == expected {
|
|
||||||
super::ListOptions::default()
|
|
||||||
}
|
}
|
||||||
else {
|
}
|
||||||
options
|
|
||||||
};
|
pub fn list(mut options : super::ListOptions, vault_folder : &path::Path, state : &state::State) -> Result<(), error::Error> {
|
||||||
|
|
||||||
|
|
||||||
let mut table = comfy_table::Table::new();
|
let mut table = comfy_table::Table::new();
|
||||||
table
|
table
|
||||||
@ -466,130 +449,214 @@ pub fn list(options : super::ListOptions, vault_folder : &path::Path) -> Result<
|
|||||||
|
|
||||||
let mut tasks : Box<dyn Iterator<Item = Task>> = Box::new(Task::load_all(vault_folder, true)?.into_iter());
|
let mut tasks : Box<dyn Iterator<Item = Task>> = Box::new(Task::load_all(vault_folder, true)?.into_iter());
|
||||||
|
|
||||||
// Filter the tasks
|
// Filter the tasks.
|
||||||
if let Some(before) = options.before {
|
if let Some(date) = options.created_before {
|
||||||
tasks = Box::new(tasks.filter(move |t| t.data.created < before));
|
tasks = Box::new(tasks.filter(move |t| t.data.created.date() <= date));
|
||||||
}
|
}
|
||||||
if let Some(after) = options.after {
|
if let Some(date) = options.created_after {
|
||||||
tasks = Box::new(tasks.filter(move |t| t.data.created > after));
|
tasks = Box::new(tasks.filter(move |t| t.data.created.date() >= date));
|
||||||
}
|
}
|
||||||
if let Some(due_in) = options.due_in {
|
|
||||||
let now = chrono::Local::now().naive_local();
|
if let Some(date) = options.due_before {
|
||||||
tasks = Box::new(tasks.filter(move |t| {
|
tasks = Box::new(tasks.filter(move |t| {
|
||||||
if let Some(due) = t.data.due {
|
match compare_due_dates(&t.data.due.map(|d| d.date()), &Some(date)) {
|
||||||
due < now + chrono::Duration::days(i64::from(due_in))
|
cmp::Ordering::Less | cmp::Ordering::Equal => true,
|
||||||
}
|
cmp::Ordering::Greater => false,
|
||||||
else {
|
|
||||||
false
|
|
||||||
}
|
}
|
||||||
}));
|
}));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if let Some(date) = options.due_after {
|
||||||
|
tasks = Box::new(tasks.filter(move |t| {
|
||||||
|
match compare_due_dates(&t.data.due.map(|d| d.date()), &Some(date)) {
|
||||||
|
cmp::Ordering::Greater | cmp::Ordering::Equal => true,
|
||||||
|
cmp::Ordering::Less => false,
|
||||||
|
}
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
if !options.include_completed {
|
if !options.include_completed {
|
||||||
tasks = Box::new(tasks.filter(|t| t.data.completed.is_none()));
|
tasks = Box::new(tasks.filter(|t| t.data.completed.is_none()));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if !options.tag.is_empty() {
|
||||||
|
let specified_tags : HashSet<_> = options.tag.iter().collect();
|
||||||
|
|
||||||
|
tasks = Box::new(tasks.filter(move |t| {
|
||||||
|
let task_tags : HashSet<_> = t.data.tags.iter().collect();
|
||||||
|
|
||||||
|
// Non empty intersection of tags means the task should be displayed
|
||||||
|
specified_tags.intersection(&task_tags).next().is_some()
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
if options.no_dependencies {
|
||||||
|
tasks = Box::new(tasks.filter(move |t| {
|
||||||
|
t.data.dependencies.is_empty()
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
if options.no_dependents {
|
||||||
|
let tasks_with_dependents = state.data.deps.get_tasks_with_dependents();
|
||||||
|
|
||||||
|
tasks = Box::new(tasks.filter(move |t| {
|
||||||
|
!tasks_with_dependents.contains(&t.data.id)
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
let mut tasks : Vec<Task> = tasks.collect();
|
let mut tasks : Vec<Task> = tasks.collect();
|
||||||
|
|
||||||
|
|
||||||
// Sort the tasks
|
// Sort the tasks.
|
||||||
use super::{SortBy, SortType};
|
use super::{OrderBy, Order};
|
||||||
match options.sort_by {
|
match options.order_by {
|
||||||
SortBy::Id => {
|
OrderBy::Id => {
|
||||||
match options.sort_type {
|
match options.order {
|
||||||
SortType::Asc => {
|
Order::Asc => {
|
||||||
tasks.sort_by(|t1, t2| t1.data.id.cmp(&t2.data.id));
|
tasks.sort_by(|t1, t2| t1.data.id.cmp(&t2.data.id));
|
||||||
},
|
},
|
||||||
SortType::Desc => {
|
Order::Desc => {
|
||||||
tasks.sort_by(|t1, t2| t2.data.id.cmp(&t1.data.id));
|
tasks.sort_by(|t1, t2| t2.data.id.cmp(&t1.data.id));
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
SortBy::Name => {
|
OrderBy::Name => {
|
||||||
match options.sort_type {
|
match options.order {
|
||||||
SortType::Asc => {
|
Order::Asc => {
|
||||||
tasks.sort_by(|t1, t2| t1.data.name.cmp(&t2.data.name));
|
tasks.sort_by(|t1, t2| t1.data.name.cmp(&t2.data.name));
|
||||||
},
|
},
|
||||||
SortType::Desc => {
|
Order::Desc => {
|
||||||
tasks.sort_by(|t1, t2| t2.data.name.cmp(&t1.data.name));
|
tasks.sort_by(|t1, t2| t2.data.name.cmp(&t1.data.name));
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
SortBy::Due => {
|
OrderBy::Due => {
|
||||||
match options.sort_type {
|
match options.order {
|
||||||
SortType::Asc => {
|
Order::Asc => {
|
||||||
tasks.sort_by(|t1, t2| t1.data.due.cmp(&t2.data.due));
|
tasks.sort_by(|t1, t2| compare_due_dates(&t1.data.due, &t2.data.due));
|
||||||
},
|
},
|
||||||
SortType::Desc => {
|
Order::Desc => {
|
||||||
tasks.sort_by(|t1, t2| t2.data.due.cmp(&t1.data.due));
|
tasks.sort_by(|t1, t2| compare_due_dates(&t2.data.due, &t1.data.due));
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
SortBy::Priority => {
|
OrderBy::Priority => {
|
||||||
match options.sort_type {
|
match options.order {
|
||||||
SortType::Asc => {
|
Order::Asc => {
|
||||||
tasks.sort_by(|t1, t2| t1.data.priority.cmp(&t2.data.priority));
|
tasks.sort_by(|t1, t2| t1.data.priority.cmp(&t2.data.priority));
|
||||||
},
|
},
|
||||||
SortType::Desc => {
|
Order::Desc => {
|
||||||
tasks.sort_by(|t1, t2| t2.data.priority.cmp(&t1.data.priority));
|
tasks.sort_by(|t1, t2| t2.data.priority.cmp(&t1.data.priority));
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
SortBy::Created => {
|
OrderBy::Created => {
|
||||||
match options.sort_type {
|
match options.order {
|
||||||
SortType::Asc => {
|
Order::Asc => {
|
||||||
tasks.sort_by(|t1, t2| t1.data.created.cmp(&t2.data.created));
|
tasks.sort_by(|t1, t2| t1.data.created.cmp(&t2.data.created));
|
||||||
},
|
},
|
||||||
SortType::Desc => {
|
Order::Desc => {
|
||||||
tasks.sort_by(|t1, t2| t2.data.created.cmp(&t1.data.created));
|
tasks.sort_by(|t1, t2| t2.data.created.cmp(&t1.data.created));
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
OrderBy::Tracked => {
|
||||||
|
match options.order {
|
||||||
|
Order::Asc => {
|
||||||
|
tasks.sort_by(|t1, t2| TimeEntry::total(&t1.data.time_entries).cmp(&TimeEntry::total(&t2.data.time_entries)));
|
||||||
|
},
|
||||||
|
Order::Desc => {
|
||||||
|
tasks.sort_by(|t1, t2| TimeEntry::total(&t2.data.time_entries).cmp(&TimeEntry::total(&t1.data.time_entries)));
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Include the required columns
|
// Include the required columns
|
||||||
let mut headers = vec!["Id"];
|
let mut headers = vec!["Id", "Name"];
|
||||||
|
|
||||||
if options.name { headers.push("Name") };
|
// Remove duplicate columns.
|
||||||
if options.tracked { headers.push("Tracked") };
|
{
|
||||||
if options.due { headers.push("Due") };
|
let mut columns = HashSet::new();
|
||||||
if options.tags { headers.push("Tags") };
|
|
||||||
if options.priority { headers.push("Priority") };
|
options.column = options.column
|
||||||
if options.status { headers.push("Status") };
|
.into_iter()
|
||||||
if options.created { headers.push("Created") };
|
.filter(|c| {
|
||||||
|
if columns.contains(c) {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
columns.insert(c.clone());
|
||||||
|
true
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.collect();
|
||||||
|
}
|
||||||
|
|
||||||
|
use super::Column;
|
||||||
|
for column in &options.column {
|
||||||
|
match column {
|
||||||
|
Column::Tracked => {
|
||||||
|
headers.push("Tracked");
|
||||||
|
},
|
||||||
|
Column::Due => {
|
||||||
|
headers.push("Due");
|
||||||
|
},
|
||||||
|
Column::Tags => {
|
||||||
|
headers.push("Tags");
|
||||||
|
},
|
||||||
|
Column::Priority => {
|
||||||
|
headers.push("Priority");
|
||||||
|
},
|
||||||
|
Column::Status => {
|
||||||
|
headers.push("Status");
|
||||||
|
},
|
||||||
|
Column::Created => {
|
||||||
|
headers.push("Created");
|
||||||
|
},
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
table.set_header(headers);
|
table.set_header(headers);
|
||||||
|
|
||||||
for task in tasks {
|
for task in tasks {
|
||||||
|
|
||||||
let mut row = vec![task.data.id.to_string()];
|
let mut row = vec![task.data.id.to_string(), task.data.name.clone()];
|
||||||
|
|
||||||
if options.name { row.push(task.data.name); }
|
for column in &options.column {
|
||||||
if options.tracked {
|
match column {
|
||||||
let duration = TimeEntry::total(&task.data.time_entries);
|
Column::Tracked => {
|
||||||
row.push(
|
let duration = TimeEntry::total(&task.data.time_entries);
|
||||||
if duration == Duration::zero() { String::new() } else { duration.to_string() }
|
row.push(
|
||||||
);
|
if duration == Duration::zero() { String::new() } else { duration.to_string() }
|
||||||
}
|
);
|
||||||
if options.due {
|
},
|
||||||
row.push(match task.data.due {
|
Column::Due => {
|
||||||
Some(due) => format_due_date(&due, task.data.completed.is_none(), false),
|
row.push(match task.data.due {
|
||||||
None => String::new()
|
Some(due) => format_due_date(&due, task.data.completed.is_none(), false),
|
||||||
});
|
None => String::new()
|
||||||
}
|
});
|
||||||
if options.tags { row.push(format_hash_set(&task.data.tags)?); }
|
},
|
||||||
if options.priority { row.push(task.data.priority.to_string()); }
|
Column::Tags => {
|
||||||
if options.status {
|
row.push(format_hash_set(&task.data.tags)?);
|
||||||
row.push(
|
},
|
||||||
if task.data.completed.is_some() {
|
Column::Priority => {
|
||||||
String::from("complete")
|
row.push(task.data.priority.to_string());
|
||||||
}
|
},
|
||||||
else {
|
Column::Status => {
|
||||||
String::from("incomplete")
|
row.push(
|
||||||
}
|
if task.data.completed.is_some() {
|
||||||
);
|
String::from("complete")
|
||||||
}
|
}
|
||||||
if options.created {
|
else {
|
||||||
row.push(task.data.created.round_subsecs(0).to_string());
|
String::from("incomplete")
|
||||||
|
}
|
||||||
|
);
|
||||||
|
},
|
||||||
|
Column::Created => {
|
||||||
|
row.push(task.data.created.round_subsecs(0).to_string());
|
||||||
|
},
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
table.add_row(row);
|
table.add_row(row);
|
||||||
@ -651,9 +718,7 @@ impl TimeEntry {
|
|||||||
.map(|e| e.duration)
|
.map(|e| e.duration)
|
||||||
.fold(Duration::zero(), |a, d| a + d)
|
.fold(Duration::zero(), |a, d| a + d)
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
impl TimeEntry {
|
|
||||||
pub fn new(hours : u16, minutes : u16) -> Self {
|
pub fn new(hours : u16, minutes : u16) -> Self {
|
||||||
|
|
||||||
let (hours, minutes) = {
|
let (hours, minutes) = {
|
||||||
|
0
src/vault.rs
Normal file → Executable file
0
src/vault.rs
Normal file → Executable file
0
src/vcs.rs
Normal file → Executable file
0
src/vcs.rs
Normal file → Executable file
Loading…
Reference in New Issue
Block a user