diff --git a/src/main.cpp b/src/main.cpp index aaa2c0f..ace41e6 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -1,9 +1,7 @@ #include #include -#include -#include -#include #include +#include #include #include #include @@ -11,10 +9,9 @@ #include #include "config/config.h" -#include "ftxui/screen/color.hpp" #include "os/os.h" -constexpr bool SHOW_ICONS = true; +constexpr inline bool SHOW_ICONS = true; struct BytesToGiB { u64 value; @@ -24,46 +21,110 @@ struct BytesToGiB { constexpr u64 GIB = 1'073'741'824; template <> -struct fmt::formatter : fmt::formatter { - template - constexpr fn format(const BytesToGiB& BTG, FmtCtx& ctx) const -> typename FmtCtx::iterator { - // Format as double with GiB suffix, no space - return fmt::format_to(ctx.out(), "{:.2f}GiB", static_cast(BTG.value) / GIB); +struct std::formatter : std::formatter { + auto format(const BytesToGiB& BTG, auto& ctx) const { + return std::format_to(ctx.out(), "{:.2f}GiB", static_cast(BTG.value) / GIB); } }; +namespace ui { + using ftxui::Color; + + constexpr int MAX_PARAGRAPH_LENGTH = 30; + constexpr int PADDING = 3; + + // Color themes + struct Theme { + Color::Palette16 icon; + Color::Palette16 label; + Color::Palette16 value; + Color::Palette16 border; + Color::Palette16 accent; + }; + + constexpr Theme DEFAULT_THEME = { + .icon = Color::Cyan, + .label = Color::Yellow, + .value = Color::White, + .border = Color::GrayLight, + .accent = Color::Magenta, + }; + + struct Icons { + std::string_view user; + std::string_view palette; + std::string_view calendar; + std::string_view host; + std::string_view kernel; + std::string_view os; + std::string_view memory; + std::string_view weather; + std::string_view music; + std::string_view disk; + std::string_view shell; + std::string_view desktop; + std::string_view window_manager; + }; + + constexpr Icons EMPTY_ICONS = { + .user = "", + .palette = "", + .calendar = "", + .host = "", + .kernel = "", + .os = "", + .memory = "", + .weather = "", + .music = "", + .disk = "", + .shell = "", + .desktop = "", + .window_manager = "", + }; + + // Using your original icons + constexpr Icons NERD_ICONS = { + .user = "  ", + .palette = "  ", + .calendar = "  ", + .host = " 󰌢 ", + .kernel = "  ", + .os = "  ", + .memory = "  ", + .weather = "  ", + .music = "  ", + .disk = " 󰋊 ", + .shell = "  ", + .desktop = " 󰇄 ", + .window_manager = "  ", + }; +} + namespace { - fn GetDate() -> std::string { - // Get current local time - const std::time_t now = std::time(nullptr); - std::tm localTime; + template + auto expected_visit(const std::expected& exp, ValueFunc value_func, ErrorFunc error_func) { + if (exp.has_value()) + return value_func(*exp); -#ifdef _WIN32 - if (localtime_s(&localTime, &now) != 0) - ERROR_LOG("localtime_s failed"); -#else - if (localtime_r(&now, &localTime) == nullptr) - ERROR_LOG("localtime_r failed"); -#endif + return error_func(exp.error()); + } - // Format the date using fmt::format - std::string date = fmt::format("{:%e}", localTime); + fn GetDate() -> string { + using namespace std::chrono; - // Remove leading whitespace - if (!date.empty() && std::isspace(date.front())) - date.erase(date.begin()); + const year_month_day ymd = year_month_day { floor(system_clock::now()) }; - // Append appropriate suffix for the datE - if (date.back() == '1' && date != "11") - date += "st"; - else if (date.back() == '2' && date != "12") - date += "nd"; - else if (date.back() == '3' && date != "13") - date += "rd"; - else - date += "th"; + string month = std::format("{:%B}", ymd); - return fmt::format("{:%B} {}", localTime, date); + i32 day = static_cast(ymd.day()); + + const char* suffix = (day >= 11 && day <= 13) ? "th" + : (day % 10 == 1) ? "st" + : (day % 10 == 2) ? "nd" + : (day % 10 == 3) ? "rd" + : "th"; + + return std::format("{} {}{}", month, day, suffix); } struct SystemData { @@ -84,15 +145,15 @@ namespace { SystemData data; // Single-threaded execution for core system info (faster on Windows) - data.date = GetDate(); - data.host = GetHost(); - data.kernel_version = GetKernelVersion(); - data.os_version = GetOSVersion(); - data.mem_info = GetMemInfo(); + data.date = std::move(GetDate()); + data.host = std::move(GetHost()); + data.kernel_version = std::move(GetKernelVersion()); + data.os_version = std::move(GetOSVersion()); + data.mem_info = std::move(GetMemInfo()); // Desktop environment info - data.desktop_environment = GetDesktopEnvironment(); - data.window_manager = GetWindowManager(); + data.desktop_environment = std::move(GetDesktopEnvironment()); + data.window_manager = std::move(GetWindowManager()); // Parallel execution for disk/shell only auto diskShell = std::async(std::launch::async, [] { @@ -128,13 +189,12 @@ namespace { using namespace ftxui; fn CreateColorCircles() -> Element { - Elements circles(16); - - std::generate_n(circles.begin(), 16, [colorIndex = 0]() mutable { - return hbox({ text("◯") | bold | color(static_cast(colorIndex++)), text(" ") }); - }); - - return hbox(circles); + return hbox( + std::views::iota(0, 16) | std::views::transform([](int colorIndex) { + return hbox({ text("◯") | bold | color(static_cast(colorIndex)), text(" ") }); + }) | + std::ranges::to() + ); } fn SystemInfoBox(const Config& config, const SystemData& data) -> Element { @@ -143,44 +203,32 @@ namespace { const Weather weather = config.weather; const bool nowPlayingEnabled = config.now_playing.enabled; - const char *calendarIcon = "", *hostIcon = "", *kernelIcon = "", *osIcon = "", *memoryIcon = "", *weatherIcon = "", - *musicIcon = ""; - - if (SHOW_ICONS) { - calendarIcon = "  "; - hostIcon = " 󰌢 "; - kernelIcon = "  "; - osIcon = "  "; - memoryIcon = "  "; - weatherIcon = "  "; - musicIcon = "  "; - } - - constexpr Color::Palette16 labelColor = Color::Yellow; - constexpr Color::Palette16 valueColor = Color::White; - constexpr Color::Palette16 borderColor = Color::GrayLight; - constexpr Color::Palette16 iconColor = Color::Cyan; + const auto& [userIcon, paletteIcon, calendarIcon, hostIcon, kernelIcon, osIcon, memoryIcon, weatherIcon, musicIcon, diskIcon, shellIcon, deIcon, wmIcon] = + SHOW_ICONS ? ui::NERD_ICONS : ui::EMPTY_ICONS; Elements content; - content.push_back(text("  Hello " + name + "! ") | bold | color(Color::Cyan)); - content.push_back(separator() | color(borderColor)); + content.push_back(text(string(userIcon) + "Hello " + name + "! ") | bold | color(Color::Cyan)); + content.push_back(separator() | color(ui::DEFAULT_THEME.border)); content.push_back(hbox( { - text("  ") | color(iconColor), // Palette icon + text(string(paletteIcon)) | color(ui::DEFAULT_THEME.icon), CreateColorCircles(), } )); - content.push_back(separator() | color(borderColor)); + content.push_back(separator() | color(ui::DEFAULT_THEME.border)); // Helper function for aligned rows - fn createRow = [&](const std::string& icon, const std::string& label, const std::string& value) { + auto createRow = [&](Icon&& icon, Label&& label, Value&& value) + requires std::constructible_from && std::constructible_from && + std::constructible_from + { return hbox( { - text(icon) | color(iconColor), - text(label) | color(labelColor), + text(string(std::forward(icon))) | color(ui::DEFAULT_THEME.icon), + text(string(std::forward