| 35 const std::string repo_key = m_separate ? m_current_repo : "All Repositories"; |
35 const std::string repo_key = m_separate ? m_current_repo : "All Repositories"; |
| 36 |
36 |
| 37 for (auto line: std::views::split(log, "\n"sv)) { |
37 for (auto line: std::views::split(log, "\n"sv)) { |
| 38 if (line.empty()) continue; |
38 if (line.empty()) continue; |
| 39 |
39 |
| 40 // find all delimiters |
40 // split the line by delimiter |
| 41 const auto line_view = std::string_view{line}; |
41 const auto line_view = std::string_view{line}; |
| 42 const auto pos_delim1 = line_view.find('#', 0); |
42 auto parts = std::views::split(line_view, '#') |
| 43 const auto pos_delim2 = line_view.find('#', pos_delim1 + 1); |
43 | std::views::transform([](auto r) { return std::string_view(r); }) |
| 44 const auto pos_delim3 = line_view.find('#', pos_delim2 + 1); |
44 | std::ranges::to<std::vector>(); |
| 45 |
45 |
| 46 std::string author{settings.map_author(line_view.substr(0, pos_delim1))}; |
46 std::string_view hash_view{parts[0]}; |
| 47 std::string_view date_view{line_view.substr(pos_delim1+1, pos_delim2 - pos_delim1 - 1)}; |
47 std::string author{settings.map_author(parts[1])}; |
| 48 std::string_view tags_view{line_view.substr(pos_delim2+1, pos_delim3 - pos_delim2 - 1)}; |
48 std::string_view date_view{parts[2]}; |
| 49 std::string_view summary_view{line_view.substr(pos_delim3+1)}; |
49 std::string_view tags_view{parts[3]}; |
| |
50 std::string_view summary_view{parts[4]}; |
| 50 |
51 |
| 51 int year = 0; |
52 int year = 0; |
| 52 unsigned int month = 0, day = 0; |
53 unsigned int month = 0, day = 0; |
| 53 auto date_parts = std::views::split(date_view, "-"sv) |
54 auto date_parts = std::views::split(date_view, "-"sv) |
| 54 | std::views::transform([](auto r) { return std::string_view(r); }) |
55 | std::views::transform([](auto r) { return std::string_view(r); }) |
| 58 std::from_chars(date_parts[2].begin(), date_parts[2].end(), day); |
59 std::from_chars(date_parts[2].begin(), date_parts[2].end(), day); |
| 59 auto &[summaries, tags] = |
60 auto &[summaries, tags] = |
| 60 m_heatmap[repo_key][author][chrono::year_month_day{ |
61 m_heatmap[repo_key][author][chrono::year_month_day{ |
| 61 chrono::year{year}, chrono::month{month}, chrono::day{day} |
62 chrono::year{year}, chrono::month{month}, chrono::day{day} |
| 62 }]; |
63 }]; |
| 63 summaries[m_current_repo].emplace_back(summary_view); |
64 summaries[m_current_repo].emplace_back(hash_view, summary_view); |
| 64 // special case: if the (only) tag is "tip", we do not add it |
65 // special case: if the (only) tag is "tip", we do not add it |
| 65 if (!tags_view.empty() && tags_view != "tip") { |
66 if (!tags_view.empty() && tags_view != "tip") { |
| 66 tags[m_current_repo].emplace_back(tags_view); |
67 tags[m_current_repo].emplace_back(hash_view, tags_view); |
| 67 } |
68 } |
| 68 } |
69 } |
| 69 } |
70 } |
| 70 |
71 |
| 71 std::array<fm::commit_summary, 12> fm::heatmap::commits_per_month( |
72 std::array<fm::commit_summary, 12> fm::heatmap::commits_per_month( |
| 80 for (auto &&[reponame, summaries]: commits.summaries) { |
81 for (auto &&[reponame, summaries]: commits.summaries) { |
| 81 cs.commits[reponame] += summaries.size(); |
82 cs.commits[reponame] += summaries.size(); |
| 82 } |
83 } |
| 83 for (auto &&[reponame, tags]: commits.tags) { |
84 for (auto &&[reponame, tags]: commits.tags) { |
| 84 if (tags.empty()) continue; |
85 if (tags.empty()) continue; |
| 85 std::string tag_list = tags.at(0); |
86 std::string tag_list = tags.at(0).message; |
| 86 for (unsigned i = 1; i < tags.size(); ++i) { |
87 for (unsigned i = 1; i < tags.size(); ++i) { |
| 87 tag_list.append(", "); |
88 tag_list.append(", "); |
| 88 tag_list.append(tags.at(i)); |
89 tag_list.append(tags.at(i).message); |
| 89 } |
90 } |
| 90 cs.tags_with_date[reponame].emplace_back( |
91 cs.tags_with_date[reponame].emplace_back( |
| 91 std::format("{} on {}-{:02}-{:02}", |
92 std::format("{} on {}-{:02}-{:02}", |
| 92 tag_list, |
93 tag_list, |
| 93 static_cast<int>(ymd.year()), |
94 static_cast<int>(ymd.year()), |