list tasks of a certain date or date range

This commit is contained in:
Nikolas Schmidt-Voigt 2021-06-30 22:23:02 +02:00
parent e1804a7d06
commit 5f03c20706
4 changed files with 105 additions and 15 deletions

View file

@ -1,2 +1,3 @@
pub static FORMAT_DATETIME : &str = "%F %R";
pub static FORMAT_TIME : &str = "%R";
pub static FORMAT_TIME : &str = "%R";
pub static FORMAT_DATE : &str = "%F";

View file

@ -1,4 +1,7 @@
mod conf;
use chrono::NaiveDate;
use chrono::naive;
pub mod conf;
mod project;
mod task;
mod table;
@ -6,6 +9,13 @@ mod format_util;
mod output;
pub mod bartib_file;
pub struct TaskFilter {
pub number_of_tasks: Option<usize>,
pub from_date: Option<NaiveDate>,
pub to_date: Option<NaiveDate>,
pub date: Option<NaiveDate>
}
// starts a new task
pub fn start(file_name: &str, project_name: &str, task_description: &str) {
let mut file_content = bartib_file::get_file_content(file_name);
@ -39,14 +49,20 @@ pub fn list_running(file_name: &str) {
// lists tracked tasks
//
// the tasks will be ordered chronologically.
pub fn list(file_name: &str, number_of_tasks: Option<usize>) {
pub fn list(file_name: &str, filter: TaskFilter, do_group_tasks: bool) {
let file_content = bartib_file::get_file_content(file_name);
let mut all_tasks : Vec<&task::Task> = get_tasks(&file_content).collect();
let tasks = get_tasks(&file_content);
let mut filtered_tasks : Vec<&task::Task> = filter_tasks(tasks, &filter).collect();
all_tasks.sort_by_key(|task| task.start);
filtered_tasks.sort_by_key(|task| task.start);
let first_element = get_index_of_first_element(all_tasks.len(), number_of_tasks);
output::list_tasks_grouped_by_date(&all_tasks[first_element .. all_tasks.len()]);
let first_element = get_index_of_first_element(filtered_tasks.len(), filter.number_of_tasks);
if do_group_tasks {
output::list_tasks_grouped_by_date(&filtered_tasks[first_element .. filtered_tasks.len()]);
} else {
output::list_tasks(&filtered_tasks[first_element .. filtered_tasks.len()], true);
}
}
fn get_index_of_first_element(length: usize, sub: Option<usize>) -> usize {
@ -78,4 +94,19 @@ fn get_tasks(file_content: &[bartib_file::Line]) -> impl Iterator<Item = &task::
file_content.iter()
.map(|line| line.task.as_ref())
.filter_map(|task_result| task_result.ok())
}
fn filter_tasks<'a>(tasks : impl Iterator<Item = &'a task::Task>, filter : &TaskFilter) -> impl Iterator<Item = &'a task::Task> {
let from_date : NaiveDate;
let to_date : NaiveDate;
if let Some(date) = filter.date {
from_date = date;
to_date = date;
} else {
from_date = filter.from_date.unwrap_or(naive::MIN_DATE);
to_date = filter.to_date.unwrap_or(naive::MAX_DATE);
}
tasks.filter(move |task| task.start.date() >= from_date && task.start.date() <= to_date)
}

View file

@ -1,4 +1,5 @@
use clap::{App, AppSettings, Arg, SubCommand};
use chrono::NaiveDate;
fn main() {
let matches = App::new("bartib")
@ -50,11 +51,43 @@ fn main() {
.arg(
Arg::with_name("number")
.short("n")
.long("number")
.value_name("NUMBER")
.help("maximum number of tasks to display")
.required(false)
.takes_value(true)
)
.arg(
Arg::with_name("from_date")
.long("from")
.value_name("FROM_DATE")
.help("begin of date range (inclusive)")
.requires("to_date")
.takes_value(true)
)
.arg(
Arg::with_name("to_date")
.long("to")
.value_name("TO_DATE")
.help("end of date range (inclusive)")
.requires("from_date")
.takes_value(true)
)
.arg(
Arg::with_name("date")
.short("d")
.long("date")
.value_name("DATE")
.help("show tasks of a certain date only")
.required(false)
.conflicts_with_all(&["from_date", "to_date"])
.takes_value(true)
)
.arg(
Arg::with_name("no_grouping")
.long("no_grouping")
.help("do not group tasks by date in list")
)
)
.get_matches();
@ -71,8 +104,15 @@ fn main() {
("stop", Some(_)) => bartib::stop(file_name),
("current", Some(_)) => bartib::list_running(file_name),
("list", Some(sub_m)) => {
let number_of_tasks : Option<usize> = get_number_argument_or_ignore(sub_m.value_of("number"), "-n/--number");
bartib::list(file_name, number_of_tasks)
let filter = bartib::TaskFilter {
number_of_tasks : get_number_argument_or_ignore(sub_m.value_of("number"), "-n/--number"),
from_date : get_date_argument_or_ignore(sub_m.value_of("from_date"), "--from"),
to_date : get_date_argument_or_ignore(sub_m.value_of("to_date"), "--to"),
date : get_date_argument_or_ignore(sub_m.value_of("date"), "-d/--date")
};
let do_group_tasks = !sub_m.is_present("no_grouping");
bartib::list(file_name, filter, do_group_tasks);
},
_ => println!("Unknown command")
}
@ -92,3 +132,19 @@ fn get_number_argument_or_ignore(number_argument : Option<&str>, argument_name :
None
}
}
fn get_date_argument_or_ignore(date_argument : Option<&str>, argument_name : &str) -> Option<NaiveDate> {
if let Some(date_string) = date_argument {
let parsing_result = NaiveDate::parse_from_str(date_string, bartib::conf::FORMAT_DATE);
match parsing_result {
Ok(date) => Some(date),
Err(parsing_error) => {
println!("Can not parse \"{}\" as date. Argument for {} is ignored ({})", date_string, argument_name, parsing_error);
None
}
}
} else {
None
}
}

View file

@ -7,7 +7,7 @@ use crate::table;
use crate::conf;
// displays a table with tasks
pub fn list_tasks(tasks: &[&task::Task]) {
pub fn list_tasks(tasks: &[&task::Task], with_start_dates: bool) {
if tasks.is_empty() {
println!("No task to display");
return
@ -16,7 +16,7 @@ pub fn list_tasks(tasks: &[&task::Task]) {
let mut task_table = table::Table::new(vec!["Started", "Stopped", "Description", "Project", "Duration"]);
tasks.iter()
.map(get_task_table_row_without_dates)
.map(|t| get_task_table_row(&t, with_start_dates))
.for_each(|row| task_table.add_row(row));
println!("\n{}", task_table);
@ -33,7 +33,7 @@ pub fn list_tasks_grouped_by_date(tasks: &[&task::Task]) {
for (date, task_list) in tasks_by_date {
println!("{}", date);
list_tasks(&task_list);
list_tasks(&task_list, false);
println!();
}
}
@ -58,10 +58,10 @@ pub fn list_running_tasks(running_tasks: &[&task::Task]) {
}
}
// create a row for a task without showing dates
// create a row for a task
//
// the date of the end is shown when it is not the same date as the start
fn get_task_table_row_without_dates(task: &&task::Task) -> table::Row {
fn get_task_table_row(task: &&task::Task, with_start_dates : bool) -> table::Row {
let end = task.end.map_or_else(
|| "-".to_string(),
|end| if task.start.date() == end.date() {
@ -72,8 +72,10 @@ fn get_task_table_row_without_dates(task: &&task::Task) -> table::Row {
}
);
let start_format = if with_start_dates {conf::FORMAT_DATETIME} else {conf::FORMAT_TIME};
table::Row::new(vec![
task.start.format(conf::FORMAT_TIME).to_string(),
task.start.format(start_format).to_string(),
end,
task.description.clone(),
task.project.to_string(),