This code is probably terrible but its ok
This commit is contained in:
parent
8db3dae6f1
commit
e8fb8ec19f
|
@ -1,6 +1,4 @@
|
|||
---
|
||||
Language: Cpp
|
||||
BasedOnStyle: Chromium
|
||||
IndentCaseBlocks: true
|
||||
IndentCaseLabels: true
|
||||
|
||||
SpaceBeforeCpp11BracedList: true
|
||||
|
|
3
.clangd
3
.clangd
|
@ -1,2 +1,3 @@
|
|||
CompileFlags:
|
||||
Add: [-std=c++2b]
|
||||
Add: [-std=c++2b, -Wno-unused-function]
|
||||
Remove: -Wc++98-compat
|
||||
|
|
|
@ -1,37 +0,0 @@
|
|||
cmake_minimum_required(VERSION 3.28.1)
|
||||
set(CMAKE_CXX_STANDARD 26)
|
||||
set(CMAKE_EXPORT_COMPILE_COMMANDS 1)
|
||||
set(CMAKE_CXX_SCAN_FOR_MODULES 1)
|
||||
|
||||
project(draconis++)
|
||||
|
||||
set(sources)
|
||||
|
||||
list(APPEND sources src/main.cpp)
|
||||
|
||||
if (${CMAKE_SYSTEM_NAME} MATCHES "Darwin")
|
||||
set(MACOSX TRUE)
|
||||
endif ()
|
||||
|
||||
if (MACOSX)
|
||||
list(APPEND sources src/os/macos.cpp)
|
||||
elseif (LINUX)
|
||||
list(APPEND sources src/os/linux.cpp)
|
||||
endif ()
|
||||
|
||||
add_executable(${PROJECT_NAME})
|
||||
target_sources(${PROJECT_NAME} PUBLIC src/main.cpp)
|
||||
target_sources(${PROJECT_NAME} PUBLIC FILE_SET all_my_modules TYPE CXX_MODULES FILES src/os/linux.cpp)
|
||||
|
||||
find_package(PkgConfig REQUIRED)
|
||||
find_package(cpr REQUIRED)
|
||||
find_package(Boost REQUIRED)
|
||||
|
||||
if (MACOSX)
|
||||
pkg_check_modules(${PROJECT_NAME} REQUIRED IMPORTED_TARGET fmt tomlplusplus)
|
||||
else ()
|
||||
pkg_check_modules(${PROJECT_NAME} REQUIRED IMPORTED_TARGET fmt playerctl tomlplusplus)
|
||||
endif ()
|
||||
|
||||
target_link_libraries(${PROJECT_NAME} PRIVATE PkgConfig::${PROJECT_NAME} cpr::cpr Boost::boost)
|
||||
|
|
@ -2,11 +2,11 @@
|
|||
"nodes": {
|
||||
"nixpkgs": {
|
||||
"locked": {
|
||||
"lastModified": 1716715802,
|
||||
"narHash": "sha256-usk0vE7VlxPX8jOavrtpOqphdfqEQpf9lgedlY/r66c=",
|
||||
"lastModified": 1717112898,
|
||||
"narHash": "sha256-7R2ZvOnvd9h8fDd65p0JnB7wXfUvreox3xFdYWd1BnY=",
|
||||
"owner": "NixOS",
|
||||
"repo": "nixpkgs",
|
||||
"rev": "e2dd4e18cc1c7314e24154331bae07df76eb582f",
|
||||
"rev": "6132b0f6e344ce2fe34fc051b72fb46e34f668e0",
|
||||
"type": "github"
|
||||
},
|
||||
"original": {
|
||||
|
|
112
flake.nix
112
flake.nix
|
@ -16,6 +16,7 @@
|
|||
system: let
|
||||
pkgs = import nixpkgs {
|
||||
inherit system;
|
||||
|
||||
overlays = [
|
||||
(self: super: {
|
||||
ccacheWrapper = super.ccacheWrapper.override {
|
||||
|
@ -45,111 +46,80 @@
|
|||
];
|
||||
};
|
||||
|
||||
llvm = pkgs.llvmPackages_latest;
|
||||
|
||||
stdenv = pkgs.ccacheStdenv.override {
|
||||
stdenv =
|
||||
if pkgs.hostPlatform.isDarwin
|
||||
then llvm.libcxxStdenv
|
||||
else pkgs.stdenvAdapters.useMoldLinker pkgs.clangStdenv;
|
||||
};
|
||||
|
||||
darwinPkgs = nixpkgs.lib.optionals pkgs.stdenv.isDarwin (with pkgs.darwin; [
|
||||
apple_sdk.frameworks.AppKit
|
||||
apple_sdk.frameworks.Carbon
|
||||
apple_sdk.frameworks.Cocoa
|
||||
apple_sdk.frameworks.CoreFoundation
|
||||
apple_sdk.frameworks.IOKit
|
||||
apple_sdk.frameworks.WebKit
|
||||
apple_sdk.frameworks.Security
|
||||
apple_sdk.frameworks.DisplayServices
|
||||
]);
|
||||
in {
|
||||
packages = rec {
|
||||
draconis-cpp = with pkgs;
|
||||
stdenv.mkDerivation {
|
||||
stdenv = pkgs.llvmPackages_18.stdenv;
|
||||
in
|
||||
with pkgs; {
|
||||
packages = rec {
|
||||
draconis-cpp = stdenv.mkDerivation {
|
||||
name = "draconis++";
|
||||
version = "0.1.0";
|
||||
src = self;
|
||||
|
||||
nativeBuildInputs = [
|
||||
cmake
|
||||
meson
|
||||
ninja
|
||||
pkg-config
|
||||
];
|
||||
|
||||
propagatedBuildInputs =
|
||||
[
|
||||
boost185
|
||||
glib
|
||||
]
|
||||
++ (
|
||||
if pkgs.hostPlatform.isLinux
|
||||
then [playerctl]
|
||||
else []
|
||||
);
|
||||
|
||||
buildInputs =
|
||||
[
|
||||
fmt
|
||||
libcpr
|
||||
tomlplusplus
|
||||
]
|
||||
++ darwinPkgs;
|
||||
++ (lib.optionals pkgs.hostPlatform.isLinux [
|
||||
glib
|
||||
playerctl
|
||||
]);
|
||||
|
||||
buildInputs = [
|
||||
boost185
|
||||
fmt
|
||||
];
|
||||
|
||||
configurePhase = ''
|
||||
meson setup build
|
||||
'';
|
||||
|
||||
buildPhase = ''
|
||||
cmake -GNinja .
|
||||
ninja
|
||||
meson compile -C build
|
||||
'';
|
||||
|
||||
installPhase = ''
|
||||
install -Dm755 ./draconis++ $out/bin/draconis++
|
||||
mkdir -p $out/bin
|
||||
mv build/draconis++ $out/bin/draconis++
|
||||
'';
|
||||
};
|
||||
|
||||
default = draconis-cpp;
|
||||
};
|
||||
default = draconis-cpp;
|
||||
};
|
||||
|
||||
devShell = with pkgs;
|
||||
mkShell.override {inherit stdenv;} {
|
||||
packages = with pkgs;
|
||||
formatter = alejandra;
|
||||
|
||||
devShell = mkShell.override {inherit stdenv;} {
|
||||
packages =
|
||||
[
|
||||
# builder
|
||||
cmake
|
||||
alejandra
|
||||
bear
|
||||
clang-tools
|
||||
meson
|
||||
ninja
|
||||
pkg-config
|
||||
|
||||
# debugger
|
||||
lldb
|
||||
|
||||
# fix headers not found
|
||||
clang-tools_18
|
||||
|
||||
# LSP and compiler
|
||||
llvm.libstdcxxClang
|
||||
|
||||
# other tools
|
||||
cppcheck
|
||||
llvm.libllvm
|
||||
|
||||
# stdlib for cpp
|
||||
llvm.libcxx
|
||||
|
||||
# libraries
|
||||
boost185
|
||||
fmt
|
||||
glib
|
||||
libcpr
|
||||
tomlplusplus
|
||||
]
|
||||
++ (
|
||||
if stdenv.isDarwin
|
||||
then []
|
||||
else [playerctl]
|
||||
)
|
||||
++ darwinPkgs;
|
||||
++ (lib.optionals pkgs.hostPlatform.isLinux [playerctl]);
|
||||
|
||||
buildInputs = [
|
||||
libcpr
|
||||
tomlplusplus
|
||||
];
|
||||
|
||||
name = "C++";
|
||||
};
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
|
|
59
meson.build
Normal file
59
meson.build
Normal file
|
@ -0,0 +1,59 @@
|
|||
project(
|
||||
'draconis++', 'cpp',
|
||||
default_options: [
|
||||
'cpp_std=c++26',
|
||||
'default_library=static',
|
||||
'buildtype=debugoptimized',
|
||||
'warning_level=everything',
|
||||
]
|
||||
)
|
||||
|
||||
cc = meson.get_compiler('cpp')
|
||||
|
||||
add_project_arguments(
|
||||
cc.get_supported_arguments([
|
||||
'-Wno-c++98-compat',
|
||||
'-Wno-c++98-compat-pedantic',
|
||||
'-Wno-padded',
|
||||
'-Wno-pre-c++20-compat-pedantic',
|
||||
'-Wno-switch-default',
|
||||
'-Wno-missing-prototypes'
|
||||
]),
|
||||
language: 'cpp'
|
||||
)
|
||||
|
||||
source_file_names = ['src/main.cpp', 'src/os/os.h']
|
||||
|
||||
if host_machine.system() == 'linux'
|
||||
source_file_names += ['src/os/linux.cpp']
|
||||
endif
|
||||
|
||||
if host_machine.system() == 'darwin'
|
||||
source_file_names += ['src/os/macos.cpp']
|
||||
endif
|
||||
|
||||
sources = []
|
||||
|
||||
foreach file : source_file_names
|
||||
sources += files(file)
|
||||
endforeach
|
||||
|
||||
boost_dep = dependency('boost')
|
||||
cpr_dep = cc.find_library('cpr')
|
||||
curl_dep = cc.find_library('curl')
|
||||
fmt_dep = dependency('fmt')
|
||||
tomlplusplus_dep = cc.find_library('tomlplusplus')
|
||||
playerctl_dep = dependency('playerctl')
|
||||
|
||||
executable(
|
||||
'draconis++',
|
||||
sources,
|
||||
dependencies: [
|
||||
boost_dep,
|
||||
cpr_dep,
|
||||
curl_dep,
|
||||
fmt_dep,
|
||||
tomlplusplus_dep,
|
||||
playerctl_dep
|
||||
]
|
||||
)
|
159
src/main.cpp
159
src/main.cpp
|
@ -4,9 +4,9 @@
|
|||
#include <fmt/core.h>
|
||||
#include <fmt/format.h>
|
||||
#include <boost/json/src.hpp>
|
||||
#include <ctime>
|
||||
#include <toml++/toml.hpp>
|
||||
|
||||
import OS;
|
||||
#include "os/os.h"
|
||||
|
||||
using std::string;
|
||||
|
||||
|
@ -24,35 +24,41 @@ struct LatLon {
|
|||
};
|
||||
|
||||
struct Location {
|
||||
enum { coords, city } type;
|
||||
enum {
|
||||
coords,
|
||||
city,
|
||||
} type;
|
||||
|
||||
union {
|
||||
LatLon coords;
|
||||
const char* city;
|
||||
LatLon coords;
|
||||
} data;
|
||||
};
|
||||
|
||||
void use_location(const Location& l) {
|
||||
switch (l.type) {
|
||||
case Location::city:
|
||||
{
|
||||
char* c = const_cast<char*>(l.data.city);
|
||||
puts(c);
|
||||
free(c);
|
||||
break;
|
||||
}
|
||||
case Location::coords:
|
||||
{
|
||||
const auto [lat, lon] = l.data.coords;
|
||||
printf("%.f, %.f", lon, lat);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct Weather {
|
||||
Location location;
|
||||
string api_key;
|
||||
string units;
|
||||
|
||||
Weather() = default;
|
||||
|
||||
Weather(const char* _city, string _api_key, string _units) {
|
||||
this->api_key = _api_key;
|
||||
this->units = _units;
|
||||
this->location = Location {
|
||||
Location::city,
|
||||
{.city = _city},
|
||||
};
|
||||
}
|
||||
|
||||
Weather(LatLon _coords, string _api_key, string _units) {
|
||||
this->api_key = _api_key;
|
||||
this->units = _units;
|
||||
this->location = Location {
|
||||
Location::coords,
|
||||
{.coords = _coords},
|
||||
};
|
||||
}
|
||||
};
|
||||
|
||||
struct Config {
|
||||
|
@ -60,44 +66,28 @@ struct Config {
|
|||
NowPlaying now_playing;
|
||||
Weather weather;
|
||||
|
||||
explicit Config(auto toml) {
|
||||
general = General{.name = toml["general"]["name"].value_or(getlogin())};
|
||||
Config(toml::table toml) {
|
||||
general = General {toml["general"]["name"].value_or(getlogin())};
|
||||
|
||||
now_playing =
|
||||
NowPlaying{.enable = toml["now_playing"]["enable"].value_or(false)};
|
||||
now_playing = NowPlaying {toml["now_playing"]["enable"].value_or(false)};
|
||||
|
||||
const char* location = toml["weather"]["location"].value_or("");
|
||||
const auto location = toml["weather"]["location"];
|
||||
const string api_key = toml["weather"]["api_key"].value_or("");
|
||||
const string units = toml["weather"]["units"].value_or("metric");
|
||||
|
||||
const size_t len = strlen(location);
|
||||
char* loc = new char[len + 1];
|
||||
strncpy(loc, location, len);
|
||||
loc[len] = '\0';
|
||||
|
||||
if (toml["weather"]["location"].is_string()) {
|
||||
weather = Weather{
|
||||
.location = Location{.type = Location::city, .data = {.city = loc}},
|
||||
.api_key = toml["weather"]["api_key"].value_or(""),
|
||||
.units = toml["weather"]["units"].value_or("metric"),
|
||||
};
|
||||
} else {
|
||||
weather = Weather{
|
||||
.location =
|
||||
Location{
|
||||
.type = Location::coords,
|
||||
.data = {.coords =
|
||||
LatLon{
|
||||
toml["weather"]["location"]["lat"].value_or(
|
||||
0.0),
|
||||
toml["weather"]["location"]["lon"].value_or(
|
||||
0.0)}}},
|
||||
.api_key = toml["weather"]["api_key"].value_or(""),
|
||||
.units = toml["weather"]["units"].value_or("metric"),
|
||||
};
|
||||
}
|
||||
if (location.is_string())
|
||||
weather = Weather(location.value_or(""), api_key, units);
|
||||
else
|
||||
weather = Weather(
|
||||
LatLon {location["lat"].value_or(0.0), location["lon"].value_or(0.0)},
|
||||
api_key, units);
|
||||
}
|
||||
};
|
||||
|
||||
static Config CONFIG = Config(toml::parse_file("./config.toml"));
|
||||
static const Config& CONFIG() {
|
||||
static const Config& CONFIG = *new Config(toml::parse_file("./config.toml"));
|
||||
return CONFIG;
|
||||
}
|
||||
|
||||
struct BytesToGiB {
|
||||
uint64_t value;
|
||||
|
@ -108,7 +98,7 @@ struct fmt::formatter<BytesToGiB> : formatter<double> {
|
|||
template <typename FormatContext>
|
||||
auto format(const BytesToGiB b, FormatContext& ctx) {
|
||||
auto out = formatter<double>::format(
|
||||
b.value / pow(1024, 3), ctx); // NOLINT(*-narrowing-conversions);
|
||||
static_cast<double>(b.value) / pow(1024, 3), ctx);
|
||||
*out++ = 'G';
|
||||
*out++ = 'i';
|
||||
*out++ = 'B';
|
||||
|
@ -136,30 +126,30 @@ boost::json::object get_weather() {
|
|||
using namespace boost::json;
|
||||
using namespace fmt;
|
||||
|
||||
if (CONFIG.weather.location.type == Location::city) {
|
||||
const char* location =
|
||||
curl_easy_escape(nullptr, CONFIG.weather.location.data.city,
|
||||
strlen(CONFIG.weather.location.data.city));
|
||||
const char* api_key = CONFIG.weather.api_key.c_str();
|
||||
const char* units = CONFIG.weather.units.c_str();
|
||||
if (CONFIG().weather.location.type == Location::city) {
|
||||
const char* location = curl_easy_escape(
|
||||
nullptr, CONFIG().weather.location.data.city,
|
||||
static_cast<int>(strlen(CONFIG().weather.location.data.city)));
|
||||
const char* api_key = CONFIG().weather.api_key.c_str();
|
||||
const char* units = CONFIG().weather.units.c_str();
|
||||
|
||||
const Response r =
|
||||
Get(Url{format("https://api.openweathermap.org/data/2.5/"
|
||||
"weather?q={}&appid={}&units={}",
|
||||
location, api_key, units)});
|
||||
Get(Url {format("https://api.openweathermap.org/data/2.5/"
|
||||
"weather?q={}&appid={}&units={}",
|
||||
location, api_key, units)});
|
||||
|
||||
value json = parse(r.text);
|
||||
|
||||
return json.as_object();
|
||||
} else {
|
||||
const auto [lat, lon] = CONFIG.weather.location.data.coords;
|
||||
const char* api_key = CONFIG.weather.api_key.c_str();
|
||||
const char* units = CONFIG.weather.units.c_str();
|
||||
const auto [lat, lon] = CONFIG().weather.location.data.coords;
|
||||
const char* api_key = CONFIG().weather.api_key.c_str();
|
||||
const char* units = CONFIG().weather.units.c_str();
|
||||
|
||||
const Response r =
|
||||
Get(Url{format("https://api.openweathermap.org/data/2.5/"
|
||||
"weather?lat={}&lon={}&appid={}&units={}",
|
||||
lat, lon, api_key, units)});
|
||||
Get(Url {format("https://api.openweathermap.org/data/2.5/"
|
||||
"weather?lat={}&lon={}&appid={}&units={}",
|
||||
lat, lon, api_key, units)});
|
||||
|
||||
value json = parse(r.text);
|
||||
|
||||
|
@ -168,20 +158,28 @@ boost::json::object get_weather() {
|
|||
}
|
||||
|
||||
int main() {
|
||||
const auto toml = toml::parse_file("./config.toml");
|
||||
using boost::json::object;
|
||||
using fmt::format;
|
||||
using fmt::localtime;
|
||||
using fmt::println;
|
||||
using std::time;
|
||||
using std::time_t;
|
||||
using toml::parse_result;
|
||||
|
||||
if (CONFIG.now_playing.enable)
|
||||
fmt::println("{}", get_nowplaying());
|
||||
const parse_result toml = toml::parse_file("./config.toml");
|
||||
|
||||
fmt::println("Hello {}!", CONFIG.general.name);
|
||||
if (CONFIG().now_playing.enable)
|
||||
println("{}", get_nowplaying());
|
||||
|
||||
println("Hello {}!", CONFIG().general.name);
|
||||
|
||||
const uint64_t meminfo = get_meminfo();
|
||||
|
||||
fmt::println("{:.2f}", BytesToGiB{meminfo});
|
||||
println("{:.2f}", BytesToGiB {meminfo});
|
||||
|
||||
const std::time_t t = std::time(nullptr);
|
||||
const time_t t = time(nullptr);
|
||||
|
||||
string date = fmt::format("{:%d}", fmt::localtime(t));
|
||||
string date = format("{:%d}", localtime(t));
|
||||
|
||||
switch (parse_date(date)) {
|
||||
case Ones:
|
||||
|
@ -201,15 +199,14 @@ int main() {
|
|||
break;
|
||||
}
|
||||
|
||||
fmt::println("{:%B} {}, {:%-I:%0M %p}", fmt::localtime(t), date,
|
||||
fmt::localtime(t));
|
||||
println("{:%B} {}, {:%-I:%0M %p}", localtime(t), date, localtime(t));
|
||||
|
||||
boost::json::object json = get_weather();
|
||||
object json = get_weather();
|
||||
|
||||
const char* town_name =
|
||||
json["name"].is_string() ? json["name"].as_string().c_str() : "Unknown";
|
||||
|
||||
fmt::println("{}", town_name);
|
||||
println("{}", town_name);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -1,11 +1,7 @@
|
|||
module;
|
||||
|
||||
#include <fmt/core.h>
|
||||
#include <playerctl/playerctl.h>
|
||||
#include <fstream>
|
||||
|
||||
export module OS;
|
||||
|
||||
using std::string;
|
||||
|
||||
uint64_t parse_line_as_number(const string& input) {
|
||||
|
@ -13,15 +9,13 @@ uint64_t parse_line_as_number(const string& input) {
|
|||
string::size_type start = 0;
|
||||
|
||||
// Skip leading non-numbers
|
||||
while (!isdigit(input[++start]))
|
||||
;
|
||||
while (!isdigit(input[++start]));
|
||||
|
||||
// Start searching from the start of the number
|
||||
string::size_type end = start;
|
||||
|
||||
// Increment to the end of the number
|
||||
while (isdigit(input[++end]))
|
||||
;
|
||||
while (isdigit(input[++end]));
|
||||
|
||||
// Return the substring containing the number
|
||||
return std::stoul(input.substr(start, end - start));
|
||||
|
@ -31,16 +25,15 @@ uint64_t meminfo_parse(std::ifstream is) {
|
|||
string line;
|
||||
|
||||
// Skip every line before the one that starts with "MemTotal"
|
||||
while (std::getline(is, line) && !line.starts_with("MemTotal"))
|
||||
;
|
||||
while (std::getline(is, line) && !line.starts_with("MemTotal"));
|
||||
|
||||
// Parse the number from the line
|
||||
const auto num = parse_line_as_number(line);
|
||||
const uint64_t num = parse_line_as_number(line);
|
||||
|
||||
return num;
|
||||
}
|
||||
|
||||
export uint64_t get_meminfo() {
|
||||
uint64_t get_meminfo() {
|
||||
return meminfo_parse(std::ifstream("/proc/meminfo")) * 1024;
|
||||
}
|
||||
|
||||
|
@ -60,7 +53,7 @@ PlayerctlPlayer* init_playerctl() {
|
|||
return nullptr;
|
||||
|
||||
// Get the first player
|
||||
const auto player_name =
|
||||
PlayerctlPlayerName* player_name =
|
||||
static_cast<PlayerctlPlayerName*>(available_players->data);
|
||||
|
||||
// Create the player
|
||||
|
@ -80,10 +73,8 @@ PlayerctlPlayer* init_playerctl() {
|
|||
return current_player;
|
||||
}
|
||||
|
||||
export string get_nowplaying() {
|
||||
if (PlayerctlPlayer* current_player = init_playerctl()) {
|
||||
string get_nowplaying() {
|
||||
if (PlayerctlPlayer* current_player = init_playerctl())
|
||||
return playerctl_player_get_title(current_player, nullptr);
|
||||
}
|
||||
|
||||
return "Could not get now playing info";
|
||||
}
|
||||
|
|
|
@ -1,10 +1,8 @@
|
|||
module;
|
||||
|
||||
#include <sys/sysctl.h>
|
||||
#include <unistd.h>
|
||||
#include <string>
|
||||
|
||||
export module OS;
|
||||
|
||||
export uint64_t get_meminfo() {
|
||||
uint64_t get_meminfo() {
|
||||
uint64_t mem = 0;
|
||||
size_t size = sizeof(mem);
|
||||
|
||||
|
@ -13,6 +11,6 @@ export uint64_t get_meminfo() {
|
|||
return mem;
|
||||
}
|
||||
|
||||
export string get_nowplaying() {
|
||||
static std::string get_nowplaying() {
|
||||
return "";
|
||||
}
|
||||
|
|
5
src/os/os.h
Normal file
5
src/os/os.h
Normal file
|
@ -0,0 +1,5 @@
|
|||
#include <cstdint>
|
||||
#include <string>
|
||||
|
||||
uint64_t get_meminfo();
|
||||
std::string get_nowplaying();
|
Loading…
Reference in a new issue