Added 'change' subcommand

This commit is contained in:
Nikolas Schmidt-Voigt 2023-01-03 10:16:16 +01:00
parent f03c96cb5f
commit e10b11920d
3 changed files with 95 additions and 18 deletions

View file

@ -263,6 +263,17 @@ bartib list --from 2021-09-01 --to 2021-09-05 # list activities in a given ti
bartib list --project "The most exciting project" # list activities for a given project
```
### Edit activities
```bash
bartib change -d "A new description" # change the description of the current activity
bartib change -p "Another project" # change the project for the current activity
bartib change -t 8:15 # change the start time of the current activity
bartib edit # open the activity log in the editor you have defined in your `EDITOR` environment variable
bartib edit -e vim # open the activity log in a given editor
```
### Doing other stuff
```bash
@ -270,9 +281,6 @@ bartib current # show currently running activity
bartib projects # list all projects ever used
bartib projects -c # show current project only
bartib edit # open the activity log in the editor you have defined in your `EDITOR` environment variable
bartib edit -e vim # open the activity log in a given editor
bartib check # check your activity log for invalid lines
bartib sanity # check for activities with logical errors (e.g activities with negative duration)
```

View file

@ -2,10 +2,10 @@ use anyhow::{anyhow, bail, Context, Error, Result};
use chrono::NaiveDateTime;
use std::process::Command;
use crate::conf;
use crate::data::activity;
use crate::data::bartib_file;
use crate::data::getter;
use crate::conf;
use crate::view::format_util;
// starts a new activity
@ -52,6 +52,50 @@ fn save_new_activity(
.context(format!("Could not write to file: {}", file_name))
}
pub fn change(
file_name: &str,
project_name: Option<&str>,
activity_description: Option<&str>,
time: Option<NaiveDateTime>,
) -> Result<()> {
let mut file_content = bartib_file::get_file_content(file_name)?;
for line in file_content.iter_mut() {
if let Ok(activity) = &mut line.activity {
if !activity.is_stopped() {
let mut changed = false;
if let Some(project_name) = project_name {
activity.project = project_name.to_string();
changed = true;
}
if let Some(activity_description) = activity_description {
activity.description = activity_description.to_string();
changed = true;
}
if let Some(time) = time {
activity.start = time;
changed = true;
}
if changed {
println!(
"Changed activity: \"{}\" ({}) started at {}",
activity.description,
activity.project,
activity.start.format(conf::FORMAT_DATETIME)
);
line.set_changed();
}
}
}
}
bartib_file::write_to_file(file_name, &file_content)
.context(format!("Could not write to file: {}", file_name))
}
// stops all currently running activities
pub fn stop(file_name: &str, time: Option<NaiveDateTime>) -> Result<()> {
let mut file_content = bartib_file::get_file_content(file_name)?;
@ -63,7 +107,7 @@ pub fn stop(file_name: &str, time: Option<NaiveDateTime>) -> Result<()> {
// cancels all currently running activities
pub fn cancel(file_name: &str) -> Result<()> {
let file_content = bartib_file::get_file_content(file_name)?;
let mut new_file_content : Vec<bartib_file::Line> = Vec::new();
let mut new_file_content: Vec<bartib_file::Line> = Vec::new();
for line in file_content {
match &line.activity {
@ -71,14 +115,15 @@ pub fn cancel(file_name: &str) -> Result<()> {
if activity.is_stopped() {
new_file_content.push(line);
} else {
println!("Canceled activity: \"{}\" ({}) started at {}",
println!(
"Canceled activity: \"{}\" ({}) started at {}",
activity.description,
activity.project,
activity.start.format(conf::FORMAT_DATETIME)
);
}
},
Err(_) => new_file_content.push(line)
}
Err(_) => new_file_content.push(line),
}
}
@ -86,28 +131,34 @@ pub fn cancel(file_name: &str) -> Result<()> {
.context(format!("Could not write to file: {}", file_name))
}
// continue last activity
pub fn continue_last_activity(
file_name: &str,
project_name: Option<&str>,
activity_description: Option<&str>,
time: Option<NaiveDateTime>,
number: usize
number: usize,
) -> Result<()> {
let mut file_content = bartib_file::get_file_content(file_name)?;
let descriptions_and_projects : Vec<(&String, &String)> = getter::get_descriptions_and_projects(&file_content);
let descriptions_and_projects: Vec<(&String, &String)> =
getter::get_descriptions_and_projects(&file_content);
if descriptions_and_projects.is_empty() {
bail!("No activity has been started before.")
}
if number > descriptions_and_projects.len() {
bail!(format!("Less than {} distinct activities have been logged yet", number));
bail!(format!(
"Less than {} distinct activities have been logged yet",
number
));
}
let i = descriptions_and_projects.len().saturating_sub(number).saturating_sub(1);
let i = descriptions_and_projects
.len()
.saturating_sub(number)
.saturating_sub(1);
let optional_description_and_project = descriptions_and_projects.get(i);
if let Some((description, project)) = optional_description_and_project {
@ -119,7 +170,10 @@ pub fn continue_last_activity(
stop_all_running_activities(&mut file_content, time);
save_new_activity(file_name, &mut file_content, new_activity)
} else {
bail!(format!("Less than {} distinct activities have been logged yet", number));
bail!(format!(
"Less than {} distinct activities have been logged yet",
number
));
}
}

View file

@ -126,6 +126,13 @@ fn main() -> Result<()> {
)
.arg(&arg_time),
)
.subcommand(
SubCommand::with_name("change")
.about("changes the current activity")
.arg(&arg_description)
.arg(&arg_project)
.arg(&arg_time)
)
.subcommand(
SubCommand::with_name("stop")
.about("stops all currently running activities")
@ -251,6 +258,14 @@ fn run_subcommand(matches: &ArgMatches, file_name: &str) -> Result<()> {
bartib::controller::manipulation::start(file_name, project_name, activity_description, time)
}
("change", Some(sub_m)) => {
let project_name = sub_m.value_of("project");
let activity_description = sub_m.value_of("description");
let time = get_time_argument_or_ignore(sub_m.value_of("time"), "-t/--time")
.map(|t| Local::today().naive_local().and_time(t));
bartib::controller::manipulation::change(file_name, project_name, activity_description, time)
}
("continue", Some(sub_m)) => {
let project_name = sub_m.value_of("project");
let activity_description = sub_m.value_of("description");