From 9a951780956cc94efd5472821efc8f793dc0c63c Mon Sep 17 00:00:00 2001 From: Mars Date: Thu, 1 May 2025 14:51:41 -0400 Subject: [PATCH] fixes --- src/core/system_data.cpp | 68 +++++++++++++++++++++++++++++++++------ src/core/system_data.hpp | 24 +++++++------- src/core/util/logging.hpp | 43 ++++++++++++++++++------- src/main.cpp | 6 +++- src/os/macos.cpp | 18 +++++------ src/os/shared.cpp | 2 ++ 6 files changed, 118 insertions(+), 43 deletions(-) diff --git a/src/core/system_data.cpp b/src/core/system_data.cpp index f7c090b..818e062 100644 --- a/src/core/system_data.cpp +++ b/src/core/system_data.cpp @@ -1,24 +1,73 @@ #include "system_data.hpp" -#include // std::chrono::{year_month_day, days, floor, system_clock} +#include // std::chrono::system_clock +#include // localtime_r/s, strftime, time_t, tm #include // std::format -#include // std::async +#include // std::{async, launch} #include "src/config/config.hpp" #include "src/config/weather.hpp" +#include "src/core/util/defs.hpp" #include "src/core/util/error.hpp" #include "src/core/util/types.hpp" #include "src/os/os.hpp" +using util::error::DracError, util::error::DracErrorCode; + +namespace { + using util::types::i32, util::types::CStr; + + fn getOrdinalSuffix(i32 day) -> CStr { + if (day >= 11 && day <= 13) + return "th"; + + switch (day % 10) { + case 1: return "st"; + case 2: return "nd"; + case 3: return "rd"; + default: return "th"; + } + } + + fn getDate() -> Result { + using std::chrono::system_clock; + using util::types::String, util::types::usize, util::types::Err; + + const system_clock::time_point nowTp = system_clock::now(); + const std::time_t nowTt = system_clock::to_time_t(nowTp); + + std::tm nowTm; + +#ifdef _WIN32 + if (localtime_s(&nowTm, &nowTt) == 0) { +#else + if (localtime_r(&nowTt, &nowTm) != nullptr) { +#endif + i32 day = nowTm.tm_mday; + + String monthBuffer(32, '\0'); + const usize monthLen = std::strftime(monthBuffer.data(), monthBuffer.size(), "%B", &nowTm); + + if (monthLen > 0) { + monthBuffer.resize(monthLen); + + CStr suffix = getOrdinalSuffix(day); + + try { + return std::format("{} {}{}", monthBuffer, day, suffix); + } catch (const std::format_error& e) { return Err(DracError(DracErrorCode::ParseError, e.what())); } + } else + return Err(DracError(DracErrorCode::ParseError, "Failed to format date")); + } else + return Err(DracError(DracErrorCode::ParseError, "Failed to get local time")); + } +} // namespace + namespace os { SystemData::SystemData(const Config& config) { - // NOLINTNEXTLINE(misc-include-cleaner) - std::chrono::{days, floor} are inherited from - using std::chrono::year_month_day, std::chrono::system_clock, std::chrono::floor, std::chrono::days; - using util::error::DracError, util::error::DracErrorCode; - using util::types::Result, util::types::Err, util::types::Option, util::types::None, util::types::Exception, - util::types::Future; - using weather::Output; using enum std::launch; + using util::types::Future, util::types::Err; + using weather::Output; Future> hostFut = std::async(async, GetHost); Future> kernelFut = std::async(async, GetKernelVersion); @@ -36,8 +85,7 @@ namespace os { return config.weather.getWeatherInfo(); }); - // TODO: make this use the user's timezone - this->date = std::format("{:%B %d}", year_month_day { floor(system_clock::now()) }); + this->date = getDate(); this->host = hostFut.get(); this->kernelVersion = kernelFut.get(); this->osVersion = osFut.get(); diff --git a/src/core/system_data.hpp b/src/core/system_data.hpp index b099011..b354bb7 100644 --- a/src/core/system_data.hpp +++ b/src/core/system_data.hpp @@ -67,18 +67,18 @@ namespace os { * in order to display it at all at once during runtime. */ struct SystemData { - String date; ///< Current date (e.g., "April 26"). Always expected to succeed. - Result host; ///< Host/product family (e.g., "MacBook Air") or OS util::erroror. - Result kernelVersion; ///< OS kernel version (e.g., "6.14.4") or OS error. - Result osVersion; ///< OS pretty name (e.g., "Ubuntu 24.04.2 LTS") or OS error. - Result memInfo; ///< Total physical RAM in bytes or OS error. - Result desktopEnv; ///< Desktop environment (e.g., "KDE") or None if not detected. - Result windowMgr; ///< Window manager (e.g., "KWin") or None if not detected. - Result diskUsage; ///< Used/Total disk space for root filesystem or OS error. - Result shell; ///< Name of the current user shell (e.g., "zsh"). None if not detected. - Result packageCount; ///< Total number of packages installed or OS error. - Result nowPlaying; ///< Result of fetching media info. - Result weather; ///< Result of fetching weather info. + Result date; ///< Current date (e.g., "April 26th"). + Result host; ///< Host/product family (e.g., "MacBook Air"). + Result kernelVersion; ///< OS kernel version (e.g., "6.14.4"). + Result osVersion; ///< OS pretty name (e.g., "Ubuntu 24.04.2 LTS"). + Result memInfo; ///< Total physical RAM in bytes. + Result desktopEnv; ///< Desktop environment (e.g., "KDE"). + Result windowMgr; ///< Window manager (e.g., "KWin"). + Result diskUsage; ///< Used/Total disk space for root filesystem. + Result shell; ///< Name of the current user shell (e.g., "zsh"). + Result packageCount; ///< Total number of packages installed. + Result nowPlaying; ///< Result of fetching media info. + Result weather; ///< Result of fetching weather info. /** * @brief Constructs a SystemData object and initializes its members. diff --git a/src/core/util/logging.hpp b/src/core/util/logging.hpp index cb8e93a..442831b 100644 --- a/src/core/util/logging.hpp +++ b/src/core/util/logging.hpp @@ -1,13 +1,17 @@ #pragma once -#include // std::chrono::{days, floor, seconds, system_clock} -#include // std::filesystem::path -#include // std::format +#include // std::chrono::{days, floor, seconds, system_clock} +#include // For time_t, tm, localtime_s, localtime_r, strftime (needed for cross-platform local time) +#include // std::filesystem::path +#include // std::format #include // ftxui::Color #include // std::print -#include // std::source_location #include // std::forward +#ifndef NDEBUG + #include // std::source_location +#endif + #include "src/core/util/defs.hpp" #include "src/core/util/error.hpp" #include "src/core/util/types.hpp" @@ -48,7 +52,7 @@ namespace util::logging { static constexpr ftxui::Color::Palette16 ERROR_COLOR = ftxui::Color::Palette16::Red; static constexpr ftxui::Color::Palette16 DEBUG_INFO_COLOR = ftxui::Color::Palette16::GrayLight; - static constexpr CStr TIMESTAMP_FORMAT = "{:%X}"; + static constexpr CStr TIMESTAMP_FORMAT = "%X"; static constexpr CStr LOG_FORMAT = "{} {} {}"; #ifndef NDEBUG @@ -143,7 +147,7 @@ namespace util::logging { * @brief Logs a message with the specified log level, source location, and format string. * @tparam Args Parameter pack for format arguments. * @param level The log level (DEBUG, INFO, WARN, ERROR). - * @param loc The source location of the log message. + * @param loc The source location of the log message (only in Debug builds). * @param fmt The format string. * @param args The arguments for the format string. */ @@ -161,17 +165,34 @@ namespace util::logging { using Buffer = Array; - // Dynamic parts (runtime) - const time_point> now = floor(system_clock::now()); + const auto nowTp = system_clock::now(); + const std::time_t nowTt = system_clock::to_time_t(nowTp); + std::tm localTm; - const String timestamp = std::format(LogLevelConst::TIMESTAMP_FORMAT, now); - const String message = std::format(fmt, std::forward(args)...); + String timestamp; + +#ifdef _WIN32 + if (localtime_s(&local_tm, &now_tt) == 0) { +#else + if (localtime_r(&nowTt, &localTm) != nullptr) { +#endif + Array timeBuffer; + + if (std::strftime(timeBuffer.data(), sizeof(timeBuffer), LogLevelConst::TIMESTAMP_FORMAT, &localTm) > 0) + timestamp = timeBuffer.data(); + else + timestamp = "??:??:?? (strf_err)"; + } else + timestamp = "??:??:?? (conv_err)"; + + const String message = std::format(fmt, std::forward(args)...); Buffer buffer {}; + // Use the locally formatted timestamp string here auto* iter = std::format_to( buffer.begin(), - LogLevelConst::LOG_FORMAT, + LogLevelConst::LOG_FORMAT, // "{timestamp} {level} {message}" Colorize("[" + timestamp + "]", LogLevelConst::DEBUG_INFO_COLOR), GetLevelInfo().at(static_cast(level)), message diff --git a/src/main.cpp b/src/main.cpp index 71c639a..0802fb3 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -4,6 +4,7 @@ #include // ftxui::{Render} #include // ftxui::Color #include // ftxui::{Screen, Dimension::Full} +#include // std::println #include // std::ranges::{iota, to, transform} #include "src/config/config.hpp" @@ -151,7 +152,10 @@ namespace { }; // System info rows - content.push_back(createRow(calendarIcon, "Date", data.date)); + if (data.date) + content.push_back(createRow(calendarIcon, "Date", *data.date)); + else + error_at(data.date.error()); // Weather row if (weather.enabled && data.weather) { diff --git a/src/os/macos.cpp b/src/os/macos.cpp index aed8727..6d90e08 100644 --- a/src/os/macos.cpp +++ b/src/os/macos.cpp @@ -13,7 +13,7 @@ // clang-format on using namespace util::types; -using util::error::DracError, util::error::DracErrorCode; +using util::error::DracError; fn os::GetMemInfo() -> Result { u64 mem = 0; @@ -30,16 +30,16 @@ fn os::GetNowPlaying() -> Result { return GetCurrentPlayin fn os::GetOSVersion() -> Result { return GetMacOSVersion(); } fn os::GetDesktopEnvironment() -> Result { - return Err(DracError(DracErrorCode::Other, "Not implemented on macOS")); + return "Aqua"; // TODO: Implement } fn os::GetWindowManager() -> Result { - return Err(DracError(DracErrorCode::Other, "Not implemented on macOS")); + return "Yabai"; // TODO: Implement } fn os::GetKernelVersion() -> Result { - std::array kernelVersion {}; - usize kernelVersionLen = sizeof(kernelVersion); + Array kernelVersion {}; + usize kernelVersionLen = sizeof(kernelVersion); if (sysctlbyname("kern.osrelease", kernelVersion.data(), &kernelVersionLen, nullptr, 0) == -1) return Err(DracError::withErrno("Failed to get kernel version")); @@ -48,15 +48,15 @@ fn os::GetKernelVersion() -> Result { } fn os::GetHost() -> Result { - std::array hwModel {}; - size_t hwModelLen = sizeof(hwModel); + Array hwModel {}; + usize hwModelLen = sizeof(hwModel); if (sysctlbyname("hw.model", hwModel.data(), &hwModelLen, nullptr, 0) == -1) return Err(DracError::withErrno("Failed to get host info")); // taken from https://github.com/fastfetch-cli/fastfetch/blob/dev/src/detection/host/host_mac.c // shortened a lot of the entries to remove unnecessary info - std::flat_map modelNameByHwModel = { + std::flat_map modelNameByHwModel = { // MacBook Pro { "MacBookPro18,3", "MacBook Pro (14-inch, 2021)" }, { "MacBookPro18,4", "MacBook Pro (14-inch, 2021)" }, @@ -225,7 +225,7 @@ fn os::GetDiskUsage() -> Result { fn os::GetPackageCount() -> Result { return shared::GetPackageCount(); } fn os::GetShell() -> Result { - return Err(DracError(DracErrorCode::Other, "Not implemented on macOS")); + return "Fish"; // TODO: Implement } #endif diff --git a/src/os/shared.cpp b/src/os/shared.cpp index ec8c394..6186979 100644 --- a/src/os/shared.cpp +++ b/src/os/shared.cpp @@ -3,6 +3,7 @@ #include // SQLite::Statement #include // std::chrono #include // std::filesystem +#include // std::format #include // std::{ifstream, ofstream} #include // glz::read_beve #include // glz::write_beve @@ -11,6 +12,7 @@ #include // glz::detail::Object #include // std::ios::{binary, trunc}, std::ios_base #include // std::istreambuf_iterator +#include // std::error_code #include "src/core/util/defs.hpp" #include "src/core/util/error.hpp"