| 30 |
30 |
| 31 namespace chrono = std::chrono; |
31 namespace chrono = std::chrono; |
| 32 |
32 |
| 33 void fm::heatmap::add(const settings &settings, const std::string &log) { |
33 void fm::heatmap::add(const settings &settings, const std::string &log) { |
| 34 using std::string_view_literals::operator ""sv; |
34 using std::string_view_literals::operator ""sv; |
| 35 const std::string repo_key = m_separate ? m_current_repo : "All Repositories"; |
|
| 36 |
35 |
| 37 for (auto line: std::views::split(log, "\n"sv)) { |
36 for (auto line: std::views::split(log, "\n"sv)) { |
| 38 if (line.empty()) continue; |
37 if (line.empty()) continue; |
| 39 |
38 |
| 40 // split the line by delimiter |
39 // split the line by delimiter |
| 57 | std::views::transform([](auto r) { return std::string_view(r); }) |
56 | std::views::transform([](auto r) { return std::string_view(r); }) |
| 58 | std::ranges::to<std::vector>(); |
57 | std::ranges::to<std::vector>(); |
| 59 std::from_chars(date_parts[0].begin(), date_parts[0].end(), year); |
58 std::from_chars(date_parts[0].begin(), date_parts[0].end(), year); |
| 60 std::from_chars(date_parts[1].begin(), date_parts[1].end(), month); |
59 std::from_chars(date_parts[1].begin(), date_parts[1].end(), month); |
| 61 std::from_chars(date_parts[2].begin(), date_parts[2].end(), day); |
60 std::from_chars(date_parts[2].begin(), date_parts[2].end(), day); |
| 62 auto &[summaries, tags] = |
61 const auto ymd = chrono::year_month_day{ |
| 63 m_heatmap[repo_key][author][chrono::year_month_day{ |
62 chrono::year{year}, chrono::month{month}, chrono::day{day} |
| 64 chrono::year{year}, chrono::month{month}, chrono::day{day} |
63 }; |
| 65 }]; |
64 |
| 66 summaries[m_current_repo].emplace_back(hash_view, summary_view); |
65 auto add_info = [this, hash_view, summary_view, tags_view] (commits & commit_info) { |
| 67 // special case: if the (only) tag is "tip", we do not add it |
66 commit_info.summaries[m_current_repo].emplace_back(hash_view, summary_view); |
| 68 if (!tags_view.empty() && tags_view != "tip") { |
67 // special case: if the (only) tag is "tip", we do not add it |
| 69 tags[m_current_repo].emplace_back(hash_view, tags_view); |
68 if (!tags_view.empty() && tags_view != "tip") { |
| 70 } |
69 commit_info.tags[m_current_repo].emplace_back(hash_view, tags_view); |
| |
70 } |
| |
71 }; |
| |
72 |
| |
73 add_info(m_heatmap[m_current_repo][author][ymd]); |
| |
74 add_info(m_aggregated_heatmap[aggregated_repo_label][author][ymd]); |
| 71 } |
75 } |
| 72 } |
76 } |
| 73 |
77 |
| 74 std::array<fm::commit_summary, 12> fm::heatmap::commits_per_month( |
78 std::array<fm::commit_summary, 12> fm::heatmap::commits_per_month( |
| 75 const std::string& repo, |
79 const std::string& repo, |
| 76 const std::string& author, |
80 const std::string& author, |
| 77 chrono::year year |
81 chrono::year year |
| 78 ) const { |
82 ) const { |
| 79 std::array<commit_summary, 12> result{}; |
83 std::array<commit_summary, 12> result{}; |
| 80 for (auto &&[ymd, commits]: m_heatmap.at(repo).at(author)) { |
84 for (const auto &heatmap_data = repo == aggregated_repo_label ? m_aggregated_heatmap : m_heatmap; |
| |
85 auto &&[ymd, commits]: heatmap_data.at(repo).at(author)) { |
| 81 if (ymd.year() != year) continue; |
86 if (ymd.year() != year) continue; |
| 82 commit_summary &cs = result[static_cast<unsigned int>(ymd.month()) - 1]; |
87 commit_summary &cs = result[static_cast<unsigned int>(ymd.month()) - 1]; |
| 83 for (auto &&[reponame, summaries]: commits.summaries) { |
88 for (auto &&[reponame, summaries]: commits.summaries) { |
| 84 cs.commits[reponame] += summaries.size(); |
89 cs.commits[reponame] += summaries.size(); |
| 85 } |
90 } |