M src/activity-graph.css => src/activity-graph.css +9 -4
@@ 14,7 14,6 @@ html {
}
.blob {
- background-color: #fff;
width: 8px;
height: 8px;
border: solid #888 1px;
@@ 25,12 24,16 @@ html {
border-color: #222;
}
-.lvl0 { background-color: #fff; }
+.lvl0 { background-color: #fefefe; }
.lvl1 { background-color: #e1e1f7; }
.lvl2 { background-color: #c3c3ef; }
.lvl3 { background-color: #a5a5e7; }
.lvl4 { background-color: #8888de; }
+.filler-day {
+ opacity: 0.3;
+}
+
@media (prefers-reduced-motion: reduce) {
.activity-blob {
transition: border-color 0s;
@@ 44,7 47,6 @@ html {
}
.blob {
- background-color: #1b1b1b;
border-color: #444;
}
@@ 57,6 59,10 @@ html {
.lvl2 { background-color: #404752; }
.lvl3 { background-color: #525e74; }
.lvl4 { background-color: #62789a; }
+
+ .filler-day {
+ opacity: 0.3;
+ }
}
@media (max-width: 760px) {
@@ 73,4 79,3 @@ html {
}
@media (max-width: 400px) { .blob { border-width: 0.75px; } }
-@media (max-width: 200px) { .blob { border-width: 0px; } }
M src/main.rs => src/main.rs +10 -19
@@ 1,4 1,5 @@
-use chrono::{DateTime, Datelike, Utc};
+// TODO: Run clippy, and add a #warn for it
+
use structopt::StructOpt;
use std::fs::File;
@@ 23,6 24,7 @@ pub struct ProjectMetadata {
#[derive(Clone, Default)]
pub struct Day {
+ filler: bool,
commits: Vec<ProjectMetadata>,
}
@@ 116,7 118,7 @@ fn main() {
let args = Args::from_args();
log::set_verbosity(args.verbose);
- let mut stdout_years: Option<Vec<Year>> = None;
+ let stdout_years;
if let Some(command) = &args.command {
match command {
@@ 151,7 153,7 @@ fn main() {
write_to_file(&css, output_css, "css");
}
- stdout_years = Some(years);
+ stdout_years = years;
}
#[cfg(feature = "server")]
@@ 160,16 162,15 @@ fn main() {
cache_lifetime,
} => {
server::run(&args, *host, *cache_lifetime);
+ return;
}
}
} else {
- stdout_years = Some(generate_years(&args.gen));
+ stdout_years = generate_years(&args.gen);
}
if args.stdout {
- if let Some(years) = stdout_years {
- println!("{}", render::ascii(&years));
- }
+ println!("{}", render::ascii(&stdout_years));
}
log::verbose_println(
@@ 183,16 184,6 @@ fn main() {
pub fn generate_years(gen: &GenerationData) -> Vec<Year> {
let repos = find_repositories::from_paths(&gen.input, gen.depth);
-
- let mut commit_dates = commits::find_dates(gen.author.as_ref(), &repos);
- commit_dates.sort_by(|(a, _), (b, _)| a.cmp(b));
-
- if commit_dates.len() > 0 {
- let get_year = |date: DateTime<Utc>| date.date().iso_week().year();
- let first_year = get_year(commit_dates[0].0);
- let last_year = get_year(commit_dates[commit_dates.len() - 1].0);
- render::gather_years(commit_dates, first_year, last_year)
- } else {
- Vec::new()
- }
+ let commit_dates = commits::find_dates(gen.author.as_ref(), &repos);
+ render::gather_years(commit_dates)
}
M src/render.rs => src/render.rs +90 -18
@@ 1,5 1,6 @@
//! Contains the functionality to render the visualizations out of
//! dated commit data.
+use chrono::naive::NaiveDate;
use chrono::{DateTime, Datelike, Utc};
use std::fs::File;
@@ 12,11 13,17 @@ static HTML_HEAD: &str = include_str!("head.html");
static CSS: &str = include_str!("activity-graph.css");
static WEEKS: usize = 53;
-pub fn gather_years(
- commit_dates: Vec<(DateTime<Utc>, ProjectMetadata)>,
- first_year: i32,
- last_year: i32,
-) -> Vec<Year> {
+pub fn gather_years(mut commit_dates: Vec<(DateTime<Utc>, ProjectMetadata)>) -> Vec<Year> {
+ if commit_dates.is_empty() {
+ return Vec::new();
+ }
+
+ commit_dates.sort_by(|(a, _), (b, _)| a.cmp(b));
+
+ let get_year = |date: DateTime<Utc>| date.date().year();
+ let first_year = get_year(commit_dates[0].0);
+ let last_year = get_year(commit_dates[commit_dates.len() - 1].0);
+
// Years is a vec containing vecs of years, which consist
// of weekday-major grids of days: eg. the first row
// represents all of the mondays in the year, in order.
@@ 28,36 35,96 @@ pub fn gather_years(
});
}
- let mut commit_dates = commit_dates.into_iter();
+ let mut commit_dates = commit_dates.into_iter().peekable();
let mut counted_commits = 0;
for year in first_year..=last_year {
// Loop through the years
- let days = &mut years[(year - first_year) as usize].days;
- while let Some((date, metadata)) = commit_dates.next() {
+ let weekday_offset = NaiveDate::from_ymd(year, 1, 1)
+ .weekday()
+ .num_days_from_monday() as usize;
+ let last_day =
+ weekday_offset + NaiveDate::from_ymd(year + 1, 1, 1).pred().ordinal() as usize;
+ let last_week = (last_day - (last_day % 7)) / 7;
+
+ let (before, after) = years.split_at_mut((year + 1 - first_year) as usize);
+ let (before, current) = before.split_at_mut(before.len() - 1);
+ let days = &mut current[0].days;
+ let mut last_year_days = if year > first_year {
+ Some(&mut before[before.len() - 1].days)
+ } else {
+ None
+ };
+ let mut next_year_days = if year < last_year {
+ Some(&mut after[0].days)
+ } else {
+ None
+ };
+ while let Some((date, _)) = commit_dates.peek() {
// Loop through the days until the commit is from
// next year or commits run out
- if date.iso_week().year() != year {
+ if date.year() != year {
break;
}
- let weekday_index = date.weekday().num_days_from_monday() as usize;
- let week_index = date.iso_week().week0() as usize;
+
+ let ordinal_with_offset = (date.ordinal0()) as usize + weekday_offset;
+ let weekday_index = ordinal_with_offset % 7;
+ let week_index = ordinal_with_offset / 7;
if week_index < WEEKS {
let day = &mut days[weekday_index * WEEKS + week_index];
- day.commits.push(metadata);
- counted_commits += 1;
+ // This branch should always be taken because of the peek()
+ if let Some((_, metadata)) = commit_dates.next() {
+ // Add the commit to the next/last year as well,
+ // to achieve consistency in the duplicated days
+ if week_index == last_week {
+ if let Some(days) = &mut next_year_days {
+ let next_year_today = &mut days[weekday_index * WEEKS];
+ next_year_today.commits.push(metadata.clone());
+ }
+ }
+ if week_index == 0 {
+ if let Some(days) = &mut last_year_days {
+ let last_year_today = &mut days[weekday_index * WEEKS + WEEKS - 1];
+ last_year_today.commits.push(metadata.clone());
+ }
+ }
+ day.commits.push(metadata);
+ counted_commits += 1;
+ }
}
}
+ // Set the first and last days as filler
+ let first_day = weekday_offset;
+ for ordinal_with_offset in (0..first_day).chain(last_day..days.len()) {
+ let weekday_index = ordinal_with_offset % 7;
+ let week_index = ordinal_with_offset / 7;
+ days[weekday_index * WEEKS + week_index].filler = true;
+ }
+
log::verbose_println(
&format!(
"prepared year {} for rendering, {} commits processed so far",
year, counted_commits
),
- false,
+ true,
);
}
+
+ let year_range = if first_year == last_year {
+ format!(" {}", first_year)
+ } else {
+ format!("s {}-{}", first_year, last_year)
+ };
+ log::verbose_println(
+ &format!(
+ "prepared year{} for rendering, {} commits processed",
+ year_range, counted_commits
+ ),
+ false,
+ );
+
years
}
@@ 115,9 182,10 @@ pub fn html(
} else {
format!("{} commits", commit_count)
};
+ let filler = if metadata.filler { "filler-day" } else { "" };
result += &format!(
- "<td class=\"blob lvl{}\" title=\"{}\"></td>",
- shade, tooltip
+ "<td class=\"blob lvl{} {}\" title=\"{}\"></td>",
+ shade, filler, tooltip
);
}
result += "</tr>\n";
@@ 144,8 212,12 @@ pub fn ascii(years: &[Year]) -> String {
for day in 0..7 {
for week in 0..WEEKS {
let metadata = &year.days[day * WEEKS + week];
- let shade = metadata.commits.len() as f32 / max_count as f32;
- result.push(get_shaded_char(shade));
+ if metadata.filler {
+ result.push(' ');
+ } else {
+ let shade = metadata.commits.len() as f32 / max_count as f32;
+ result.push(get_shaded_char(shade));
+ }
}
result.push('\n');
}
M src/server.rs => src/server.rs +1 -1
@@ 99,7 99,7 @@ async fn refresh_caches() {
if Instant::now() >= refresh_time
&& !REFRESHING_CACHE.compare_and_swap(false, true, Ordering::Relaxed)
{
- eprintln!("refreshing cache...");
+ log::verbose_println("refreshing cache...", false);
let start = Instant::now();
if let (Ok(gen), Ok(ext)) = (GENERATION_DATA.read(), EXTERNAL_HTML.read()) {
let years = generate_years(&gen);