Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix #32

Open
wants to merge 2 commits into
base: master
Choose a base branch
from
Open

Fix #32

Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
98 changes: 50 additions & 48 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,13 @@ extern crate chrono;
#[macro_use]
extern crate clap;
extern crate dirs;
extern crate math;
extern crate open;
extern crate rprompt;
extern crate math;

use chrono::prelude::*;
use clap::{Arg, SubCommand};
use math::round;
use std::cmp;
use std::collections::HashMap;
use std::env;
Expand All @@ -20,7 +21,6 @@ use std::io::Write;
use std::path::PathBuf;
use std::process;
use std::process::Command;
use math::round;

fn main() {
let matches = app_from_crate!()
Expand All @@ -46,7 +46,8 @@ fn main() {
let ago: i64 = if habitctl.first_date().is_some() {
cmp::min(
7,
Local::today().naive_local()
Local::today()
.naive_local()
.signed_duration_since(habitctl.first_date().unwrap())
.num_days(),
)
Expand Down Expand Up @@ -77,15 +78,15 @@ fn main() {
ago
};
habitctl.ask(ago);
habitctl.log(&vec![]);
habitctl.log(&[]);
}
("edit", Some(_)) => habitctl.edit(),
("edith", Some(_)) => habitctl.edith(),
_ => {
// no subcommand used
habitctl.assert_habits();
habitctl.ask(ago);
habitctl.log(&vec![]);
habitctl.log(&[]);
}
}
}
Expand Down Expand Up @@ -134,11 +135,11 @@ impl HabitCtl {
fs::File::create(&log_file).unwrap();

let file = OpenOptions::new().append(true).open(&habits_file).unwrap();
write!(
writeln!(
&file,
"# The numbers specifies how often you want to do a habit:\n"
);
write!(
writeln!(
&file,
"# 1 means daily, 7 means weekly, 0 means you're just tracking the habit. Some examples:\n"
);
Expand Down Expand Up @@ -178,20 +179,21 @@ impl HabitCtl {

if let Some(last_date) = last_date {
if last_date != entry.date {
write!(&file, "\n").unwrap();
writeln!(&file, "\n").unwrap();
}
}

write!(
writeln!(
&file,
"{}\t{}\t{}\n",
&entry.date.format("%F"),
&entry.habit,
&entry.value
).unwrap();
)
.unwrap();
}

fn log(&self, filters: &Vec<&str>) {
fn log(&self, filters: &[&str]) {
let to = Local::today().naive_local();
let from = to.checked_sub_signed(chrono::Duration::days(100)).unwrap();

Expand Down Expand Up @@ -220,14 +222,12 @@ impl HabitCtl {
continue;
}

self.print_habit_row(&habit, from, to);
self.print_habit_row(habit, from, to);
println!();
}

if !self.habits.is_empty() {
let date = to
.checked_sub_signed(chrono::Duration::days(1))
.unwrap();
let date = to.checked_sub_signed(chrono::Duration::days(1)).unwrap();
println!("Yesterday's score: {}%", self.get_score(&date));
}
}
Expand All @@ -239,7 +239,7 @@ impl HabitCtl {
while current <= to {
print!(
"{0: >1}",
&self.status_to_symbol(&self.day_status(&habit, &current))
&self.status_to_symbol(&self.day_status(habit, &current))
);

current = current
Expand Down Expand Up @@ -275,7 +275,8 @@ impl HabitCtl {
}

fn ask(&mut self, ago: i64) {
let from = Local::today().naive_local()
let from = Local::today()
.naive_local()
.checked_sub_signed(chrono::Duration::days(ago))
.unwrap();

Expand All @@ -291,22 +292,22 @@ impl HabitCtl {
}

for habit in self.get_todo(&current) {
self.print_habit_row(&habit, log_from, current.clone());
let l = format!("[y/n/s/⏎] ");
self.print_habit_row(&habit, log_from, current);
let l = "[y/n/s/⏎] ".to_string();

let mut value;
loop {
value = String::from(rprompt::prompt_reply_stdout(&l).unwrap());
value = rprompt::prompt_reply_stdout(&l).unwrap();
value = value.trim_end().to_string();

if value == "y" || value == "n" || value == "s" || value == "" {
if value == "y" || value == "n" || value == "s" || value.is_empty() {
break;
}
}

if value != "" {
if !value.is_empty() {
self.entry(&Entry {
date: current.clone(),
date: current,
habit: habit.name,
value,
});
Expand Down Expand Up @@ -362,15 +363,14 @@ impl HabitCtl {

for line in file.lines() {
let l = line.unwrap();
if l == "" {
if l.is_empty() {
continue;
}
let split = l.split('\t');
let parts: Vec<&str> = split.collect();

let entry = Entry {
date: NaiveDate::parse_from_str(parts[0], "%Y-%m-%d")
.unwrap(),
date: NaiveDate::parse_from_str(parts[0], "%Y-%m-%d").unwrap(),
habit: parts[1].to_string(),
value: parts[2].to_string(),
};
Expand All @@ -388,24 +388,22 @@ impl HabitCtl {
}

fn day_status(&self, habit: &Habit, date: &NaiveDate) -> DayStatus {
if let Some(entry) = self.get_entry(&date, &habit.name) {
if let Some(entry) = self.get_entry(date, &habit.name) {
if entry.value == "y" {
DayStatus::Done
} else if entry.value == "s" {
DayStatus::Skipped
} else if self.habit_satisfied(habit, &date) {
} else if self.habit_satisfied(habit, date) {
DayStatus::Satisfied
} else if self.habit_skipified(habit, &date) {
} else if self.habit_skipified(habit, date) {
DayStatus::Skipified
} else {
DayStatus::NotDone
}
} else if self.habit_warning(habit, date) {
DayStatus::Warning
} else {
if self.habit_warning(habit, &date) {
DayStatus::Warning
} else {
DayStatus::Unknown
}
}
}

Expand All @@ -417,7 +415,7 @@ impl HabitCtl {
DayStatus::Satisfied => "─",
DayStatus::Skipped => "•",
DayStatus::Skipified => "·",
DayStatus::Warning => "!"
DayStatus::Warning => "!",
};
String::from(symbol)
}
Expand All @@ -444,7 +442,7 @@ impl HabitCtl {
false
}

fn habit_skipified(&self, habit: &Habit, date: &NaiveDate) -> bool {
fn habit_skipified(&self, habit: &Habit, date: &NaiveDate) -> bool {
if habit.every_days < 1 {
return false;
}
Expand All @@ -466,7 +464,7 @@ impl HabitCtl {
false
}

fn habit_warning(&self, habit: &Habit, date: &NaiveDate) -> bool {
fn habit_warning(&self, habit: &Habit, date: &NaiveDate) -> bool {
if habit.every_days < 1 {
return false;
}
Expand All @@ -477,9 +475,13 @@ impl HabitCtl {
let mut current = *date;
while current >= from {
if let Some(entry) = self.get_entry(&current, &habit.name) {
if (entry.value == "y" || entry.value == "s") && current - from > chrono::Duration::days(0) {
return false;
} else if (entry.value == "y" || entry.value == "s") && current - from == chrono::Duration::days(0) {
if (entry.value == "y" || entry.value == "s")
&& current - from > chrono::Duration::days(0)
{
return false;
} else if (entry.value == "y" || entry.value == "s")
&& current - from == chrono::Duration::days(0)
{
return true;
}
}
Expand Down Expand Up @@ -507,14 +509,11 @@ impl HabitCtl {

fn first_date(&self) -> Option<NaiveDate> {
self.get_entries()
.first()
.and_then(|entry| Some(entry.date.clone()))
.first().map(|entry| entry.date)
}

fn last_date(&self) -> Option<NaiveDate> {
self.get_entries()
.last()
.and_then(|entry| Some(entry.date.clone()))
self.get_entries().last().map(|entry| entry.date)
}

fn get_score(&self, score_date: &NaiveDate) -> f32 {
Expand All @@ -529,7 +528,7 @@ impl HabitCtl {
.habits
.iter()
.map(|habit| {
let status = self.day_status(&habit, &score_date);
let status = self.day_status(habit, score_date);
habit.every_days > 0
&& (status == DayStatus::Done || status == DayStatus::Satisfied)
})
Expand All @@ -540,15 +539,18 @@ impl HabitCtl {
.habits
.iter()
.map(|habit| {
let status = self.day_status(&habit, &score_date);
let status = self.day_status(habit, score_date);
habit.every_days > 0
&& (status == DayStatus::Skipped || status == DayStatus::Skipified)
})
.collect();
skip.retain(|value| *value);

if !todo.is_empty() {
round::ceil((100.0 * done.len() as f32 / (todo.len() - skip.len()) as f32).into(), 1) as f32
round::ceil(
(100.0 * done.len() as f32 / (todo.len() - skip.len()) as f32).into(),
1,
) as f32
} else {
0.0
}
Expand All @@ -571,7 +573,7 @@ impl HabitCtl {
}

fn spark(&self, score: f32) -> String {
let sparks = vec![" ", "▁", "▂", "▃", "▄", "▅", "▆", "▇", "█"];
let sparks = [" ", "▁", "▂", "▃", "▄", "▅", "▆", "▇", "█"];
let i = cmp::min(sparks.len() - 1, (score / sparks.len() as f32) as usize);
String::from(sparks[i])
}
Expand Down