2024-08-15 22:09:51 +03:00
|
|
|
use std::collections::BTreeMap;
|
|
|
|
|
2024-08-16 02:27:50 +03:00
|
|
|
use chrono::{DateTime, Datelike, Duration, Local, Utc};
|
2024-08-15 22:09:51 +03:00
|
|
|
use clap::ValueEnum;
|
|
|
|
|
|
|
|
use crate::{get_char, get_color, get_color_map, Commit, DAYS, RESET};
|
|
|
|
|
|
|
|
pub struct Heatmap {
|
|
|
|
data: [Vec<u32>; 7],
|
2024-08-16 02:27:50 +03:00
|
|
|
start_date: DateTime<Local>,
|
|
|
|
end_date: DateTime<Local>,
|
2024-08-15 22:09:51 +03:00
|
|
|
commits: Vec<Commit>,
|
|
|
|
months: Vec<(usize, String)>,
|
|
|
|
}
|
|
|
|
|
|
|
|
impl Heatmap {
|
2024-08-16 02:27:50 +03:00
|
|
|
pub fn new(
|
|
|
|
start_date: DateTime<Local>,
|
|
|
|
end_date: DateTime<Local>,
|
|
|
|
commits: Vec<Commit>,
|
|
|
|
) -> Self {
|
2024-08-15 22:09:51 +03:00
|
|
|
let mut heatmap = Self {
|
|
|
|
data: [vec![], vec![], vec![], vec![], vec![], vec![], vec![]],
|
|
|
|
start_date,
|
|
|
|
end_date,
|
|
|
|
commits,
|
|
|
|
months: vec![],
|
|
|
|
};
|
|
|
|
|
|
|
|
let mut grouped_commits = BTreeMap::new();
|
|
|
|
|
|
|
|
for commit in &heatmap.commits {
|
2024-08-16 02:27:50 +03:00
|
|
|
let commit_day = commit.time.date_naive();
|
2024-08-15 22:09:51 +03:00
|
|
|
let record = grouped_commits.entry(commit_day).or_insert(0);
|
|
|
|
*record += 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
let mut current_day = start_date;
|
2024-08-16 02:27:50 +03:00
|
|
|
let mut day_of_week = (current_day.weekday().num_days_from_monday()) % 7;
|
2024-08-15 22:09:51 +03:00
|
|
|
|
|
|
|
if day_of_week != 0 {
|
|
|
|
for i in 0..day_of_week {
|
|
|
|
heatmap.data[i as usize].push(0);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
while current_day <= end_date {
|
|
|
|
let month_name = current_day.format("%b").to_string();
|
|
|
|
|
|
|
|
if current_day == start_date {
|
|
|
|
heatmap.months.push((0, month_name));
|
|
|
|
}
|
|
|
|
else if current_day.day0() == 0 {
|
|
|
|
heatmap
|
|
|
|
.months
|
|
|
|
.push((heatmap.data[day_of_week as usize].len(), month_name));
|
|
|
|
}
|
|
|
|
|
2024-08-16 02:27:50 +03:00
|
|
|
let value = grouped_commits.get(¤t_day.date_naive());
|
2024-08-15 22:09:51 +03:00
|
|
|
match value {
|
|
|
|
Some(val) => heatmap.data[day_of_week as usize].push(*val),
|
|
|
|
None => heatmap.data[day_of_week as usize].push(0),
|
|
|
|
}
|
2024-08-16 02:27:50 +03:00
|
|
|
// println!("{} {value:?}", current_day.date_naive());
|
2024-08-15 22:09:51 +03:00
|
|
|
current_day += Duration::days(1);
|
2024-08-16 02:27:50 +03:00
|
|
|
day_of_week = current_day.weekday().num_days_from_monday() % 7;
|
2024-08-15 22:09:51 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
heatmap
|
|
|
|
}
|
|
|
|
|
|
|
|
fn months_row(&self) -> String {
|
|
|
|
let mut row = " ".to_string();
|
|
|
|
|
|
|
|
let mut last_index = 0;
|
|
|
|
|
|
|
|
for (index, month) in &self.months {
|
|
|
|
let range_size = (index * 2).saturating_sub(last_index * 2).saturating_sub(3);
|
|
|
|
for _i in 0..range_size {
|
|
|
|
row.push(' ');
|
|
|
|
}
|
|
|
|
last_index = *index;
|
|
|
|
row.push_str(month);
|
|
|
|
}
|
|
|
|
|
|
|
|
row
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn print(&self) {
|
|
|
|
println!(
|
|
|
|
"{} - {}",
|
|
|
|
self.start_date.format("%Y-%b-%d"),
|
|
|
|
self.end_date.format("%Y-%b-%d")
|
|
|
|
);
|
|
|
|
println!("{} commits\n", &self.commits.len());
|
|
|
|
println!("{}", self.months_row());
|
|
|
|
for (day, row) in DAYS.iter().zip(&self.data) {
|
|
|
|
print!("{day} ");
|
|
|
|
for val in row {
|
|
|
|
let color = &get_color_map()[get_color(*val)];
|
|
|
|
print!("{color}{}{RESET} ", get_char());
|
|
|
|
}
|
|
|
|
print!("\n");
|
|
|
|
}
|
|
|
|
print!("\nLess ");
|
|
|
|
for color in get_color_map() {
|
|
|
|
print!("{color}{}{RESET} ", get_char())
|
|
|
|
}
|
|
|
|
print!(" More\n");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[derive(Clone, Debug, PartialEq, Eq, ValueEnum)]
|
|
|
|
pub enum HeatmapColors {
|
|
|
|
Green,
|
|
|
|
Red,
|
|
|
|
}
|