From ebef58591e149b4581a5c3817a32adca54bcf995 Mon Sep 17 00:00:00 2001 From: Nikola Ducak Date: Fri, 15 Nov 2024 13:36:49 +0100 Subject: [PATCH] fix: preview title not having all events listed --- source/app.cpp | 43 ++++++++++++-------- source/app.hpp | 6 +-- source/config.cpp | 33 ++++++++------- source/config.hpp | 5 +++ source/log/local_log_repository.cpp | 1 - source/log/log_file.cpp | 1 - source/log/log_repository_base.hpp | 2 +- source/log/log_repository_crypto_applier.cpp | 2 +- source/main.cpp | 4 +- source/utils/async_git_repo.hpp | 4 +- source/utils/crypto.cpp | 2 +- source/utils/git_repo.hpp | 2 +- source/view/annual_view.hpp | 2 +- source/view/annual_view_base.hpp | 2 +- source/view/calendar_component.cpp | 6 ++- source/view/calendar_component.hpp | 5 +-- test/calendar_component_test.cpp | 1 + test/config_test.cpp | 14 +++---- 18 files changed, 75 insertions(+), 60 deletions(-) diff --git a/source/app.cpp b/source/app.cpp index f3aa8fe..ee7c789 100644 --- a/source/app.cpp +++ b/source/app.cpp @@ -3,6 +3,7 @@ #include #include +#include #include #include @@ -16,23 +17,30 @@ using namespace utils; namespace { std::string makePreviewTitle(std::chrono::year_month_day date, const CalendarEvents &events) { - auto eventForDate = [&]() -> std::optional> { - for (const auto &[groupName, events] : events) { - for (const auto &event : events) { + auto eventsForDate = [&]() -> std::map> { + std::map> filteredEvents; + + for (const auto &[groupName, groupEvents] : events) { + for (const auto &event : groupEvents) { if (event.date == date::monthDay(date)) { - return std::make_tuple(groupName, event); + filteredEvents[groupName].insert(event.name); } } } - return std::nullopt; + return filteredEvents; }(); - const auto eventStr = - eventForDate.has_value() - ? fmt::format("({} - {})", std::get<0>(*eventForDate), std::get<1>(*eventForDate).name) - : ""; - const auto title = - fmt::format("log preview for {} {}", utils::date::formatToString(date), eventStr); + // join in format: "birthdays: alice, bob; holidays: christmas" + std::string eventString; + for (const auto &[group, events] : eventsForDate) { + if (not eventString.empty()) { + eventString += "; "; + } + eventString += fmt::format("{}: {}", group, fmt::join(events, ", ")); + } + + const auto title = fmt::format("log preview for {} {}", utils::date::formatToString(date), + eventString.empty() ? "" : " - " + eventString); return title; } @@ -54,9 +62,9 @@ void ViewDataUpdater::handleFocusedTagChange() { m_view->setHighlightedDates( &m_data.tagsPerSection.at(m_view->getSelectedSection()).at(AnnualLogData::kAnyOrNoTag)); } else { - const auto *const highlighMap = + const auto *const highlightedDates = &m_data.tagsPerSection.at(m_view->getSelectedSection()).at(newTag); - m_view->setHighlightedDates(highlighMap); + m_view->setHighlightedDates(highlightedDates); } } @@ -288,8 +296,8 @@ void App::handleUiStarted() { void App::quit() { if (m_gitRepo) { m_view->loadingScreen("Committing & pushing..."); - m_gitRepo->commitAll([this](bool somethingCommited) { - if (somethingCommited) { + m_gitRepo->commitAll([this](bool somethingCommitted) { + if (somethingCommitted) { m_gitRepo->push([this] { m_view->stop(); }); } else { m_view->stop(); @@ -336,15 +344,14 @@ void App::handleCalendarButtonClick() { // check that after editing still exists log = m_repo->read(date); - if (log && noMeaningfullContent(log->getContent(), date)) { + if (log && noMeaningfulContent(log->getContent(), date)) { m_repo->remove(date); } updateDataAndViewAfterLogChange(date); }); } -bool App::noMeaningfullContent(const std::string &content, - const std::chrono::year_month_day &date) { +bool App::noMeaningfulContent(const std::string &content, const std::chrono::year_month_day &date) { return content == date::formatToString(date, kLogBaseTemplate) || content.empty(); } } // namespace caps_log diff --git a/source/app.hpp b/source/app.hpp index 4f0b318..18c5e1a 100644 --- a/source/app.hpp +++ b/source/app.hpp @@ -22,7 +22,7 @@ using namespace utils; static const std::string kLogBaseTemplate{"# %d. %m. %y."}; /** - * A helper class that updatest the view components after the data in the AnnualLogData has changed. + * A helper class that updates the view components after the data in the AnnualLogData has changed. * It updates the menus, the highlighted dates and the preview string, other elements of the view * are not part of it's set of responsibilities. This happens when the user deletes a log or adds a * new one or update an existing one. @@ -88,7 +88,7 @@ class App final : public InputHandlerBase { void deleteFocusedLog(); void quit(); - static bool noMeaningfullContent(const std::string &content, - const std::chrono::year_month_day &date); + static bool noMeaningfulContent(const std::string &content, + const std::chrono::year_month_day &date); }; } // namespace caps_log diff --git a/source/config.cpp b/source/config.cpp index 088efe1..7f474d3 100644 --- a/source/config.cpp +++ b/source/config.cpp @@ -4,6 +4,7 @@ #include #include #include +#include #include namespace caps_log { @@ -171,20 +172,24 @@ Config Config::make(const FileReader &fileReader, auto selectedConfigFilePath = cmdLineArgs.count("config") != 0U ? cmdLineArgs["config"].as() : Config::kDefaultConfigLocation; + try { + auto config = Config{}; - auto config = Config{}; + if (auto configFile = fileReader(selectedConfigFilePath)) { + boost::property_tree::ptree ptree; + boost::property_tree::ini_parser::read_ini(*configFile, ptree); - if (auto configFile = fileReader(selectedConfigFilePath)) { - boost::property_tree::ptree ptree; - boost::property_tree::ini_parser::read_ini(*configFile, ptree); - - applyConfigFileOverrides(config, ptree); - applyGitConfigIfEnabled(config, ptree); - } + applyConfigFileOverrides(config, ptree); + applyGitConfigIfEnabled(config, ptree); + } - applyCommandlineOverrides(config, cmdLineArgs); + applyCommandlineOverrides(config, cmdLineArgs); - return config; + return config; + } catch (const std::exception &e) { + throw ConfigParsingException{ + fmt::format("Error parsing config file ({}): {}", selectedConfigFilePath, e.what())}; + } } boost::program_options::variables_map parseCLIOptions(int argc, const char **argv) { @@ -199,7 +204,7 @@ boost::program_options::variables_map parseCLIOptions(int argc, const char **arg ("log-name-format", po::value()->default_value("d%Y_%m_%d.md"), "format in which log entry markdown files are saved") ("sunday-start", "have the calendar display sunday as first day of the week") ("first-line-section", "if a section mark is placed on the first line, by default it is ignored as it's left for log title, this overrides this behaviour") - ("password", po::value(), "password for encrypted log repositores or to be used with --encrypt/--decrypt") + ("password", po::value(), "password for encrypted log repositories or to be used with --encrypt/--decrypt") ("encrypt", "apply encryption to all logs in log dir path (needs --password)") ("decrypt", "apply decryption to all logs in log dir path (needs --password)"); // clang-format on @@ -209,10 +214,10 @@ boost::program_options::variables_map parseCLIOptions(int argc, const char **arg po::notify(vmap); if (vmap.count("help") != 0U) { - std::cout << "Capstains Log (caps-log)! A CLI journalig tool." << '\n'; - std::cout << "Version: " << CAPS_LOG_VERSION_STRING << std::endl; + std::cout << "Captain's Log (caps-log)! A CLI journalig tool." << '\n'; + std::cout << "Version: " << CAPS_LOG_VERSION_STRING << '\n'; std::cout << desc; - std::cout.flush(); + std::cout << std::flush; exit(0); } diff --git a/source/config.hpp b/source/config.hpp index 1d121ad..f822f19 100644 --- a/source/config.hpp +++ b/source/config.hpp @@ -19,6 +19,11 @@ struct GitRepoConfig { std::string remoteName = "origin"; }; +class ConfigParsingException : public std::runtime_error { + public: + explicit ConfigParsingException(const std::string &what) : std::runtime_error{what} {} +}; + struct Config { static Config make(const FileReader &fileReader, const boost::program_options::variables_map &cmdLineArgs); diff --git a/source/log/local_log_repository.cpp b/source/log/local_log_repository.cpp index 3c77cb7..2538012 100644 --- a/source/log/local_log_repository.cpp +++ b/source/log/local_log_repository.cpp @@ -2,7 +2,6 @@ #include "log/log_repository_crypto_applier.hpp" #include -#include #include #include #include diff --git a/source/log/log_file.cpp b/source/log/log_file.cpp index 0e03c17..ce8cc21 100644 --- a/source/log/log_file.cpp +++ b/source/log/log_file.cpp @@ -2,7 +2,6 @@ #include "utils/string.hpp" #include -#include #include #include #include diff --git a/source/log/log_repository_base.hpp b/source/log/log_repository_base.hpp index 75bd011..6e77f40 100644 --- a/source/log/log_repository_base.hpp +++ b/source/log/log_repository_base.hpp @@ -8,7 +8,7 @@ namespace caps_log::log { /* - * Only class that actualy interacts with physical files on the drive + * Only class that actually interacts with physical files on the drive */ class LogRepositoryBase { public: diff --git a/source/log/log_repository_crypto_applier.cpp b/source/log/log_repository_crypto_applier.cpp index 33f2b12..195737d 100644 --- a/source/log/log_repository_crypto_applier.cpp +++ b/source/log/log_repository_crypto_applier.cpp @@ -16,7 +16,7 @@ void updateEncryptionMarkerfile(Crypto crypto, const std::filesystem::path &logD if (crypto == Crypto::Encrypt) { std::ofstream cle{markerFilePath, std::ios::binary}; if (not cle.is_open()) { - // This would be an unfortuane situation, the repo has already been encrypted + // This would be an unfortunate situation, the repo has already been encrypted // but the encryption marker file is not added. // TODO: figure something out throw std::runtime_error{"Failed writing encryption marker file"}; diff --git a/source/main.cpp b/source/main.cpp index 10fe39b..aebb0ed 100644 --- a/source/main.cpp +++ b/source/main.cpp @@ -40,7 +40,7 @@ std::string promptPassword(const caps_log::Config &config) { const auto container = Container::Vertical({input, buttonSubmit, buttonQuit}); const Component renderer = Renderer(container, [container]() { - return window(text("Pasword required!"), container->Render()) | center; + return window(text("Password required!"), container->Render()) | center; }); screen.Loop(renderer); @@ -119,6 +119,6 @@ int main(int argc, const char **argv) try { return 0; } catch (const std::exception &e) { - std::cerr << "Captains log encountered an error: \n " << e.what() << '\n' << std::flush; + std::cerr << "Captain's log encountered an error: \n " << e.what() << '\n' << std::flush; return 1; } diff --git a/source/utils/async_git_repo.hpp b/source/utils/async_git_repo.hpp index 2c9dc29..8efc668 100644 --- a/source/utils/async_git_repo.hpp +++ b/source/utils/async_git_repo.hpp @@ -33,8 +33,8 @@ class AsyncGitRepo final { void commitAll(std::function acallback) { m_taskExec.post([this, callback = std::move(acallback)]() { - auto somethingCommited = m_repo.commitAll(); - callback(somethingCommited); + auto somethingCommitted = m_repo.commitAll(); + callback(somethingCommitted); }); } }; diff --git a/source/utils/crypto.cpp b/source/utils/crypto.cpp index a908a7e..4907606 100644 --- a/source/utils/crypto.cpp +++ b/source/utils/crypto.cpp @@ -78,7 +78,7 @@ std::string encrypt(const std::string &password, std::istream &file) { } if (EVP_EncryptFinal_ex(ctx.get(), outBuffer.data(), &outLength) != 1) { - throw std::runtime_error{"Encryption failed: failed to finaleze encryption!"}; + throw std::runtime_error{"Encryption failed: failed to finalize encryption!"}; } output += std::string{outBuffer.begin(), outBuffer.begin() + outLength}; diff --git a/source/utils/git_repo.hpp b/source/utils/git_repo.hpp index 409a0b7..89382a9 100644 --- a/source/utils/git_repo.hpp +++ b/source/utils/git_repo.hpp @@ -8,7 +8,7 @@ namespace caps_log::utils { /** * A utility class that manages the initialization of libgit2 and other required interactions with * the library. It deals with commit the files, pulling and pushing. It expect that the repository - * has an innitial commit, remote added and ssh communication. + * has an initial commit, remote added and ssh communication. */ class GitRepo { class GitLibRaii { diff --git a/source/view/annual_view.hpp b/source/view/annual_view.hpp index 3966831..d45276b 100644 --- a/source/view/annual_view.hpp +++ b/source/view/annual_view.hpp @@ -21,7 +21,7 @@ class AnnualView : public AnnualViewBase { InputHandlerBase *m_handler{nullptr}; ftxui::ScreenInteractive m_screen; - // UI compontents visible to the user + // UI components visible to the user std::shared_ptr m_calendarButtons; std::shared_ptr m_tagsMenu, m_sectionsMenu; std::shared_ptr m_preview = std::make_unique(); diff --git a/source/view/annual_view_base.hpp b/source/view/annual_view_base.hpp index 981550e..89c1d08 100644 --- a/source/view/annual_view_base.hpp +++ b/source/view/annual_view_base.hpp @@ -69,7 +69,7 @@ class AnnualViewBase { // NOLINT virtual void loadingScreenOff() = 0; // passing only a pointer and having a view have no ownership of - // the map allows for having precoputed maps and switching + // the map allows for having precomputed maps and switching virtual void setDatesWithLogs(const utils::date::Dates *map) = 0; virtual void setHighlightedDates(const utils::date::Dates *map) = 0; virtual void setEventDates(const CalendarEvents *map) {}; diff --git a/source/view/calendar_component.cpp b/source/view/calendar_component.cpp index 38d25d8..a321359 100644 --- a/source/view/calendar_component.cpp +++ b/source/view/calendar_component.cpp @@ -1,8 +1,10 @@ #include "calendar_component.hpp" #include "ftxui/dom/elements.hpp" +#include "utils/date.hpp" +#include "view/ftxui_ext/extended_containers.hpp" + #include -#include namespace caps_log::view { using namespace ftxui; @@ -12,7 +14,7 @@ namespace { * @brief Utility class that allows for the arrangement of month components in a calendar. * It distributes 12 months into 2 or more rows of equal elements. * @Note This class had to be implemented to allow for fetching the screen size at runtime to - * avoid relying on "Terimal::GetDimensions()" which is troublign in test environment. + * avoid relying on "Terminal::GetDimensions()" which is troubling in test environment. * @Note the class makes some assumptions about the width of the rendered month components. Like * that month component day buttons have a border and such */ diff --git a/source/view/calendar_component.hpp b/source/view/calendar_component.hpp index 762e071..e6d1789 100644 --- a/source/view/calendar_component.hpp +++ b/source/view/calendar_component.hpp @@ -1,8 +1,5 @@ #pragma once -#include "utils/date.hpp" -#include "view/ftxui_ext/extended_containers.hpp" - #include #include #include @@ -41,7 +38,7 @@ class Calendar : public ftxui::ComponentBase { /** * @brief A utility factory method to create a shared pointer to a Calendar instance. This is - * usefull as FTXUI works with shared pointers to ComponentBase instances. + * useful as FTXUI works with shared pointers to ComponentBase instances. */ static inline auto make(const ftxui::Screen &screen, const std::chrono::year_month_day &today, CalendarOption option = {}) { diff --git a/test/calendar_component_test.cpp b/test/calendar_component_test.cpp index 97e7732..e76b52c 100644 --- a/test/calendar_component_test.cpp +++ b/test/calendar_component_test.cpp @@ -1,3 +1,4 @@ +#include "utils/date.hpp" #include "view/calendar_component.hpp" #include #include diff --git a/test/config_test.cpp b/test/config_test.cpp index 4000df8..34fb999 100644 --- a/test/config_test.cpp +++ b/test/config_test.cpp @@ -112,7 +112,7 @@ TEST(ConfigTest, GitConfigWorks) { auto fileReader = mockFileReader(configContent); Config config = Config::make(fileReader, cmdLineArgs); - ASSERT_TRUE(config.repoConfig.has_value()); + EXPECT_TRUE(config.repoConfig.has_value()); EXPECT_EQ(config.repoConfig->root, "/path/to/repo/"); EXPECT_EQ(config.repoConfig->sshKeyPath, "/path/to/key"); EXPECT_EQ(config.repoConfig->sshPubKeyPath, "/path/to/pub-key"); @@ -132,7 +132,7 @@ TEST(ConfigTest, GitConfigDisabledIfUnset) { auto fileReader = mockFileReader(configContent); Config config = Config::make(fileReader, cmdLineArgs); - ASSERT_FALSE(config.repoConfig.has_value()); + EXPECT_FALSE(config.repoConfig.has_value()); } TEST(ConfigTest, GitConfigDisabled) { @@ -148,7 +148,7 @@ TEST(ConfigTest, GitConfigDisabled) { auto fileReader = mockFileReader(configContent); Config config = Config::make(fileReader, cmdLineArgs); - ASSERT_FALSE(config.repoConfig.has_value()); + EXPECT_FALSE(config.repoConfig.has_value()); } TEST(ConfigTest, GitConfigThrowsIfLogDirIsNotInsideRepoRoot) { @@ -162,7 +162,7 @@ TEST(ConfigTest, GitConfigThrowsIfLogDirIsNotInsideRepoRoot) { "remote-name=remote-name"; auto cmdLineArgs = parseArgs({"caps-log"}); auto fileReader = mockFileReader(configContent); - ASSERT_THROW(Config::make(fileReader, cmdLineArgs), std::invalid_argument); + EXPECT_THROW(Config::make(fileReader, cmdLineArgs), caps_log::ConfigParsingException); } TEST(ConfigTest, GitConfigDoesNotThrowIfGitRootIsSameAsLogDirPath) { @@ -176,7 +176,7 @@ TEST(ConfigTest, GitConfigDoesNotThrowIfGitRootIsSameAsLogDirPath) { "remote-name=remote-name"; auto cmdLineArgs = parseArgs({"caps-log"}); auto fileReader = mockFileReader(configContent); - ASSERT_NO_THROW(Config::make(fileReader, cmdLineArgs)); + EXPECT_NO_THROW(Config::make(fileReader, cmdLineArgs)); } TEST(ConfigTest, CalendarEventsParsing) { @@ -217,7 +217,7 @@ TEST(ConfigTest, CalendarEventsParsing_ThrowsWhenNoId) { "date=12.25.\n"; auto cmdLineArgs = parseArgs({"caps-log"}); auto fileReader = mockFileReader(configContent); - ASSERT_THROW(Config::make(fileReader, cmdLineArgs), std::runtime_error); + EXPECT_THROW(Config::make(fileReader, cmdLineArgs), caps_log::ConfigParsingException); } TEST(ConfigTest, CalendarEventsParsing_ThrowsWhenBadDate) { @@ -232,5 +232,5 @@ TEST(ConfigTest, CalendarEventsParsing_ThrowsWhenBadDate) { "date=12.25.\n"; auto cmdLineArgs = parseArgs({"caps-log"}); auto fileReader = mockFileReader(configContent); - ASSERT_THROW(Config::make(fileReader, cmdLineArgs), std::runtime_error); + EXPECT_THROW(Config::make(fileReader, cmdLineArgs), caps_log::ConfigParsingException); }