suckle
This commit is contained in:
parent
a5cdc09156
commit
96c6e79780
10 changed files with 177 additions and 202 deletions
|
@ -23,6 +23,7 @@ Checks: >
|
||||||
-llvmlibc-*,
|
-llvmlibc-*,
|
||||||
-misc-non-private-member-variables-in-classes,
|
-misc-non-private-member-variables-in-classes,
|
||||||
-modernize-use-nullptr,
|
-modernize-use-nullptr,
|
||||||
|
-readability-avoid-nested-conditional-operator,
|
||||||
-readability-braces-around-statements,
|
-readability-braces-around-statements,
|
||||||
-readability-function-cognitive-complexity,
|
-readability-function-cognitive-complexity,
|
||||||
-readability-implicit-bool-conversion,
|
-readability-implicit-bool-conversion,
|
||||||
|
|
|
@ -1,44 +0,0 @@
|
||||||
{
|
|
||||||
"fmt": {
|
|
||||||
"cargoLocks": null,
|
|
||||||
"date": null,
|
|
||||||
"extract": null,
|
|
||||||
"name": "fmt",
|
|
||||||
"passthru": null,
|
|
||||||
"pinned": false,
|
|
||||||
"src": {
|
|
||||||
"deepClone": false,
|
|
||||||
"fetchSubmodules": false,
|
|
||||||
"leaveDotGit": false,
|
|
||||||
"name": null,
|
|
||||||
"owner": "fmtlib",
|
|
||||||
"repo": "fmt",
|
|
||||||
"rev": "11.1.4",
|
|
||||||
"sha256": "sha256-sUbxlYi/Aupaox3JjWFqXIjcaQa0LFjclQAOleT+FRA=",
|
|
||||||
"sparseCheckout": [],
|
|
||||||
"type": "github"
|
|
||||||
},
|
|
||||||
"version": "11.1.4"
|
|
||||||
},
|
|
||||||
"tomlplusplus": {
|
|
||||||
"cargoLocks": null,
|
|
||||||
"date": null,
|
|
||||||
"extract": null,
|
|
||||||
"name": "tomlplusplus",
|
|
||||||
"passthru": null,
|
|
||||||
"pinned": false,
|
|
||||||
"src": {
|
|
||||||
"deepClone": false,
|
|
||||||
"fetchSubmodules": false,
|
|
||||||
"leaveDotGit": false,
|
|
||||||
"name": null,
|
|
||||||
"owner": "marzer",
|
|
||||||
"repo": "tomlplusplus",
|
|
||||||
"rev": "v3.4.0",
|
|
||||||
"sha256": "sha256-h5tbO0Rv2tZezY58yUbyRVpsfRjY3i+5TPkkxr6La8M=",
|
|
||||||
"sparseCheckout": [],
|
|
||||||
"type": "github"
|
|
||||||
},
|
|
||||||
"version": "v3.4.0"
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,26 +0,0 @@
|
||||||
# This file was generated by nvfetcher, please do not modify it manually.
|
|
||||||
{ fetchgit, fetchurl, fetchFromGitHub, dockerTools }:
|
|
||||||
{
|
|
||||||
fmt = {
|
|
||||||
pname = "fmt";
|
|
||||||
version = "11.1.4";
|
|
||||||
src = fetchFromGitHub {
|
|
||||||
owner = "fmtlib";
|
|
||||||
repo = "fmt";
|
|
||||||
rev = "11.1.4";
|
|
||||||
fetchSubmodules = false;
|
|
||||||
sha256 = "sha256-sUbxlYi/Aupaox3JjWFqXIjcaQa0LFjclQAOleT+FRA=";
|
|
||||||
};
|
|
||||||
};
|
|
||||||
tomlplusplus = {
|
|
||||||
pname = "tomlplusplus";
|
|
||||||
version = "v3.4.0";
|
|
||||||
src = fetchFromGitHub {
|
|
||||||
owner = "marzer";
|
|
||||||
repo = "tomlplusplus";
|
|
||||||
rev = "v3.4.0";
|
|
||||||
fetchSubmodules = false;
|
|
||||||
sha256 = "sha256-h5tbO0Rv2tZezY58yUbyRVpsfRjY3i+5TPkkxr6La8M=";
|
|
||||||
};
|
|
||||||
};
|
|
||||||
}
|
|
14
flake.nix
14
flake.nix
|
@ -31,26 +31,12 @@
|
||||||
)
|
)
|
||||||
llvmPackages.stdenv;
|
llvmPackages.stdenv;
|
||||||
|
|
||||||
sources = import ./_sources/generated.nix {
|
|
||||||
inherit (pkgs) fetchFromGitHub fetchgit fetchurl dockerTools;
|
|
||||||
};
|
|
||||||
|
|
||||||
fmt = pkgs.pkgsStatic.fmt.overrideAttrs (old: {
|
|
||||||
inherit (sources.fmt) pname version src;
|
|
||||||
});
|
|
||||||
|
|
||||||
tomlplusplus = pkgs.pkgsStatic.tomlplusplus.overrideAttrs {
|
|
||||||
inherit (sources.tomlplusplus) pname version src;
|
|
||||||
doCheck = false;
|
|
||||||
};
|
|
||||||
|
|
||||||
deps = with pkgs;
|
deps = with pkgs;
|
||||||
[
|
[
|
||||||
(glaze.override {enableAvx2 = hostPlatform.isx86;})
|
(glaze.override {enableAvx2 = hostPlatform.isx86;})
|
||||||
]
|
]
|
||||||
++ (with pkgsStatic; [
|
++ (with pkgsStatic; [
|
||||||
curl
|
curl
|
||||||
fmt
|
|
||||||
ftxui
|
ftxui
|
||||||
libiconv
|
libiconv
|
||||||
sqlitecpp
|
sqlitecpp
|
||||||
|
|
|
@ -99,7 +99,6 @@ sources = base_sources + files(platform_sources.get(host_system, []))
|
||||||
# Dependencies Config #
|
# Dependencies Config #
|
||||||
# --------------------- #
|
# --------------------- #
|
||||||
common_deps = [
|
common_deps = [
|
||||||
dependency('fmt', include_type: 'system', static: true),
|
|
||||||
dependency('libcurl', include_type: 'system', static: true),
|
dependency('libcurl', include_type: 'system', static: true),
|
||||||
dependency('tomlplusplus', include_type: 'system', static: true),
|
dependency('tomlplusplus', include_type: 'system', static: true),
|
||||||
dependency('openssl', include_type: 'system', static: true, required: false),
|
dependency('openssl', include_type: 'system', static: true, required: false),
|
||||||
|
|
|
@ -1,7 +0,0 @@
|
||||||
[fmt]
|
|
||||||
src.github = "fmtlib/fmt"
|
|
||||||
fetch.github = "fmtlib/fmt"
|
|
||||||
|
|
||||||
[tomlplusplus]
|
|
||||||
src.github = "marzer/tomlplusplus"
|
|
||||||
fetch.github = "marzer/tomlplusplus"
|
|
|
@ -1,6 +1,5 @@
|
||||||
#include <cstdlib>
|
#include <cstdlib>
|
||||||
#include <filesystem>
|
#include <filesystem>
|
||||||
#include <fmt/core.h>
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
#include <stdexcept>
|
#include <stdexcept>
|
||||||
|
|
||||||
|
|
|
@ -2,7 +2,6 @@
|
||||||
#include <curl/curl.h>
|
#include <curl/curl.h>
|
||||||
#include <expected>
|
#include <expected>
|
||||||
#include <filesystem>
|
#include <filesystem>
|
||||||
#include <fmt/core.h>
|
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
|
|
||||||
#include "weather.h"
|
#include "weather.h"
|
||||||
|
@ -114,7 +113,7 @@ namespace {
|
||||||
curl_easy_cleanup(curl);
|
curl_easy_cleanup(curl);
|
||||||
|
|
||||||
if (res != CURLE_OK)
|
if (res != CURLE_OK)
|
||||||
return std::unexpected(fmt::format("cURL error: {}", curl_easy_strerror(res)));
|
return std::unexpected(std::format("cURL error: {}", curl_easy_strerror(res)));
|
||||||
|
|
||||||
WeatherOutput output;
|
WeatherOutput output;
|
||||||
|
|
||||||
|
@ -160,7 +159,7 @@ fn Weather::getWeatherInfo() const -> WeatherOutput {
|
||||||
DEBUG_LOG("Requesting city: {}", escaped);
|
DEBUG_LOG("Requesting city: {}", escaped);
|
||||||
|
|
||||||
const string apiUrl =
|
const string apiUrl =
|
||||||
fmt::format("https://api.openweathermap.org/data/2.5/weather?q={}&appid={}&units={}", escaped, api_key, units);
|
std::format("https://api.openweathermap.org/data/2.5/weather?q={}&appid={}&units={}", escaped, api_key, units);
|
||||||
|
|
||||||
curl_free(escaped);
|
curl_free(escaped);
|
||||||
return handleApiResult(MakeApiRequest(apiUrl));
|
return handleApiResult(MakeApiRequest(apiUrl));
|
||||||
|
@ -169,7 +168,7 @@ fn Weather::getWeatherInfo() const -> WeatherOutput {
|
||||||
const auto& [lat, lon] = std::get<Coords>(location);
|
const auto& [lat, lon] = std::get<Coords>(location);
|
||||||
DEBUG_LOG("Requesting coordinates: lat={:.3f}, lon={:.3f}", lat, lon);
|
DEBUG_LOG("Requesting coordinates: lat={:.3f}, lon={:.3f}", lat, lon);
|
||||||
|
|
||||||
const string apiUrl = fmt::format(
|
const string apiUrl = std::format(
|
||||||
"https://api.openweathermap.org/data/2.5/weather?lat={:.3f}&lon={:.3f}&appid={}&units={}", lat, lon, api_key, units
|
"https://api.openweathermap.org/data/2.5/weather?lat={:.3f}&lon={:.3f}&appid={}&units={}", lat, lon, api_key, units
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|
132
src/main.cpp
132
src/main.cpp
|
@ -1,4 +1,4 @@
|
||||||
#include <ctime>
|
#include <chrono>
|
||||||
#include <expected>
|
#include <expected>
|
||||||
#include <ftxui/dom/elements.hpp>
|
#include <ftxui/dom/elements.hpp>
|
||||||
#include <ftxui/screen/color.hpp>
|
#include <ftxui/screen/color.hpp>
|
||||||
|
@ -31,7 +31,6 @@ namespace ui {
|
||||||
using ftxui::Color;
|
using ftxui::Color;
|
||||||
|
|
||||||
constexpr int MAX_PARAGRAPH_LENGTH = 30;
|
constexpr int MAX_PARAGRAPH_LENGTH = 30;
|
||||||
constexpr int PADDING = 3;
|
|
||||||
|
|
||||||
// Color themes
|
// Color themes
|
||||||
struct Theme {
|
struct Theme {
|
||||||
|
@ -116,13 +115,15 @@ namespace {
|
||||||
|
|
||||||
string month = std::format("{:%B}", ymd);
|
string month = std::format("{:%B}", ymd);
|
||||||
|
|
||||||
i32 day = static_cast<unsigned>(ymd.day());
|
u32 day = static_cast<u32>(ymd.day());
|
||||||
|
|
||||||
const char* suffix = (day >= 11 && day <= 13) ? "th"
|
const char* suffix = static_cast<const char*>(
|
||||||
: (day % 10 == 1) ? "st"
|
(day >= 11 && day <= 13) ? "th"
|
||||||
: (day % 10 == 2) ? "nd"
|
: (day % 10 == 1) ? "st"
|
||||||
: (day % 10 == 3) ? "rd"
|
: (day % 10 == 2) ? "nd"
|
||||||
: "th";
|
: (day % 10 == 3) ? "rd"
|
||||||
|
: "th"
|
||||||
|
);
|
||||||
|
|
||||||
return std::format("{} {}{}", month, day, suffix);
|
return std::format("{} {}{}", month, day, suffix);
|
||||||
}
|
}
|
||||||
|
@ -145,15 +146,15 @@ namespace {
|
||||||
SystemData data;
|
SystemData data;
|
||||||
|
|
||||||
// Single-threaded execution for core system info (faster on Windows)
|
// Single-threaded execution for core system info (faster on Windows)
|
||||||
data.date = std::move(GetDate());
|
data.date = GetDate();
|
||||||
data.host = std::move(GetHost());
|
data.host = GetHost();
|
||||||
data.kernel_version = std::move(GetKernelVersion());
|
data.kernel_version = GetKernelVersion();
|
||||||
data.os_version = std::move(GetOSVersion());
|
data.os_version = GetOSVersion();
|
||||||
data.mem_info = std::move(GetMemInfo());
|
data.mem_info = GetMemInfo();
|
||||||
|
|
||||||
// Desktop environment info
|
// Desktop environment info
|
||||||
data.desktop_environment = std::move(GetDesktopEnvironment());
|
data.desktop_environment = GetDesktopEnvironment();
|
||||||
data.window_manager = std::move(GetWindowManager());
|
data.window_manager = GetWindowManager();
|
||||||
|
|
||||||
// Parallel execution for disk/shell only
|
// Parallel execution for disk/shell only
|
||||||
auto diskShell = std::async(std::launch::async, [] {
|
auto diskShell = std::async(std::launch::async, [] {
|
||||||
|
@ -210,28 +211,21 @@ namespace {
|
||||||
|
|
||||||
content.push_back(text(string(userIcon) + "Hello " + name + "! ") | bold | color(Color::Cyan));
|
content.push_back(text(string(userIcon) + "Hello " + name + "! ") | bold | color(Color::Cyan));
|
||||||
content.push_back(separator() | color(ui::DEFAULT_THEME.border));
|
content.push_back(separator() | color(ui::DEFAULT_THEME.border));
|
||||||
content.push_back(hbox(
|
content.push_back(hbox({
|
||||||
{
|
text(string(paletteIcon)) | color(ui::DEFAULT_THEME.icon),
|
||||||
text(string(paletteIcon)) | color(ui::DEFAULT_THEME.icon),
|
CreateColorCircles(),
|
||||||
CreateColorCircles(),
|
}));
|
||||||
}
|
|
||||||
));
|
|
||||||
content.push_back(separator() | color(ui::DEFAULT_THEME.border));
|
content.push_back(separator() | color(ui::DEFAULT_THEME.border));
|
||||||
|
|
||||||
// Helper function for aligned rows
|
// Helper function for aligned rows
|
||||||
auto createRow = [&]<typename Icon, typename Label, typename Value>(Icon&& icon, Label&& label, Value&& value)
|
fn createRow = [&](const auto& icon, const auto& label, const auto& value) {
|
||||||
requires std::constructible_from<string, Icon> && std::constructible_from<string, Label> &&
|
return hbox({
|
||||||
std::constructible_from<string, Value>
|
text(string(icon)) | color(ui::DEFAULT_THEME.icon),
|
||||||
{
|
text(string(static_cast<const char*>(label))) | color(ui::DEFAULT_THEME.label),
|
||||||
return hbox(
|
filler(),
|
||||||
{
|
text(string(value)) | color(ui::DEFAULT_THEME.value),
|
||||||
text(string(std::forward<Icon>(icon))) | color(ui::DEFAULT_THEME.icon),
|
text(" "),
|
||||||
text(string(std::forward<Label>(label))) | color(ui::DEFAULT_THEME.label),
|
});
|
||||||
filler(),
|
|
||||||
text(string(std::forward<Value>(value))) | color(ui::DEFAULT_THEME.value),
|
|
||||||
text(" "),
|
|
||||||
}
|
|
||||||
);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// System info rows
|
// System info rows
|
||||||
|
@ -242,39 +236,31 @@ namespace {
|
||||||
const WeatherOutput& weatherInfo = data.weather_info.value();
|
const WeatherOutput& weatherInfo = data.weather_info.value();
|
||||||
|
|
||||||
if (weather.show_town_name)
|
if (weather.show_town_name)
|
||||||
content.push_back(hbox(
|
content.push_back(hbox({
|
||||||
{
|
text(string(weatherIcon)) | color(ui::DEFAULT_THEME.icon),
|
||||||
text(string(weatherIcon)) | color(ui::DEFAULT_THEME.icon),
|
text("Weather") | color(ui::DEFAULT_THEME.label),
|
||||||
text("Weather") | color(ui::DEFAULT_THEME.label),
|
filler(),
|
||||||
filler(),
|
|
||||||
|
|
||||||
hbox(
|
hbox({
|
||||||
{
|
text(std::format("{}°F ", std::lround(weatherInfo.main.temp))),
|
||||||
text(std::format("{}°F ", std::lround(weatherInfo.main.temp))),
|
text("in "),
|
||||||
text("in "),
|
text(weatherInfo.name),
|
||||||
text(weatherInfo.name),
|
text(" "),
|
||||||
text(" "),
|
}) |
|
||||||
}
|
color(ui::DEFAULT_THEME.value),
|
||||||
) |
|
}));
|
||||||
color(ui::DEFAULT_THEME.value),
|
|
||||||
}
|
|
||||||
));
|
|
||||||
else
|
else
|
||||||
content.push_back(hbox(
|
content.push_back(hbox({
|
||||||
{
|
text(string(weatherIcon)) | color(ui::DEFAULT_THEME.icon),
|
||||||
text(string(weatherIcon)) | color(ui::DEFAULT_THEME.icon),
|
text("Weather") | color(ui::DEFAULT_THEME.label),
|
||||||
text("Weather") | color(ui::DEFAULT_THEME.label),
|
filler(),
|
||||||
filler(),
|
|
||||||
|
|
||||||
hbox(
|
hbox({
|
||||||
{
|
text(std::format("{}°F, {}", std::lround(weatherInfo.main.temp), weatherInfo.weather[0].description)),
|
||||||
text(std::format("{}°F, {}", std::lround(weatherInfo.main.temp), weatherInfo.weather[0].description)),
|
text(" "),
|
||||||
text(" "),
|
}) |
|
||||||
}
|
color(ui::DEFAULT_THEME.value),
|
||||||
) |
|
}));
|
||||||
color(ui::DEFAULT_THEME.value),
|
|
||||||
}
|
|
||||||
));
|
|
||||||
}
|
}
|
||||||
|
|
||||||
content.push_back(separator() | color(ui::DEFAULT_THEME.border));
|
content.push_back(separator() | color(ui::DEFAULT_THEME.border));
|
||||||
|
@ -319,16 +305,14 @@ namespace {
|
||||||
const std::string& npText = *nowPlayingResult;
|
const std::string& npText = *nowPlayingResult;
|
||||||
|
|
||||||
content.push_back(separator() | color(ui::DEFAULT_THEME.border));
|
content.push_back(separator() | color(ui::DEFAULT_THEME.border));
|
||||||
content.push_back(hbox(
|
content.push_back(hbox({
|
||||||
{
|
text(string(musicIcon)) | color(ui::DEFAULT_THEME.icon),
|
||||||
text(string(musicIcon)) | color(ui::DEFAULT_THEME.icon),
|
text("Playing") | color(ui::DEFAULT_THEME.label),
|
||||||
text("Playing") | color(ui::DEFAULT_THEME.label),
|
text(" "),
|
||||||
text(" "),
|
filler(),
|
||||||
filler(),
|
paragraph(npText) | color(Color::Magenta) | size(WIDTH, LESS_THAN, ui::MAX_PARAGRAPH_LENGTH),
|
||||||
paragraph(npText) | color(Color::Magenta) | size(WIDTH, LESS_THAN, 30),
|
text(" "),
|
||||||
text(" "),
|
}));
|
||||||
}
|
|
||||||
));
|
|
||||||
} else {
|
} else {
|
||||||
const NowPlayingError& error = nowPlayingResult.error();
|
const NowPlayingError& error = nowPlayingResult.error();
|
||||||
|
|
||||||
|
|
|
@ -2,11 +2,10 @@
|
||||||
|
|
||||||
// probably stupid but it fixes the issue with windows.h defining ERROR
|
// probably stupid but it fixes the issue with windows.h defining ERROR
|
||||||
#undef ERROR
|
#undef ERROR
|
||||||
|
#include <chrono>
|
||||||
#include <filesystem>
|
#include <filesystem>
|
||||||
#include <fmt/chrono.h>
|
#include <format>
|
||||||
#include <fmt/color.h>
|
#include <print>
|
||||||
#include <fmt/format.h>
|
|
||||||
#include <source_location>
|
#include <source_location>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
|
||||||
|
@ -14,18 +13,117 @@
|
||||||
|
|
||||||
#define fn auto // Rust-style function shorthand
|
#define fn auto // Rust-style function shorthand
|
||||||
|
|
||||||
|
// Terminal color implementation to replace fmt::color
|
||||||
|
namespace term {
|
||||||
|
// Text styles
|
||||||
|
enum class Emphasis : u8 { none = 0, bold = 1, italic = 2 };
|
||||||
|
|
||||||
|
constexpr fn operator|(Emphasis emphA, Emphasis emphB)->Emphasis {
|
||||||
|
return static_cast<Emphasis>(static_cast<int>(emphA) | static_cast<int>(emphB));
|
||||||
|
}
|
||||||
|
|
||||||
|
// Terminal colors
|
||||||
|
enum class Color : u8 {
|
||||||
|
black = 30,
|
||||||
|
red = 31,
|
||||||
|
green = 32,
|
||||||
|
yellow = 33,
|
||||||
|
blue = 34,
|
||||||
|
magenta = 35,
|
||||||
|
cyan = 36,
|
||||||
|
white = 37,
|
||||||
|
bright_black = 90,
|
||||||
|
bright_red = 91,
|
||||||
|
bright_green = 92,
|
||||||
|
bright_yellow = 93,
|
||||||
|
bright_blue = 94,
|
||||||
|
bright_magenta = 95,
|
||||||
|
bright_cyan = 96,
|
||||||
|
bright_white = 97
|
||||||
|
};
|
||||||
|
|
||||||
|
// Style wrapper for foreground color
|
||||||
|
struct FgColor {
|
||||||
|
Color col;
|
||||||
|
|
||||||
|
constexpr explicit FgColor(Color color) : col(color) {}
|
||||||
|
|
||||||
|
[[nodiscard]] fn ansiCode() const -> std::string { return std::format("\033[{}m", static_cast<int>(col)); }
|
||||||
|
};
|
||||||
|
|
||||||
|
// Create a foreground color modifier
|
||||||
|
constexpr fn Fg(Color color) -> FgColor { return FgColor(color); }
|
||||||
|
|
||||||
|
// Combined style (emphasis + color)
|
||||||
|
struct Style {
|
||||||
|
Emphasis emph = Emphasis::none;
|
||||||
|
FgColor fg_col = FgColor(static_cast<Color>(-1)); // Invalid color
|
||||||
|
|
||||||
|
[[nodiscard]] fn ansiCode() const -> std::string {
|
||||||
|
std::string result;
|
||||||
|
|
||||||
|
if (emph != Emphasis::none) {
|
||||||
|
if ((static_cast<int>(emph) & static_cast<int>(Emphasis::bold)) != 0) {
|
||||||
|
result += "\033[1m";
|
||||||
|
}
|
||||||
|
if ((static_cast<int>(emph) & static_cast<int>(Emphasis::italic)) != 0) {
|
||||||
|
result += "\033[3m";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (static_cast<int>(fg_col.col) != -1) {
|
||||||
|
result += fg_col.ansiCode();
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
// Combine emphasis and color
|
||||||
|
constexpr fn operator|(Emphasis emph, FgColor fgColor)->Style { return { .emph = emph, .fg_col = fgColor }; }
|
||||||
|
|
||||||
|
constexpr fn operator|(FgColor fgColor, Emphasis emph)->Style { return emph | fgColor; }
|
||||||
|
|
||||||
|
// Reset all styles
|
||||||
|
constexpr const char* reset = "\033[0m";
|
||||||
|
|
||||||
|
// Print with style
|
||||||
|
template <typename... Args>
|
||||||
|
fn Print(const Style& style, std::format_string<Args...> fmt, Args&&... args) -> void {
|
||||||
|
std::print("{}{}{}", style.ansiCode(), std::format(fmt, std::forward<Args>(args)...), reset);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Print with foreground color only
|
||||||
|
template <typename... Args>
|
||||||
|
fn Print(const FgColor& fgColor, std::format_string<Args...> fmt, Args&&... args) -> void {
|
||||||
|
std::print("{}{}{}", fgColor.ansiCode(), std::format(fmt, std::forward<Args>(args)...), reset);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Print with emphasis only
|
||||||
|
template <typename... Args>
|
||||||
|
fn Print(Emphasis emph, std::format_string<Args...> fmt, Args&&... args) -> void {
|
||||||
|
Print({ .emph = emph }, fmt, std::forward<Args>(args)...);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Print without styling (plain text)
|
||||||
|
template <typename... Args>
|
||||||
|
fn Print(std::format_string<Args...> fmt, Args&&... args) -> void {
|
||||||
|
std::print(fmt, std::forward<Args>(args)...);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
namespace log_colors {
|
namespace log_colors {
|
||||||
using fmt::terminal_color;
|
using term::Color;
|
||||||
constexpr auto debug = terminal_color::cyan, info = terminal_color::green, warn = terminal_color::yellow,
|
constexpr auto debug = Color::cyan, info = Color::green, warn = Color::yellow, error = Color::red,
|
||||||
error = terminal_color::red, timestamp = terminal_color::bright_white,
|
timestamp = Color::bright_white, file_info = Color::bright_white;
|
||||||
file_info = terminal_color::bright_white;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
enum class LogLevel : u8 { DEBUG, INFO, WARN, ERROR };
|
enum class LogLevel : u8 { DEBUG, INFO, WARN, ERROR };
|
||||||
|
|
||||||
template <typename... Args>
|
template <typename... Args>
|
||||||
void LogImpl(const LogLevel level, const std::source_location& loc, fmt::format_string<Args...> fmt, Args&&... args) {
|
void LogImpl(const LogLevel level, const std::source_location& loc, std::format_string<Args...> fmt, Args&&... args) {
|
||||||
const time_t now = std::time(nullptr);
|
const auto now = std::chrono::floor<std::chrono::seconds>(std::chrono::system_clock::now());
|
||||||
|
|
||||||
const auto [color, levelStr] = [&] {
|
const auto [color, levelStr] = [&] {
|
||||||
switch (level) {
|
switch (level) {
|
||||||
case LogLevel::DEBUG:
|
case LogLevel::DEBUG:
|
||||||
|
@ -43,32 +141,19 @@ void LogImpl(const LogLevel level, const std::source_location& loc, fmt::format_
|
||||||
#pragma clang diagnostic pop
|
#pragma clang diagnostic pop
|
||||||
}
|
}
|
||||||
}();
|
}();
|
||||||
|
|
||||||
const string filename = std::filesystem::path(loc.file_name()).lexically_normal().string();
|
const string filename = std::filesystem::path(loc.file_name()).lexically_normal().string();
|
||||||
std::tm time;
|
|
||||||
|
|
||||||
#ifdef _WIN32
|
|
||||||
if (localtime_s(&time, &now) != 0)
|
|
||||||
throw std::runtime_error("localtime_s failed");
|
|
||||||
#else
|
|
||||||
if (localtime_r(&now, &time) == nullptr)
|
|
||||||
throw std::runtime_error("localtime_r failed");
|
|
||||||
#endif
|
|
||||||
|
|
||||||
// Timestamp and level
|
|
||||||
fmt::print(fg(log_colors::timestamp), "[{:%H:%M:%S}] ", time);
|
|
||||||
fmt::print(fmt::emphasis::bold | fg(color), "{} ", levelStr);
|
|
||||||
|
|
||||||
|
// Timestamp and level - using std::chrono with std::format
|
||||||
|
term::Print(term::Fg(log_colors::timestamp), "[{:%H:%M:%S}] ", now);
|
||||||
|
term::Print(term::Emphasis::bold | term::Fg(color), "{} ", levelStr);
|
||||||
// Message
|
// Message
|
||||||
fmt::print(fmt, std::forward<Args>(args)...);
|
term::Print(fmt, std::forward<Args>(args)...);
|
||||||
|
|
||||||
// File info (debug builds only)
|
// File info (debug builds only)
|
||||||
#ifndef NDEBUG
|
#ifndef NDEBUG
|
||||||
fmt::print(fg(log_colors::file_info), "\n{:>14} ", "╰──");
|
term::Print(term::Fg(log_colors::file_info), "\n{:>14} ", "╰──");
|
||||||
fmt::print(fmt::emphasis::italic | fg(log_colors::file_info), "{}:{}", filename, loc.line());
|
term::Print(term::Emphasis::italic | term::Fg(log_colors::file_info), "{}:{}", filename, loc.line());
|
||||||
#endif
|
#endif
|
||||||
|
term::Print("\n");
|
||||||
fmt::print("\n");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#pragma clang diagnostic push
|
#pragma clang diagnostic push
|
||||||
|
@ -78,7 +163,6 @@ void LogImpl(const LogLevel level, const std::source_location& loc, fmt::format_
|
||||||
#else
|
#else
|
||||||
#define DEBUG_LOG(...) LogImpl(LogLevel::DEBUG, std::source_location::current(), __VA_ARGS__)
|
#define DEBUG_LOG(...) LogImpl(LogLevel::DEBUG, std::source_location::current(), __VA_ARGS__)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#define INFO_LOG(...) LogImpl(LogLevel::INFO, std::source_location::current(), __VA_ARGS__)
|
#define INFO_LOG(...) LogImpl(LogLevel::INFO, std::source_location::current(), __VA_ARGS__)
|
||||||
#define WARN_LOG(...) LogImpl(LogLevel::WARN, std::source_location::current(), __VA_ARGS__)
|
#define WARN_LOG(...) LogImpl(LogLevel::WARN, std::source_location::current(), __VA_ARGS__)
|
||||||
#define ERROR_LOG(...) LogImpl(LogLevel::ERROR, std::source_location::current(), __VA_ARGS__)
|
#define ERROR_LOG(...) LogImpl(LogLevel::ERROR, std::source_location::current(), __VA_ARGS__)
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue