diff --git a/.clang-format b/.clang-format index 4c7523b..6843477 100644 --- a/.clang-format +++ b/.clang-format @@ -10,6 +10,7 @@ AllowShortLoopsOnASingleLine: true BasedOnStyle: Chromium BinPackArguments: false BinPackParameters: false +FixNamespaceComments: false IndentAccessModifiers: false IndentExternBlock: Indent NamespaceIndentation: All diff --git a/.clang-tidy b/.clang-tidy index 5078384..9518fbd 100644 --- a/.clang-tidy +++ b/.clang-tidy @@ -13,6 +13,7 @@ Checks: > -hicpp-*, -llvm-include-order, -llvm-include-order, + -llvm-namespace-comment, -llvmlibc-*, -misc-non-private-member-variables-in-classes, -readability-braces-around-statements, diff --git a/flake.lock b/flake.lock index 4d4c120..457004b 100644 --- a/flake.lock +++ b/flake.lock @@ -2,11 +2,11 @@ "nodes": { "nixpkgs": { "locked": { - "lastModified": 1717646450, - "narHash": "sha256-KE+UmfSVk5PG8jdKdclPVcMrUB8yVZHbsjo7ZT1Bm3c=", + "lastModified": 1718149104, + "narHash": "sha256-Ds1QpobBX2yoUDx9ZruqVGJ/uQPgcXoYuobBguyKEh8=", "owner": "NixOS", "repo": "nixpkgs", - "rev": "818dbe2f96df233d2041739d6079bb616d3e5597", + "rev": "e913ae340076bbb73d9f4d3d065c2bca7caafb16", "type": "github" }, "original": { @@ -59,11 +59,11 @@ "nixpkgs": "nixpkgs_2" }, "locked": { - "lastModified": 1717850719, - "narHash": "sha256-npYqVg+Wk4oxnWrnVG7416fpfrlRhp/lQ6wQ4DHI8YE=", + "lastModified": 1718271476, + "narHash": "sha256-35hUMmFesmchb+u7heKHLG5B6c8fBOcSYo0jj0CHLes=", "owner": "numtide", "repo": "treefmt-nix", - "rev": "4fc1c45a5f50169f9f29f6a98a438fb910b834ed", + "rev": "e75ba0a6bb562d2ce275db28f6a36a2e4fd81391", "type": "github" }, "original": { diff --git a/include/util/macros.h b/include/util/macros.h new file mode 100644 index 0000000..f5fe51b --- /dev/null +++ b/include/util/macros.h @@ -0,0 +1,3 @@ +#define fn auto +#define DEFINE_GETTER(class_name, type, name) \ + fn class_name::get##name() const->type { return m_##name; } diff --git a/include/util/numtypes.h b/include/util/numtypes.h index dc4a82f..86f957c 100644 --- a/include/util/numtypes.h +++ b/include/util/numtypes.h @@ -3,8 +3,6 @@ #include #include -#define fn auto - // Unsigned integers using u8 = std::uint8_t; using u16 = std::uint16_t; diff --git a/meson.build b/meson.build index 87cd266..87989f9 100644 --- a/meson.build +++ b/meson.build @@ -4,7 +4,7 @@ project( default_options: [ 'objc_std=c++20', 'objcpp_std=c++20', - 'cpp_std=c++23', + 'cpp_std=c++20', 'default_library=static', 'warning_level=everything', 'buildtype=debugoptimized' diff --git a/src/config/config.cpp b/src/config/config.cpp index 81d419f..6c59238 100644 --- a/src/config/config.cpp +++ b/src/config/config.cpp @@ -1,32 +1,12 @@ #include "config.h" -#define DEFINE_GETTER(class_name, type, name) \ - fn class_name::get##name() const->type { return m_##name; } - -DEFINE_GETTER(Config, const General, General) -DEFINE_GETTER(Config, const NowPlaying, NowPlaying) -DEFINE_GETTER(Config, const Weather, Weather) -DEFINE_GETTER(General, const std::string, Name) -DEFINE_GETTER(NowPlaying, bool, Enabled) +// ------------- +// -- Weather -- +// ------------- DEFINE_GETTER(Weather, const Weather::Location, Location) DEFINE_GETTER(Weather, const std::string, ApiKey) DEFINE_GETTER(Weather, const std::string, Units) -fn Config::getInstance() -> const Config& { - static const auto* INSTANCE = - new Config(rfl::toml::load("./config.toml").value()); - return *INSTANCE; -} - -Config::Config(General general, NowPlaying now_playing, Weather weather) - : m_General(std::move(general)), - m_NowPlaying(now_playing), - m_Weather(std::move(weather)) {} - -General::General(std::string name) : m_Name(std::move(name)) {} - -NowPlaying::NowPlaying(bool enabled) : m_Enabled(enabled) {} - Weather::Weather(Location location, std::string api_key, std::string units) : m_Location(std::move(location)), m_ApiKey(std::move(api_key)), @@ -43,22 +23,56 @@ fn WeatherImpl::from_class(const Weather& weather) noexcept -> WeatherImpl { fn WeatherImpl::to_class() const -> Weather { return {location, api_key, units}; } +// ------------ + +// ------------- +// -- General -- +// ------------- +DEFINE_GETTER(General, const std::string, Name) + +General::General(std::string name) : m_Name(std::move(name)) {} fn GeneralImpl::from_class(const General& general) noexcept -> GeneralImpl { return {general.getName()}; } fn GeneralImpl::to_class() const -> General { return {name}; } +// ------------- -// clang-format off -fn NowPlayingImpl::from_class( - const NowPlaying& now_playing +// ---------------- +// -- NowPlaying -- +// ---------------- +DEFINE_GETTER(NowPlaying, bool, Enabled) + +NowPlaying::NowPlaying(bool enabled) : m_Enabled(enabled) {} + +fn NowPlayingImpl::from_class(const NowPlaying& now_playing ) noexcept -> NowPlayingImpl { return {.enabled = now_playing.getEnabled()}; } -//clang-format on -fn NowPlayingImpl::to_class() const -> NowPlaying { return {enabled.value_or(false)}; } +fn NowPlayingImpl::to_class() const -> NowPlaying { + return {enabled.value_or(false)}; +} +// ---------------- + +// ------------ +// -- Config -- +// ------------ +DEFINE_GETTER(Config, const General, General) +DEFINE_GETTER(Config, const NowPlaying, NowPlaying) +DEFINE_GETTER(Config, const Weather, Weather) + +Config::Config(General general, NowPlaying now_playing, Weather weather) + : m_General(std::move(general)), + m_NowPlaying(now_playing), + m_Weather(std::move(weather)) {} + +fn Config::getInstance() -> const Config& { + static const auto* INSTANCE = + new Config(rfl::toml::load("./config.toml").value()); + return *INSTANCE; +} fn ConfigImpl::from_class(const Config& config) noexcept -> ConfigImpl { return { @@ -71,3 +85,4 @@ fn ConfigImpl::from_class(const Config& config) noexcept -> ConfigImpl { fn ConfigImpl::to_class() const -> Config { return {general, now_playing, weather}; } +// ------------ diff --git a/src/config/config.h b/src/config/config.h index d50e16a..940e8b4 100644 --- a/src/config/config.h +++ b/src/config/config.h @@ -4,104 +4,11 @@ #include #include #include -#include -#include "util/numtypes.h" +#include "util/macros.h" +#include "weather.h" -class Weather { - public: - using degrees = rfl::Validator, rfl::Maximum<360>>; - using percentage = rfl::Validator, rfl::Maximum<100>>; - - struct Condition { - std::string description; - std::string icon; - std::string main; - usize id; - }; - - struct Main { - f64 feels_like; - f64 temp; - f64 temp_max; - f64 temp_min; - isize pressure; - percentage humidity; - std::optional grnd_level; - std::optional sea_level; - }; - - struct Wind { - degrees deg; - f64 speed; - std::optional gust; - }; - - struct Precipitation { - rfl::Rename<"1h", f64> one_hour; - rfl::Rename<"3h", f64> three_hours; - }; - - struct Sys { - std::string country; - usize id; - usize sunrise; - usize sunset; - usize type; - }; - - struct Clouds { - percentage all; - }; - - struct Coords { - double lat; - double lon; - }; - - struct WeatherOutput { - Clouds clouds; - isize timezone; - isize visibility; - Main main; - rfl::Rename<"coord", Coords> coords; - std::optional rain; - std::optional snow; - std::string base; - std::string name; - std::vector weather; - Sys sys; - usize cod; - usize dt; - usize id; - Wind wind; - }; - - using Location = std::variant; - - private: - Location m_Location; - std::string m_ApiKey; - std::string m_Units; - - public: - Weather(Location location, std::string api_key, std::string units); - - [[nodiscard]] fn getWeatherInfo() const -> WeatherOutput; - [[nodiscard]] fn getLocation() const -> const Location; - [[nodiscard]] fn getApiKey() const -> const std::string; - [[nodiscard]] fn getUnits() const -> const std::string; -}; - -struct WeatherImpl { - Weather::Location location; - std::string api_key; - std::string units; - - static fn from_class(const Weather& weather) noexcept -> WeatherImpl; - - [[nodiscard]] fn to_class() const -> Weather; -}; +// TODO: Make config values optional and supply defaults class General { private: @@ -168,15 +75,6 @@ struct ConfigImpl { // Parsers for Config classes namespace rfl::parsing { - template - struct Parser - : public CustomParser< - ReaderType, - WriterType, - ProcessorsType, - Weather, - WeatherImpl> {}; - template struct Parser : public CustomParser< @@ -203,4 +101,4 @@ namespace rfl::parsing { ProcessorsType, Config, ConfigImpl> {}; -} // namespace rfl::parsing +} diff --git a/src/config/weather.cpp b/src/config/weather.cpp index 27fff94..8b4a03f 100644 --- a/src/config/weather.cpp +++ b/src/config/weather.cpp @@ -2,16 +2,16 @@ #include #include #include -#include -#include "config.h" +#include "weather.h" + +#include "util/result.h" using WeatherOutput = Weather::WeatherOutput; // Function to read cache from file fn ReadCacheFromFile() -> Result { - const std::string cacheFile = "/tmp/weather_cache.json"; - std::ifstream ifs(cacheFile); + std::ifstream ifs("/tmp/weather_cache.json"); if (!ifs.is_open()) return Error("Cache file not found."); @@ -35,9 +35,9 @@ fn ReadCacheFromFile() -> Result { // Function to write cache to file fn WriteCacheToFile(const WeatherOutput& data) -> Result<> { - const std::string cacheFile = "/tmp/weather_cache.json"; fmt::println("Writing to cache file..."); - std::ofstream ofs(cacheFile); + + std::ofstream ofs("/tmp/weather_cache.json"); if (!ofs.is_open()) return Error("Failed to open cache file for writing."); @@ -49,7 +49,8 @@ fn WriteCacheToFile(const WeatherOutput& data) -> Result<> { return Ok(); } -fn WriteCallback(void* contents, size_t size, size_t nmemb, std::string* str) -> size_t { +fn WriteCallback(void* contents, size_t size, size_t nmemb, std::string* str) + -> size_t { size_t totalSize = size * nmemb; str->append(static_cast(contents), totalSize); return totalSize; @@ -59,7 +60,7 @@ fn WriteCallback(void* contents, size_t size, size_t nmemb, std::string* str) -> fn MakeApiRequest(const std::string& url) -> Result { fmt::println("Making API request to URL: {}", url); - CURL* curl = curl_easy_init(); + CURL* curl = curl_easy_init(); std::string responseBuffer; if (curl) { @@ -70,10 +71,14 @@ fn MakeApiRequest(const std::string& url) -> Result { curl_easy_cleanup(curl); if (res != CURLE_OK) { - return Error(fmt::format("Failed to perform cURL request: {}", curl_easy_strerror(res))); + return Error(fmt::format( + "Failed to perform cURL request: {}", curl_easy_strerror(res) + )); } - fmt::println("Received response from API. Response size: {}", responseBuffer.size()); + fmt::println( + "Received response from API. Response size: {}", responseBuffer.size() + ); WeatherOutput output = rfl::json::read(responseBuffer).value(); diff --git a/src/config/weather.h b/src/config/weather.h new file mode 100644 index 0000000..4be9afa --- /dev/null +++ b/src/config/weather.h @@ -0,0 +1,116 @@ +#pragma once + +#include +#include +#include +#include +#include + +#include "util/macros.h" +#include "util/numtypes.h" + +class Weather { + public: + using degrees = rfl::Validator, rfl::Maximum<360>>; + using percentage = rfl::Validator, rfl::Maximum<100>>; + + struct Condition { + std::string description; + std::string icon; + std::string main; + usize id; + }; + + struct Main { + f64 feels_like; + f64 temp; + f64 temp_max; + f64 temp_min; + isize pressure; + percentage humidity; + std::optional grnd_level; + std::optional sea_level; + }; + + struct Wind { + degrees deg; + f64 speed; + std::optional gust; + }; + + struct Precipitation { + rfl::Rename<"1h", f64> one_hour; + rfl::Rename<"3h", f64> three_hours; + }; + + struct Sys { + std::string country; + usize id; + usize sunrise; + usize sunset; + usize type; + }; + + struct Clouds { + percentage all; + }; + + struct Coords { + double lat; + double lon; + }; + + struct WeatherOutput { + Clouds clouds; + isize timezone; + isize visibility; + Main main; + rfl::Rename<"coord", Coords> coords; + std::optional rain; + std::optional snow; + std::string base; + std::string name; + std::vector weather; + Sys sys; + usize cod; + usize dt; + usize id; + Wind wind; + }; + + using Location = std::variant; + + private: + Location m_Location; + std::string m_ApiKey; + std::string m_Units; + + public: + Weather(Location location, std::string api_key, std::string units); + + [[nodiscard]] fn getWeatherInfo() const -> WeatherOutput; + [[nodiscard]] fn getLocation() const -> const Location; + [[nodiscard]] fn getApiKey() const -> const std::string; + [[nodiscard]] fn getUnits() const -> const std::string; +}; + +struct WeatherImpl { + Weather::Location location; + std::string api_key; + std::string units; + + static fn from_class(const Weather& weather) noexcept -> WeatherImpl; + + [[nodiscard]] fn to_class() const -> Weather; +}; + +namespace rfl::parsing { + template + struct Parser + : public CustomParser< + ReaderType, + WriterType, + ProcessorsType, + Weather, + WeatherImpl> {}; +} diff --git a/src/os/macos/bridge.h b/src/os/macos/bridge.h index c151d80..671085e 100644 --- a/src/os/macos/bridge.h +++ b/src/os/macos/bridge.h @@ -9,7 +9,7 @@ + (NSString*)macOSVersion; @end #else -#include "util/numtypes.h" +#include "util/macros.h" extern "C" { fn GetCurrentPlayingTitle() -> const char*; diff --git a/src/os/macos/bridge.mm b/src/os/macos/bridge.mm index 8760aca..61f16f1 100644 --- a/src/os/macos/bridge.mm +++ b/src/os/macos/bridge.mm @@ -80,8 +80,13 @@ using MRMediaRemoteGetNowPlayingInfoFunction = void (*)( } // Dictionary to map macOS versions to their respective names - NSDictionary* versionNames = - @{@11 : @"Big Sur", @12 : @"Monterey", @13 : @"Ventura", @14 : @"Sonoma"}; + NSDictionary* versionNames = @{ + @11 : @"Big Sur", + @12 : @"Monterey", + @13 : @"Ventura", + @14 : @"Sonoma", + @15 : @"Sequoia" + }; NSNumber* majorVersionNumber = @(osVersion.majorVersion); NSString* versionName = versionNames[majorVersionNumber]; @@ -96,7 +101,7 @@ using MRMediaRemoteGetNowPlayingInfoFunction = void (*)( } @end -#include "util/numtypes.h" +#include "util/macros.h" extern "C" { fn GetCurrentPlayingTitle() -> const char* { diff --git a/src/os/os.h b/src/os/os.h index af5d7e8..fac7052 100644 --- a/src/os/os.h +++ b/src/os/os.h @@ -2,8 +2,9 @@ #include +#include "util/macros.h" #include "util/numtypes.h" -u64 GetMemInfo(); -std::string GetNowPlaying(); -const char* GetOSVersion(); +fn GetMemInfo() -> u64; +fn GetNowPlaying() -> std::string; +fn GetOSVersion() -> const char*;