i think? this is better??
This commit is contained in:
parent
b3e79b56f7
commit
c3b829b68f
11 changed files with 413 additions and 678 deletions
|
@ -20,48 +20,6 @@
|
||||||
},
|
},
|
||||||
"version": "11.1.4"
|
"version": "11.1.4"
|
||||||
},
|
},
|
||||||
"reflect-cpp": {
|
|
||||||
"cargoLocks": null,
|
|
||||||
"date": "2025-03-02",
|
|
||||||
"extract": null,
|
|
||||||
"name": "reflect-cpp",
|
|
||||||
"passthru": null,
|
|
||||||
"pinned": false,
|
|
||||||
"src": {
|
|
||||||
"deepClone": false,
|
|
||||||
"fetchSubmodules": false,
|
|
||||||
"leaveDotGit": false,
|
|
||||||
"name": null,
|
|
||||||
"owner": "getml",
|
|
||||||
"repo": "reflect-cpp",
|
|
||||||
"rev": "ec8c19fa3e931d736b3f3ff2e400fce4a5f97829",
|
|
||||||
"sha256": "sha256-3bbaVbU9ICQ8no/3W4M8ePsnrZR3e3CWhT3RO3lL3r0=",
|
|
||||||
"sparseCheckout": [],
|
|
||||||
"type": "github"
|
|
||||||
},
|
|
||||||
"version": "ec8c19fa3e931d736b3f3ff2e400fce4a5f97829"
|
|
||||||
},
|
|
||||||
"sdbus-cpp": {
|
|
||||||
"cargoLocks": null,
|
|
||||||
"date": null,
|
|
||||||
"extract": null,
|
|
||||||
"name": "sdbus-cpp",
|
|
||||||
"passthru": null,
|
|
||||||
"pinned": false,
|
|
||||||
"src": {
|
|
||||||
"deepClone": false,
|
|
||||||
"fetchSubmodules": false,
|
|
||||||
"leaveDotGit": false,
|
|
||||||
"name": null,
|
|
||||||
"owner": "kistler-group",
|
|
||||||
"repo": "sdbus-cpp",
|
|
||||||
"rev": "v2.1.0",
|
|
||||||
"sha256": "sha256-JnjabBr7oELLsUV9a+dAAaRyUzaMIriu90vkaVJg2eY=",
|
|
||||||
"sparseCheckout": [],
|
|
||||||
"type": "github"
|
|
||||||
},
|
|
||||||
"version": "v2.1.0"
|
|
||||||
},
|
|
||||||
"tomlplusplus": {
|
"tomlplusplus": {
|
||||||
"cargoLocks": null,
|
"cargoLocks": null,
|
||||||
"date": null,
|
"date": null,
|
||||||
|
@ -82,26 +40,5 @@
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"version": "v3.4.0"
|
"version": "v3.4.0"
|
||||||
},
|
|
||||||
"yyjson": {
|
|
||||||
"cargoLocks": null,
|
|
||||||
"date": null,
|
|
||||||
"extract": null,
|
|
||||||
"name": "yyjson",
|
|
||||||
"passthru": null,
|
|
||||||
"pinned": false,
|
|
||||||
"src": {
|
|
||||||
"deepClone": false,
|
|
||||||
"fetchSubmodules": false,
|
|
||||||
"leaveDotGit": false,
|
|
||||||
"name": null,
|
|
||||||
"owner": "ibireme",
|
|
||||||
"repo": "yyjson",
|
|
||||||
"rev": "0.10.0",
|
|
||||||
"sha256": "sha256-mp9Oz08qTyhj3P6F1d81SX96vamUY/JWpD2DTYR+v04=",
|
|
||||||
"sparseCheckout": [],
|
|
||||||
"type": "github"
|
|
||||||
},
|
|
||||||
"version": "0.10.0"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -12,29 +12,6 @@
|
||||||
sha256 = "sha256-sUbxlYi/Aupaox3JjWFqXIjcaQa0LFjclQAOleT+FRA=";
|
sha256 = "sha256-sUbxlYi/Aupaox3JjWFqXIjcaQa0LFjclQAOleT+FRA=";
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
reflect-cpp = {
|
|
||||||
pname = "reflect-cpp";
|
|
||||||
version = "ec8c19fa3e931d736b3f3ff2e400fce4a5f97829";
|
|
||||||
src = fetchFromGitHub {
|
|
||||||
owner = "getml";
|
|
||||||
repo = "reflect-cpp";
|
|
||||||
rev = "ec8c19fa3e931d736b3f3ff2e400fce4a5f97829";
|
|
||||||
fetchSubmodules = false;
|
|
||||||
sha256 = "sha256-3bbaVbU9ICQ8no/3W4M8ePsnrZR3e3CWhT3RO3lL3r0=";
|
|
||||||
};
|
|
||||||
date = "2025-03-02";
|
|
||||||
};
|
|
||||||
sdbus-cpp = {
|
|
||||||
pname = "sdbus-cpp";
|
|
||||||
version = "v2.1.0";
|
|
||||||
src = fetchFromGitHub {
|
|
||||||
owner = "kistler-group";
|
|
||||||
repo = "sdbus-cpp";
|
|
||||||
rev = "v2.1.0";
|
|
||||||
fetchSubmodules = false;
|
|
||||||
sha256 = "sha256-JnjabBr7oELLsUV9a+dAAaRyUzaMIriu90vkaVJg2eY=";
|
|
||||||
};
|
|
||||||
};
|
|
||||||
tomlplusplus = {
|
tomlplusplus = {
|
||||||
pname = "tomlplusplus";
|
pname = "tomlplusplus";
|
||||||
version = "v3.4.0";
|
version = "v3.4.0";
|
||||||
|
@ -46,15 +23,4 @@
|
||||||
sha256 = "sha256-h5tbO0Rv2tZezY58yUbyRVpsfRjY3i+5TPkkxr6La8M=";
|
sha256 = "sha256-h5tbO0Rv2tZezY58yUbyRVpsfRjY3i+5TPkkxr6La8M=";
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
yyjson = {
|
|
||||||
pname = "yyjson";
|
|
||||||
version = "0.10.0";
|
|
||||||
src = fetchFromGitHub {
|
|
||||||
owner = "ibireme";
|
|
||||||
repo = "yyjson";
|
|
||||||
rev = "0.10.0";
|
|
||||||
fetchSubmodules = false;
|
|
||||||
sha256 = "sha256-mp9Oz08qTyhj3P6F1d81SX96vamUY/JWpD2DTYR+v04=";
|
|
||||||
};
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
192
flake.lock
generated
192
flake.lock
generated
|
@ -1,96 +1,96 @@
|
||||||
{
|
{
|
||||||
"nodes": {
|
"nodes": {
|
||||||
"nixpkgs": {
|
"nixpkgs": {
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1739863612,
|
"lastModified": 1741678040,
|
||||||
"narHash": "sha256-UbtgxplOhFcyjBcNbTVO8+HUHAl/WXFDOb6LvqShiZo=",
|
"narHash": "sha256-rmBsz7BBcDwfvDkxnKHmolKceGJrr0nyz5PQYZg0kMk=",
|
||||||
"owner": "NixOS",
|
"owner": "NixOS",
|
||||||
"repo": "nixpkgs",
|
"repo": "nixpkgs",
|
||||||
"rev": "632f04521e847173c54fa72973ec6c39a371211c",
|
"rev": "3ee8818da146871cd570b164fc4f438f78479a50",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
"owner": "NixOS",
|
"owner": "NixOS",
|
||||||
"ref": "nixpkgs-unstable",
|
"ref": "nixpkgs-unstable",
|
||||||
"repo": "nixpkgs",
|
"repo": "nixpkgs",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"nixpkgs_2": {
|
"nixpkgs_2": {
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1735554305,
|
"lastModified": 1735554305,
|
||||||
"narHash": "sha256-zExSA1i/b+1NMRhGGLtNfFGXgLtgo+dcuzHzaWA6w3Q=",
|
"narHash": "sha256-zExSA1i/b+1NMRhGGLtNfFGXgLtgo+dcuzHzaWA6w3Q=",
|
||||||
"owner": "nixos",
|
"owner": "nixos",
|
||||||
"repo": "nixpkgs",
|
"repo": "nixpkgs",
|
||||||
"rev": "0e82ab234249d8eee3e8c91437802b32c74bb3fd",
|
"rev": "0e82ab234249d8eee3e8c91437802b32c74bb3fd",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
"owner": "nixos",
|
"owner": "nixos",
|
||||||
"ref": "nixpkgs-unstable",
|
"ref": "nixpkgs-unstable",
|
||||||
"repo": "nixpkgs",
|
"repo": "nixpkgs",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"root": {
|
"root": {
|
||||||
"inputs": {
|
"inputs": {
|
||||||
"nixpkgs": "nixpkgs",
|
"nixpkgs": "nixpkgs",
|
||||||
"treefmt-nix": "treefmt-nix",
|
"treefmt-nix": "treefmt-nix",
|
||||||
"utils": "utils"
|
"utils": "utils"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"systems": {
|
"systems": {
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1681028828,
|
"lastModified": 1681028828,
|
||||||
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
|
"narHash": "sha256-Vy1rq5AaRuLzOxct8nz4T6wlgyUR7zLU309k9mBC768=",
|
||||||
"owner": "nix-systems",
|
"owner": "nix-systems",
|
||||||
"repo": "default",
|
"repo": "default",
|
||||||
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
|
"rev": "da67096a3b9bf56a91d16901293e51ba5b49a27e",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
"owner": "nix-systems",
|
"owner": "nix-systems",
|
||||||
"repo": "default",
|
"repo": "default",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"treefmt-nix": {
|
"treefmt-nix": {
|
||||||
"inputs": {
|
"inputs": {
|
||||||
"nixpkgs": "nixpkgs_2"
|
"nixpkgs": "nixpkgs_2"
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1739829690,
|
"lastModified": 1739829690,
|
||||||
"narHash": "sha256-mL1szCeIsjh6Khn3nH2cYtwO5YXG6gBiTw1A30iGeDU=",
|
"narHash": "sha256-mL1szCeIsjh6Khn3nH2cYtwO5YXG6gBiTw1A30iGeDU=",
|
||||||
"owner": "numtide",
|
"owner": "numtide",
|
||||||
"repo": "treefmt-nix",
|
"repo": "treefmt-nix",
|
||||||
"rev": "3d0579f5cc93436052d94b73925b48973a104204",
|
"rev": "3d0579f5cc93436052d94b73925b48973a104204",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
"owner": "numtide",
|
"owner": "numtide",
|
||||||
"repo": "treefmt-nix",
|
"repo": "treefmt-nix",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"utils": {
|
"utils": {
|
||||||
"inputs": {
|
"inputs": {
|
||||||
"systems": "systems"
|
"systems": "systems"
|
||||||
},
|
},
|
||||||
"locked": {
|
"locked": {
|
||||||
"lastModified": 1731533236,
|
"lastModified": 1731533236,
|
||||||
"narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=",
|
"narHash": "sha256-l0KFg5HjrsfsO/JpG+r7fRrqm12kzFHyUHqHCVpMMbI=",
|
||||||
"owner": "numtide",
|
"owner": "numtide",
|
||||||
"repo": "flake-utils",
|
"repo": "flake-utils",
|
||||||
"rev": "11707dc2f618dd54ca8739b309ec4fc024de578b",
|
"rev": "11707dc2f618dd54ca8739b309ec4fc024de578b",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
},
|
},
|
||||||
"original": {
|
"original": {
|
||||||
"owner": "numtide",
|
"owner": "numtide",
|
||||||
"repo": "flake-utils",
|
"repo": "flake-utils",
|
||||||
"type": "github"
|
"type": "github"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"root": "root",
|
"root": "root",
|
||||||
"version": 7
|
"version": 7
|
||||||
}
|
}
|
||||||
|
|
286
flake.nix
286
flake.nix
|
@ -1,143 +1,143 @@
|
||||||
{
|
{
|
||||||
description = "C/C++ environment";
|
description = "C/C++ environment";
|
||||||
|
|
||||||
inputs = {
|
inputs = {
|
||||||
nixpkgs.url = "github:NixOS/nixpkgs/nixpkgs-unstable";
|
nixpkgs.url = "github:NixOS/nixpkgs/nixpkgs-unstable";
|
||||||
treefmt-nix.url = "github:numtide/treefmt-nix";
|
treefmt-nix.url = "github:numtide/treefmt-nix";
|
||||||
utils.url = "github:numtide/flake-utils";
|
utils.url = "github:numtide/flake-utils";
|
||||||
};
|
};
|
||||||
|
|
||||||
outputs = {
|
outputs = {
|
||||||
self,
|
self,
|
||||||
nixpkgs,
|
nixpkgs,
|
||||||
treefmt-nix,
|
treefmt-nix,
|
||||||
utils,
|
utils,
|
||||||
...
|
...
|
||||||
}:
|
}:
|
||||||
utils.lib.eachDefaultSystem (
|
utils.lib.eachDefaultSystem (
|
||||||
system: let
|
system: let
|
||||||
pkgs = import nixpkgs {inherit system;};
|
pkgs = import nixpkgs {inherit system;};
|
||||||
|
|
||||||
llvmPackages = with pkgs;
|
llvmPackages = with pkgs;
|
||||||
if hostPlatform.isLinux
|
if hostPlatform.isLinux
|
||||||
then llvmPackages_20
|
then llvmPackages_20
|
||||||
else llvmPackages_19;
|
else llvmPackages_19;
|
||||||
|
|
||||||
stdenv = with pkgs;
|
stdenv = with pkgs;
|
||||||
(
|
(
|
||||||
if hostPlatform.isLinux
|
if hostPlatform.isLinux
|
||||||
then stdenvAdapters.useMoldLinker
|
then stdenvAdapters.useMoldLinker
|
||||||
else lib.id
|
else lib.id
|
||||||
)
|
)
|
||||||
llvmPackages.stdenv;
|
llvmPackages.stdenv;
|
||||||
|
|
||||||
sources = import ./_sources/generated.nix {
|
sources = import ./_sources/generated.nix {
|
||||||
inherit (pkgs) fetchFromGitHub fetchgit fetchurl dockerTools;
|
inherit (pkgs) fetchFromGitHub fetchgit fetchurl dockerTools;
|
||||||
};
|
};
|
||||||
|
|
||||||
fmt = pkgs.pkgsStatic.fmt.overrideAttrs (old: {
|
fmt = pkgs.pkgsStatic.fmt.overrideAttrs (old: {
|
||||||
inherit (sources.fmt) pname version src;
|
inherit (sources.fmt) pname version src;
|
||||||
});
|
});
|
||||||
|
|
||||||
tomlplusplus = pkgs.pkgsStatic.tomlplusplus.overrideAttrs {
|
tomlplusplus = pkgs.pkgsStatic.tomlplusplus.overrideAttrs {
|
||||||
inherit (sources.tomlplusplus) pname version src;
|
inherit (sources.tomlplusplus) pname version src;
|
||||||
doCheck = false;
|
doCheck = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
deps = with pkgs.pkgsStatic;
|
deps = with pkgs.pkgsStatic;
|
||||||
[
|
[
|
||||||
curl
|
curl
|
||||||
fmt
|
fmt
|
||||||
libiconv
|
ftxui
|
||||||
tomlplusplus
|
libiconv
|
||||||
nlohmann_json
|
sqlitecpp
|
||||||
sqlitecpp
|
tomlplusplus
|
||||||
ftxui
|
]
|
||||||
]
|
++ linuxPkgs;
|
||||||
++ linuxPkgs;
|
|
||||||
|
linuxPkgs = nixpkgs.lib.optionals stdenv.isLinux (with pkgs;
|
||||||
linuxPkgs = nixpkgs.lib.optionals stdenv.isLinux (with pkgs;
|
[
|
||||||
[
|
valgrind
|
||||||
valgrind
|
(glaze.override {enableAvx2 = true;})
|
||||||
]
|
]
|
||||||
++ (with pkgsStatic; [
|
++ (with pkgsStatic; [
|
||||||
dbus
|
dbus
|
||||||
xorg.libX11
|
xorg.libX11
|
||||||
wayland
|
wayland
|
||||||
]));
|
]));
|
||||||
in
|
in
|
||||||
with pkgs; {
|
with pkgs; {
|
||||||
packages = rec {
|
packages = rec {
|
||||||
draconisplusplus = stdenv.mkDerivation {
|
draconisplusplus = stdenv.mkDerivation {
|
||||||
name = "draconis++";
|
name = "draconis++";
|
||||||
version = "0.1.0";
|
version = "0.1.0";
|
||||||
src = self;
|
src = self;
|
||||||
|
|
||||||
nativeBuildInputs = [
|
nativeBuildInputs = [
|
||||||
cmake
|
cmake
|
||||||
meson
|
meson
|
||||||
ninja
|
ninja
|
||||||
pkg-config
|
pkg-config
|
||||||
];
|
];
|
||||||
|
|
||||||
buildInputs = deps;
|
buildInputs = deps;
|
||||||
|
|
||||||
configurePhase = ''
|
configurePhase = ''
|
||||||
meson setup build
|
meson setup build
|
||||||
'';
|
'';
|
||||||
|
|
||||||
buildPhase = ''
|
buildPhase = ''
|
||||||
meson compile -C build
|
meson compile -C build
|
||||||
'';
|
'';
|
||||||
|
|
||||||
installPhase = ''
|
installPhase = ''
|
||||||
mkdir -p $out/bin
|
mkdir -p $out/bin
|
||||||
mv build/draconis++ $out/bin/draconis++
|
mv build/draconis++ $out/bin/draconis++
|
||||||
'';
|
'';
|
||||||
};
|
};
|
||||||
|
|
||||||
default = draconisplusplus;
|
default = draconisplusplus;
|
||||||
};
|
};
|
||||||
|
|
||||||
formatter = treefmt-nix.lib.mkWrapper pkgs {
|
formatter = treefmt-nix.lib.mkWrapper pkgs {
|
||||||
projectRootFile = "flake.nix";
|
projectRootFile = "flake.nix";
|
||||||
programs = {
|
programs = {
|
||||||
alejandra.enable = true;
|
alejandra.enable = true;
|
||||||
deadnix.enable = true;
|
deadnix.enable = true;
|
||||||
|
|
||||||
clang-format = {
|
clang-format = {
|
||||||
enable = true;
|
enable = true;
|
||||||
package = pkgs.llvmPackages.clang-tools;
|
package = pkgs.llvmPackages.clang-tools;
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
devShell = mkShell.override {inherit stdenv;} {
|
devShell = mkShell.override {inherit stdenv;} {
|
||||||
packages =
|
packages =
|
||||||
[
|
[
|
||||||
alejandra
|
alejandra
|
||||||
bear
|
bear
|
||||||
llvmPackages.clang-tools
|
llvmPackages.clang-tools
|
||||||
cmake
|
cmake
|
||||||
lldb
|
lldb
|
||||||
hyperfine
|
hyperfine
|
||||||
meson
|
meson
|
||||||
ninja
|
ninja
|
||||||
nvfetcher
|
nvfetcher
|
||||||
pkg-config
|
pkg-config
|
||||||
unzip
|
unzip
|
||||||
|
|
||||||
(writeScriptBin "build" "meson compile -C build")
|
(writeScriptBin "build" "meson compile -C build")
|
||||||
(writeScriptBin "clean" "meson setup build --wipe")
|
(writeScriptBin "clean" "meson setup build --wipe")
|
||||||
(writeScriptBin "run" "meson compile -C build && build/draconis++")
|
(writeScriptBin "run" "meson compile -C build && build/draconis++")
|
||||||
]
|
]
|
||||||
++ deps;
|
++ deps;
|
||||||
|
|
||||||
LD_LIBRARY_PATH = "${lib.makeLibraryPath deps}";
|
LD_LIBRARY_PATH = "${lib.makeLibraryPath deps}";
|
||||||
NIX_ENFORCE_NO_NATIVE = 0;
|
NIX_ENFORCE_NO_NATIVE = 0;
|
||||||
|
|
||||||
name = "C++";
|
name = "C++";
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,7 +8,7 @@ project(
|
||||||
default_options: [
|
default_options: [
|
||||||
'default_library=static',
|
'default_library=static',
|
||||||
'warning_level=everything',
|
'warning_level=everything',
|
||||||
'buildtype=release',
|
'buildtype=debugoptimized',
|
||||||
],
|
],
|
||||||
)
|
)
|
||||||
|
|
||||||
|
@ -98,7 +98,7 @@ common_deps = [
|
||||||
dependency('fmt', include_type: 'system', static: true),
|
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('nlohmann_json', include_type: 'system', static: true),
|
dependency('glaze'),
|
||||||
dependency('openssl', include_type: 'system', static: true, required: false),
|
dependency('openssl', include_type: 'system', static: true, required: false),
|
||||||
]
|
]
|
||||||
|
|
||||||
|
@ -122,13 +122,12 @@ elif host_system == 'windows'
|
||||||
elif host_system == 'linux' or host_system == 'freebsd'
|
elif host_system == 'linux' or host_system == 'freebsd'
|
||||||
platform_deps += [
|
platform_deps += [
|
||||||
dependency('SQLiteCpp'),
|
dependency('SQLiteCpp'),
|
||||||
dependency('sdbus-c++'),
|
|
||||||
dependency('x11'),
|
dependency('x11'),
|
||||||
dependency('xcb'),
|
dependency('xcb'),
|
||||||
dependency('xau'),
|
dependency('xau'),
|
||||||
dependency('xdmcp'),
|
dependency('xdmcp'),
|
||||||
dependency('wayland-client'),
|
dependency('wayland-client'),
|
||||||
dependency('dbus-1'),
|
dependency('dbus-1', include_type: 'system'),
|
||||||
]
|
]
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
@ -164,7 +163,7 @@ objc_args = []
|
||||||
if host_system == 'darwin'
|
if host_system == 'darwin'
|
||||||
objc_args += ['-fobjc-arc']
|
objc_args += ['-fobjc-arc']
|
||||||
elif cpp.get_id() == 'clang'
|
elif cpp.get_id() == 'clang'
|
||||||
link_args += ['-static-libgcc', '-static-libstdc++', '-static']
|
link_args += ['-static-libgcc', '-static-libstdc++']
|
||||||
endif
|
endif
|
||||||
|
|
||||||
# ------------------- #
|
# ------------------- #
|
||||||
|
|
|
@ -2,18 +2,6 @@
|
||||||
src.github = "fmtlib/fmt"
|
src.github = "fmtlib/fmt"
|
||||||
fetch.github = "fmtlib/fmt"
|
fetch.github = "fmtlib/fmt"
|
||||||
|
|
||||||
[reflect-cpp]
|
|
||||||
src.git = "https://github.com/getml/reflect-cpp"
|
|
||||||
fetch.github = "getml/reflect-cpp"
|
|
||||||
|
|
||||||
[sdbus-cpp]
|
|
||||||
src.github = "kistler-group/sdbus-cpp"
|
|
||||||
fetch.github = "kistler-group/sdbus-cpp"
|
|
||||||
|
|
||||||
[tomlplusplus]
|
[tomlplusplus]
|
||||||
src.github = "marzer/tomlplusplus"
|
src.github = "marzer/tomlplusplus"
|
||||||
fetch.github = "marzer/tomlplusplus"
|
fetch.github = "marzer/tomlplusplus"
|
||||||
|
|
||||||
[yyjson]
|
|
||||||
src.github = "ibireme/yyjson"
|
|
||||||
fetch.github = "ibireme/yyjson"
|
|
||||||
|
|
|
@ -12,56 +12,59 @@
|
||||||
#include "src/util/macros.h"
|
#include "src/util/macros.h"
|
||||||
|
|
||||||
namespace fs = std::filesystem;
|
namespace fs = std::filesystem;
|
||||||
using namespace std::string_literals;
|
|
||||||
using namespace nlohmann;
|
using namespace nlohmann;
|
||||||
|
using namespace std::string_literals;
|
||||||
|
|
||||||
// Alias for cleaner error handling
|
|
||||||
template <typename T>
|
template <typename T>
|
||||||
using Result = std::expected<T, std::string>;
|
using Result = std::expected<T, std::string>;
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
// Common function to get cache path
|
constexpr glz::opts glaze_opts = { .error_on_unknown_keys = false };
|
||||||
|
|
||||||
fn GetCachePath() -> Result<fs::path> {
|
fn GetCachePath() -> Result<fs::path> {
|
||||||
std::error_code errc;
|
std::error_code errc;
|
||||||
fs::path cachePath = fs::temp_directory_path(errc);
|
fs::path cachePath = fs::temp_directory_path(errc);
|
||||||
|
|
||||||
if (errc)
|
if (errc)
|
||||||
return std::unexpected("Failed to get temp directory: "s + errc.message());
|
return std::unexpected("Failed to get temp directory: " + errc.message());
|
||||||
|
|
||||||
cachePath /= "weather_cache.json";
|
cachePath /= "weather_cache.json";
|
||||||
return cachePath;
|
return cachePath;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Function to read cache from file
|
|
||||||
fn ReadCacheFromFile() -> Result<WeatherOutput> {
|
fn ReadCacheFromFile() -> Result<WeatherOutput> {
|
||||||
Result<fs::path> cachePath = GetCachePath();
|
Result<fs::path> cachePath = GetCachePath();
|
||||||
|
|
||||||
if (!cachePath)
|
if (!cachePath)
|
||||||
return std::unexpected(cachePath.error());
|
return std::unexpected(cachePath.error());
|
||||||
|
|
||||||
std::ifstream ifs(*cachePath, std::ios::binary);
|
std::ifstream ifs(*cachePath, std::ios::binary);
|
||||||
|
|
||||||
if (!ifs.is_open())
|
if (!ifs.is_open())
|
||||||
return std::unexpected("Cache file not found: "s + cachePath->string());
|
return std::unexpected("Cache file not found: " + cachePath->string());
|
||||||
|
|
||||||
DEBUG_LOG("Reading from cache file...");
|
DEBUG_LOG("Reading from cache file...");
|
||||||
|
|
||||||
try {
|
try {
|
||||||
const std::string content((std::istreambuf_iterator<char>(ifs)), std::istreambuf_iterator<char>());
|
const std::string content((std::istreambuf_iterator<char>(ifs)), std::istreambuf_iterator<char>());
|
||||||
json json = json::parse(content);
|
WeatherOutput result;
|
||||||
WeatherOutput result = json.get<WeatherOutput>();
|
glz::error_ctx errc = glz::read<glaze_opts>(result, content);
|
||||||
|
|
||||||
|
if (errc.ec != glz::error_code::none)
|
||||||
|
return std::unexpected("JSON parse error: " + glz::format_error(errc, content));
|
||||||
|
|
||||||
DEBUG_LOG("Successfully read from cache file.");
|
DEBUG_LOG("Successfully read from cache file.");
|
||||||
return result;
|
return result;
|
||||||
} catch (const std::exception& e) { return std::unexpected("JSON parse error: "s + e.what()); }
|
} catch (const std::exception& e) { return std::unexpected("Error reading cache: "s + e.what()); }
|
||||||
}
|
}
|
||||||
|
|
||||||
// Function to write cache to file
|
|
||||||
fn WriteCacheToFile(const WeatherOutput& data) -> Result<void> {
|
fn WriteCacheToFile(const WeatherOutput& data) -> Result<void> {
|
||||||
Result<fs::path> cachePath = GetCachePath();
|
Result<fs::path> cachePath = GetCachePath();
|
||||||
|
|
||||||
if (!cachePath)
|
if (!cachePath)
|
||||||
return std::unexpected(cachePath.error());
|
return std::unexpected(cachePath.error());
|
||||||
|
|
||||||
DEBUG_LOG("Writing to cache file...");
|
DEBUG_LOG("Writing to cache file...");
|
||||||
|
|
||||||
fs::path tempPath = *cachePath;
|
fs::path tempPath = *cachePath;
|
||||||
tempPath += ".tmp";
|
tempPath += ".tmp";
|
||||||
|
|
||||||
|
@ -69,26 +72,29 @@ namespace {
|
||||||
{
|
{
|
||||||
std::ofstream ofs(tempPath, std::ios::binary | std::ios::trunc);
|
std::ofstream ofs(tempPath, std::ios::binary | std::ios::trunc);
|
||||||
if (!ofs.is_open())
|
if (!ofs.is_open())
|
||||||
return std::unexpected("Failed to open temp file: "s + tempPath.string());
|
return std::unexpected("Failed to open temp file: " + tempPath.string());
|
||||||
|
|
||||||
json json = data;
|
std::string jsonStr;
|
||||||
ofs << json.dump();
|
glz::error_ctx errc = glz::write_json(data, jsonStr);
|
||||||
|
|
||||||
|
if (errc.ec != glz::error_code::none)
|
||||||
|
return std::unexpected("JSON serialization error: " + glz::format_error(errc, jsonStr));
|
||||||
|
|
||||||
|
ofs << jsonStr;
|
||||||
if (!ofs)
|
if (!ofs)
|
||||||
return std::unexpected("Failed to write to temp file");
|
return std::unexpected("Failed to write to temp file");
|
||||||
}
|
}
|
||||||
|
|
||||||
std::error_code errc;
|
std::error_code errc;
|
||||||
fs::rename(tempPath, *cachePath, errc);
|
fs::rename(tempPath, *cachePath, errc);
|
||||||
|
|
||||||
if (errc) {
|
if (errc) {
|
||||||
fs::remove(tempPath, errc);
|
fs::remove(tempPath, errc);
|
||||||
return std::unexpected("Failed to replace cache file: "s + errc.message());
|
return std::unexpected("Failed to replace cache file: " + errc.message());
|
||||||
}
|
}
|
||||||
|
|
||||||
DEBUG_LOG("Successfully wrote to cache file.");
|
DEBUG_LOG("Successfully wrote to cache file.");
|
||||||
return {};
|
return {};
|
||||||
} catch (const std::exception& e) { return std::unexpected("JSON serialization error: "s + e.what()); }
|
} catch (const std::exception& e) { return std::unexpected("File operation error: "s + e.what()); }
|
||||||
}
|
}
|
||||||
|
|
||||||
fn WriteCallback(void* contents, const size_t size, const size_t nmemb, std::string* str) -> size_t {
|
fn WriteCallback(void* contents, const size_t size, const size_t nmemb, std::string* str) -> size_t {
|
||||||
|
@ -97,10 +103,8 @@ namespace {
|
||||||
return totalSize;
|
return totalSize;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Function to make API request
|
fn MakeApiRequest(const std::string& url) -> const Result<WeatherOutput> {
|
||||||
fn MakeApiRequest(const std::string& url) -> Result<WeatherOutput> {
|
|
||||||
DEBUG_LOG("Making API request to URL: {}", url);
|
DEBUG_LOG("Making API request to URL: {}", url);
|
||||||
|
|
||||||
CURL* curl = curl_easy_init();
|
CURL* curl = curl_easy_init();
|
||||||
std::string responseBuffer;
|
std::string responseBuffer;
|
||||||
|
|
||||||
|
@ -119,37 +123,38 @@ namespace {
|
||||||
if (res != CURLE_OK)
|
if (res != CURLE_OK)
|
||||||
return std::unexpected(fmt::format("cURL error: {}", curl_easy_strerror(res)));
|
return std::unexpected(fmt::format("cURL error: {}", curl_easy_strerror(res)));
|
||||||
|
|
||||||
DEBUG_LOG("API response size: {}", responseBuffer.size());
|
WeatherOutput output;
|
||||||
DEBUG_LOG("API response: {}", responseBuffer);
|
glz::error_ctx errc = glz::read<glaze_opts>(output, responseBuffer);
|
||||||
|
|
||||||
try {
|
if (errc.ec != glz::error_code::none)
|
||||||
json json = json::parse(responseBuffer);
|
return std::unexpected("API response parse error: " + glz::format_error(errc, responseBuffer));
|
||||||
WeatherOutput output = json.get<WeatherOutput>();
|
|
||||||
return output;
|
return std::move(output);
|
||||||
} catch (const std::exception& e) { return std::unexpected("API response parse error: "s + e.what()); }
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Core function to get weather information
|
|
||||||
fn Weather::getWeatherInfo() const -> WeatherOutput {
|
fn Weather::getWeatherInfo() const -> WeatherOutput {
|
||||||
using namespace std::chrono;
|
using namespace std::chrono;
|
||||||
|
|
||||||
if (Result<WeatherOutput> data = ReadCacheFromFile()) {
|
if (Result<WeatherOutput> data = ReadCacheFromFile()) {
|
||||||
const WeatherOutput& dataVal = *data;
|
const WeatherOutput& dataVal = *data;
|
||||||
|
const duration<double> cacheAge = system_clock::now() - system_clock::time_point(seconds(dataVal.dt));
|
||||||
|
|
||||||
if (const duration<double> cacheAge = system_clock::now() - system_clock::time_point(seconds(dataVal.dt));
|
if (cacheAge < 10min) {
|
||||||
cacheAge < 10min) {
|
|
||||||
DEBUG_LOG("Using valid cache");
|
DEBUG_LOG("Using valid cache");
|
||||||
return dataVal;
|
return dataVal;
|
||||||
}
|
}
|
||||||
|
|
||||||
DEBUG_LOG("Cache expired");
|
DEBUG_LOG("Cache expired");
|
||||||
} else {
|
} else {
|
||||||
DEBUG_LOG("Cache error: {}", data.error());
|
DEBUG_LOG("Cache error: {}", data.error());
|
||||||
}
|
}
|
||||||
|
|
||||||
fn handleApiResult = [](const Result<WeatherOutput>& result) -> WeatherOutput {
|
fn handleApiResult = [](const Result<WeatherOutput>& result) -> WeatherOutput {
|
||||||
if (!result)
|
if (!result) {
|
||||||
ERROR_LOG("API request failed: {}", result.error());
|
ERROR_LOG("API request failed: {}", result.error());
|
||||||
|
return WeatherOutput {};
|
||||||
|
}
|
||||||
|
|
||||||
if (Result<void> writeResult = WriteCacheToFile(*result); !writeResult)
|
if (Result<void> writeResult = WriteCacheToFile(*result); !writeResult)
|
||||||
ERROR_LOG("Failed to write cache: {}", writeResult.error());
|
ERROR_LOG("Failed to write cache: {}", writeResult.error());
|
||||||
|
@ -160,8 +165,8 @@ fn Weather::getWeatherInfo() const -> WeatherOutput {
|
||||||
if (std::holds_alternative<std::string>(location)) {
|
if (std::holds_alternative<std::string>(location)) {
|
||||||
const auto& city = std::get<std::string>(location);
|
const auto& city = std::get<std::string>(location);
|
||||||
char* escaped = curl_easy_escape(nullptr, city.c_str(), static_cast<int>(city.length()));
|
char* escaped = curl_easy_escape(nullptr, city.c_str(), static_cast<int>(city.length()));
|
||||||
|
|
||||||
DEBUG_LOG("Requesting city: {}", escaped);
|
DEBUG_LOG("Requesting city: {}", escaped);
|
||||||
|
|
||||||
const std::string apiUrl =
|
const std::string apiUrl =
|
||||||
fmt::format("https://api.openweathermap.org/data/2.5/weather?q={}&appid={}&units={}", escaped, api_key, units);
|
fmt::format("https://api.openweathermap.org/data/2.5/weather?q={}&appid={}&units={}", escaped, api_key, units);
|
||||||
|
|
||||||
|
|
|
@ -1,51 +1,27 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <nlohmann/json.hpp>
|
#include <glaze/glaze.hpp>
|
||||||
|
|
||||||
#include "../util/types.h"
|
#include "../util/types.h"
|
||||||
|
|
||||||
using degrees = unsigned short; // 0-360, validate manually
|
// NOLINTBEGIN(readability-identifier-naming)
|
||||||
using percentage = unsigned char; // 0-100, validate manually
|
|
||||||
|
|
||||||
struct Condition {
|
struct Condition {
|
||||||
std::string description;
|
std::string description;
|
||||||
std::string icon;
|
|
||||||
std::string main;
|
struct glaze {
|
||||||
usize id;
|
using T = Condition;
|
||||||
|
static constexpr auto value = glz::object("description", &T::description);
|
||||||
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Main {
|
struct Main {
|
||||||
f64 feels_like;
|
f64 temp;
|
||||||
f64 temp;
|
|
||||||
f64 temp_max;
|
|
||||||
f64 temp_min;
|
|
||||||
isize pressure;
|
|
||||||
percentage humidity;
|
|
||||||
std::optional<isize> grnd_level;
|
|
||||||
std::optional<isize> sea_level;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct Wind {
|
struct glaze {
|
||||||
degrees deg;
|
using T = Main;
|
||||||
f64 speed;
|
static constexpr auto value = glz::object("temp", &T::temp);
|
||||||
std::optional<f64> gust;
|
};
|
||||||
};
|
|
||||||
|
|
||||||
struct Precipitation {
|
|
||||||
std::optional<f64> one_hour;
|
|
||||||
std::optional<f64> three_hours;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct Sys {
|
|
||||||
std::string country;
|
|
||||||
usize id;
|
|
||||||
usize sunrise;
|
|
||||||
usize sunset;
|
|
||||||
usize type;
|
|
||||||
};
|
|
||||||
|
|
||||||
struct Clouds {
|
|
||||||
percentage all;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Coords {
|
struct Coords {
|
||||||
|
@ -54,204 +30,15 @@ struct Coords {
|
||||||
};
|
};
|
||||||
|
|
||||||
struct WeatherOutput {
|
struct WeatherOutput {
|
||||||
Clouds clouds;
|
Main main;
|
||||||
isize timezone;
|
std::string name;
|
||||||
isize visibility;
|
std::vector<Condition> weather;
|
||||||
Main main;
|
usize dt;
|
||||||
Coords coords; // JSON key: "coord"
|
|
||||||
std::optional<Precipitation> rain;
|
struct glaze {
|
||||||
std::optional<Precipitation> snow;
|
using T = WeatherOutput;
|
||||||
std::string base;
|
static constexpr auto value = glz::object("main", &T::main, "name", &T::name, "weather", &T::weather, "dt", &T::dt);
|
||||||
std::string name;
|
};
|
||||||
std::vector<Condition> weather;
|
|
||||||
Sys sys;
|
|
||||||
usize cod;
|
|
||||||
usize dt;
|
|
||||||
usize id;
|
|
||||||
Wind wind;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// JSON Serialization Definitions
|
|
||||||
// NOLINTBEGIN(readability-identifier-naming)
|
|
||||||
namespace nlohmann {
|
|
||||||
using namespace nlohmann;
|
|
||||||
template <>
|
|
||||||
struct adl_serializer<Condition> {
|
|
||||||
static void to_json(json& jsonOut, const Condition& cond) {
|
|
||||||
jsonOut = json {
|
|
||||||
{ "description", cond.description },
|
|
||||||
{ "icon", cond.icon },
|
|
||||||
{ "main", cond.main },
|
|
||||||
{ "id", cond.id }
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
static void from_json(const json& jsonIn, Condition& cond) {
|
|
||||||
jsonIn.at("description").get_to(cond.description);
|
|
||||||
jsonIn.at("icon").get_to(cond.icon);
|
|
||||||
jsonIn.at("main").get_to(cond.main);
|
|
||||||
jsonIn.at("id").get_to(cond.id);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
template <>
|
|
||||||
struct adl_serializer<Main> {
|
|
||||||
static void to_json(json& jsonOut, const Main& main) {
|
|
||||||
jsonOut = json {
|
|
||||||
{ "feels_like", main.feels_like },
|
|
||||||
{ "temp", main.temp },
|
|
||||||
{ "temp_max", main.temp_max },
|
|
||||||
{ "temp_min", main.temp_min },
|
|
||||||
{ "pressure", main.pressure },
|
|
||||||
{ "humidity", main.humidity }
|
|
||||||
};
|
|
||||||
if (main.grnd_level)
|
|
||||||
jsonOut["grnd_level"] = *main.grnd_level;
|
|
||||||
if (main.sea_level)
|
|
||||||
jsonOut["sea_level"] = *main.sea_level;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void from_json(const json& jsonIn, Main& main) {
|
|
||||||
jsonIn.at("feels_like").get_to(main.feels_like);
|
|
||||||
jsonIn.at("temp").get_to(main.temp);
|
|
||||||
jsonIn.at("temp_max").get_to(main.temp_max);
|
|
||||||
jsonIn.at("temp_min").get_to(main.temp_min);
|
|
||||||
jsonIn.at("pressure").get_to(main.pressure);
|
|
||||||
jsonIn.at("humidity").get_to(main.humidity);
|
|
||||||
if (jsonIn.contains("grnd_level"))
|
|
||||||
main.grnd_level = jsonIn["grnd_level"].get<isize>();
|
|
||||||
if (jsonIn.contains("sea_level"))
|
|
||||||
main.sea_level = jsonIn["sea_level"].get<isize>();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
template <>
|
|
||||||
struct adl_serializer<Wind> {
|
|
||||||
static void to_json(json& jsonOut, const Wind& wind) {
|
|
||||||
jsonOut = json {
|
|
||||||
{ "deg", wind.deg },
|
|
||||||
{ "speed", wind.speed }
|
|
||||||
};
|
|
||||||
if (wind.gust)
|
|
||||||
jsonOut["gust"] = *wind.gust;
|
|
||||||
}
|
|
||||||
static void from_json(const json& jsonIn, Wind& wind) {
|
|
||||||
jsonIn.at("deg").get_to(wind.deg);
|
|
||||||
jsonIn.at("speed").get_to(wind.speed);
|
|
||||||
if (jsonIn.contains("gust"))
|
|
||||||
wind.gust = jsonIn["gust"].get<f64>();
|
|
||||||
// Validate degrees (0-360)
|
|
||||||
if (wind.deg > 360)
|
|
||||||
throw std::runtime_error("Invalid wind degree");
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
template <>
|
|
||||||
struct adl_serializer<Precipitation> {
|
|
||||||
static void to_json(json& jsonOut, const Precipitation& precip) {
|
|
||||||
if (precip.one_hour)
|
|
||||||
jsonOut["1h"] = *precip.one_hour;
|
|
||||||
if (precip.three_hours)
|
|
||||||
jsonOut["3h"] = *precip.three_hours;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void from_json(const json& jsonIn, Precipitation& precip) {
|
|
||||||
if (jsonIn.contains("1h"))
|
|
||||||
precip.one_hour = jsonIn["1h"].get<f64>();
|
|
||||||
if (jsonIn.contains("3h"))
|
|
||||||
precip.three_hours = jsonIn["3h"].get<f64>();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
template <>
|
|
||||||
struct adl_serializer<Sys> {
|
|
||||||
static void to_json(json& jsonOut, const Sys& sys) {
|
|
||||||
jsonOut = json {
|
|
||||||
{ "country", sys.country },
|
|
||||||
{ "id", sys.id },
|
|
||||||
{ "sunrise", sys.sunrise },
|
|
||||||
{ "sunset", sys.sunset },
|
|
||||||
{ "type", sys.type }
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
static void from_json(const json& jsonIn, Sys& sys) {
|
|
||||||
jsonIn.at("country").get_to(sys.country);
|
|
||||||
jsonIn.at("id").get_to(sys.id);
|
|
||||||
jsonIn.at("sunrise").get_to(sys.sunrise);
|
|
||||||
jsonIn.at("sunset").get_to(sys.sunset);
|
|
||||||
jsonIn.at("type").get_to(sys.type);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
template <>
|
|
||||||
struct adl_serializer<Clouds> {
|
|
||||||
static void to_json(json& jsonOut, const Clouds& clouds) {
|
|
||||||
jsonOut = json {
|
|
||||||
{ "all", clouds.all }
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
static void from_json(const json& jsonIn, Clouds& clouds) { jsonIn.at("all").get_to(clouds.all); }
|
|
||||||
};
|
|
||||||
|
|
||||||
template <>
|
|
||||||
struct adl_serializer<Coords> {
|
|
||||||
static void to_json(json& jsonOut, const Coords& coords) {
|
|
||||||
jsonOut = json {
|
|
||||||
{ "lat", coords.lat },
|
|
||||||
{ "lon", coords.lon }
|
|
||||||
};
|
|
||||||
}
|
|
||||||
static void from_json(const json& jsonIn, Coords& coords) {
|
|
||||||
jsonIn.at("lat").get_to(coords.lat);
|
|
||||||
jsonIn.at("lon").get_to(coords.lon);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
template <>
|
|
||||||
struct adl_serializer<WeatherOutput> {
|
|
||||||
static void to_json(json& jsonOut, const WeatherOutput& weatherOut) {
|
|
||||||
jsonOut = json {
|
|
||||||
{ "clouds", weatherOut.clouds },
|
|
||||||
{ "timezone", weatherOut.timezone },
|
|
||||||
{ "visibility", weatherOut.visibility },
|
|
||||||
{ "main", weatherOut.main },
|
|
||||||
{ "coord", weatherOut.coords },
|
|
||||||
{ "base", weatherOut.base },
|
|
||||||
{ "name", weatherOut.name },
|
|
||||||
{ "weather", weatherOut.weather },
|
|
||||||
{ "sys", weatherOut.sys },
|
|
||||||
{ "cod", weatherOut.cod },
|
|
||||||
{ "dt", weatherOut.dt },
|
|
||||||
{ "id", weatherOut.id },
|
|
||||||
{ "wind", weatherOut.wind }
|
|
||||||
};
|
|
||||||
if (weatherOut.rain)
|
|
||||||
jsonOut["rain"] = *weatherOut.rain;
|
|
||||||
if (weatherOut.snow)
|
|
||||||
jsonOut["snow"] = *weatherOut.snow;
|
|
||||||
}
|
|
||||||
|
|
||||||
static void from_json(const json& jsonIn, WeatherOutput& weatherOut) {
|
|
||||||
jsonIn.at("clouds").get_to(weatherOut.clouds);
|
|
||||||
jsonIn.at("timezone").get_to(weatherOut.timezone);
|
|
||||||
jsonIn.at("visibility").get_to(weatherOut.visibility);
|
|
||||||
jsonIn.at("main").get_to(weatherOut.main);
|
|
||||||
jsonIn.at("coord").get_to(weatherOut.coords);
|
|
||||||
if (jsonIn.contains("rain"))
|
|
||||||
weatherOut.rain = jsonIn["rain"].get<Precipitation>();
|
|
||||||
if (jsonIn.contains("snow"))
|
|
||||||
weatherOut.snow = jsonIn["snow"].get<Precipitation>();
|
|
||||||
jsonIn.at("base").get_to(weatherOut.base);
|
|
||||||
jsonIn.at("name").get_to(weatherOut.name);
|
|
||||||
jsonIn.at("weather").get_to(weatherOut.weather);
|
|
||||||
jsonIn.at("sys").get_to(weatherOut.sys);
|
|
||||||
jsonIn.at("cod").get_to(weatherOut.cod);
|
|
||||||
jsonIn.at("dt").get_to(weatherOut.dt);
|
|
||||||
jsonIn.at("id").get_to(weatherOut.id);
|
|
||||||
jsonIn.at("wind").get_to(weatherOut.wind);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
// NOLINTEND(readability-identifier-naming)
|
// NOLINTEND(readability-identifier-naming)
|
||||||
|
|
96
src/main.cpp
96
src/main.cpp
|
@ -166,21 +166,25 @@ namespace {
|
||||||
|
|
||||||
content.push_back(text(" Hello " + name + "! ") | bold | color(Color::Cyan));
|
content.push_back(text(" Hello " + name + "! ") | bold | color(Color::Cyan));
|
||||||
content.push_back(separator() | color(borderColor));
|
content.push_back(separator() | color(borderColor));
|
||||||
content.push_back(hbox({
|
content.push_back(hbox(
|
||||||
text(" ") | color(iconColor), // Palette icon
|
{
|
||||||
CreateColorCircles(),
|
text(" ") | color(iconColor), // Palette icon
|
||||||
}));
|
CreateColorCircles(),
|
||||||
|
}
|
||||||
|
));
|
||||||
content.push_back(separator() | color(borderColor));
|
content.push_back(separator() | color(borderColor));
|
||||||
|
|
||||||
// Helper function for aligned rows
|
// Helper function for aligned rows
|
||||||
fn createRow = [&](const std::string& icon, const std::string& label, const std::string& value) {
|
fn createRow = [&](const std::string& icon, const std::string& label, const std::string& value) {
|
||||||
return hbox({
|
return hbox(
|
||||||
text(icon) | color(iconColor),
|
{
|
||||||
text(label) | color(labelColor),
|
text(icon) | color(iconColor),
|
||||||
filler(),
|
text(label) | color(labelColor),
|
||||||
text(value) | color(valueColor),
|
filler(),
|
||||||
text(" "),
|
text(value) | color(valueColor),
|
||||||
});
|
text(" "),
|
||||||
|
}
|
||||||
|
);
|
||||||
};
|
};
|
||||||
|
|
||||||
// System info rows
|
// System info rows
|
||||||
|
@ -191,31 +195,39 @@ 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(weatherIcon) | color(iconColor),
|
{
|
||||||
text("Weather") | color(labelColor),
|
text(weatherIcon) | color(iconColor),
|
||||||
filler(),
|
text("Weather") | color(labelColor),
|
||||||
|
filler(),
|
||||||
|
|
||||||
hbox({
|
hbox(
|
||||||
text(fmt::format("{}°F ", std::lround(weatherInfo.main.temp))),
|
{
|
||||||
text("in "),
|
text(fmt::format("{}°F ", std::lround(weatherInfo.main.temp))),
|
||||||
text(weatherInfo.name),
|
text("in "),
|
||||||
text(" "),
|
text(weatherInfo.name),
|
||||||
}) |
|
text(" "),
|
||||||
color(valueColor),
|
}
|
||||||
}));
|
) |
|
||||||
|
color(valueColor),
|
||||||
|
}
|
||||||
|
));
|
||||||
else
|
else
|
||||||
content.push_back(hbox({
|
content.push_back(hbox(
|
||||||
text(weatherIcon) | color(iconColor),
|
{
|
||||||
text("Weather") | color(labelColor),
|
text(weatherIcon) | color(iconColor),
|
||||||
filler(),
|
text("Weather") | color(labelColor),
|
||||||
|
filler(),
|
||||||
|
|
||||||
hbox({
|
hbox(
|
||||||
text(fmt::format("{}°F, {}", std::lround(weatherInfo.main.temp), weatherInfo.weather[0].description)),
|
{
|
||||||
text(" "),
|
text(fmt::format("{}°F, {}", std::lround(weatherInfo.main.temp), weatherInfo.weather[0].description)),
|
||||||
}) |
|
text(" "),
|
||||||
color(valueColor),
|
}
|
||||||
}));
|
) |
|
||||||
|
color(valueColor),
|
||||||
|
}
|
||||||
|
));
|
||||||
}
|
}
|
||||||
|
|
||||||
content.push_back(separator() | color(borderColor));
|
content.push_back(separator() | color(borderColor));
|
||||||
|
@ -259,14 +271,16 @@ namespace {
|
||||||
const std::string& npText = *nowPlayingResult;
|
const std::string& npText = *nowPlayingResult;
|
||||||
|
|
||||||
content.push_back(separator() | color(borderColor));
|
content.push_back(separator() | color(borderColor));
|
||||||
content.push_back(hbox({
|
content.push_back(hbox(
|
||||||
text(musicIcon) | color(iconColor),
|
{
|
||||||
text("Playing") | color(labelColor),
|
text(musicIcon) | color(iconColor),
|
||||||
text(" "),
|
text("Playing") | color(labelColor),
|
||||||
filler(),
|
text(" "),
|
||||||
paragraph(npText) | color(Color::Magenta) | size(WIDTH, LESS_THAN, 30),
|
filler(),
|
||||||
text(" "),
|
paragraph(npText) | color(Color::Magenta) | size(WIDTH, LESS_THAN, 30),
|
||||||
}));
|
text(" "),
|
||||||
|
}
|
||||||
|
));
|
||||||
} else {
|
} else {
|
||||||
const NowPlayingError& error = nowPlayingResult.error();
|
const NowPlayingError& error = nowPlayingResult.error();
|
||||||
|
|
||||||
|
|
|
@ -15,6 +15,7 @@
|
||||||
#include <optional>
|
#include <optional>
|
||||||
#include <ranges>
|
#include <ranges>
|
||||||
#include <sys/socket.h>
|
#include <sys/socket.h>
|
||||||
|
#include <sys/statvfs.h>
|
||||||
#include <sys/utsname.h>
|
#include <sys/utsname.h>
|
||||||
#include <unistd.h>
|
#include <unistd.h>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
@ -23,18 +24,36 @@
|
||||||
#include "os.h"
|
#include "os.h"
|
||||||
#include "src/util/macros.h"
|
#include "src/util/macros.h"
|
||||||
|
|
||||||
using std::errc, std::expected, std::from_chars, std::getline, std::istreambuf_iterator, std::less, std::lock_guard,
|
// Minimal global using declarations needed for function signatures
|
||||||
std::mutex, std::ofstream, std::pair, std::string_view, std::vector, std::nullopt, std::array, std::optional,
|
using std::expected;
|
||||||
std::bit_cast, std::to_string, std::ifstream, std::getenv, std::string, std::unexpected, std::ranges::is_sorted,
|
using std::optional;
|
||||||
std::ranges::lower_bound, std::ranges::replace, std::ranges::subrange, std::ranges::transform;
|
|
||||||
|
|
||||||
using namespace std::literals::string_view_literals;
|
|
||||||
|
|
||||||
namespace fs = std::filesystem;
|
namespace fs = std::filesystem;
|
||||||
|
using namespace std::literals::string_view_literals;
|
||||||
enum SessionType : u8 { Wayland, X11, TTY, Unknown };
|
|
||||||
|
|
||||||
namespace {
|
namespace {
|
||||||
|
// Local using declarations for the anonymous namespace
|
||||||
|
using std::array;
|
||||||
|
using std::bit_cast;
|
||||||
|
using std::getenv;
|
||||||
|
using std::ifstream;
|
||||||
|
using std::istreambuf_iterator;
|
||||||
|
using std::less;
|
||||||
|
using std::lock_guard;
|
||||||
|
using std::mutex;
|
||||||
|
using std::nullopt;
|
||||||
|
using std::ofstream;
|
||||||
|
using std::pair;
|
||||||
|
using std::string_view;
|
||||||
|
using std::to_string;
|
||||||
|
using std::unexpected;
|
||||||
|
using std::vector;
|
||||||
|
using std::ranges::is_sorted;
|
||||||
|
using std::ranges::lower_bound;
|
||||||
|
using std::ranges::replace;
|
||||||
|
using std::ranges::subrange;
|
||||||
|
using std::ranges::transform;
|
||||||
|
|
||||||
fn GetX11WindowManager() -> string {
|
fn GetX11WindowManager() -> string {
|
||||||
Display* display = XOpenDisplay(nullptr);
|
Display* display = XOpenDisplay(nullptr);
|
||||||
|
|
||||||
|
@ -394,6 +413,8 @@ fn GetOSVersion() -> expected<string, string> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn GetMemInfo() -> expected<u64, string> {
|
fn GetMemInfo() -> expected<u64, string> {
|
||||||
|
using std::from_chars, std::errc;
|
||||||
|
|
||||||
constexpr const char* path = "/proc/meminfo";
|
constexpr const char* path = "/proc/meminfo";
|
||||||
|
|
||||||
ifstream input(path);
|
ifstream input(path);
|
||||||
|
@ -657,9 +678,20 @@ fn GetDesktopEnvironment() -> optional<string> {
|
||||||
}
|
}
|
||||||
|
|
||||||
fn GetShell() -> string {
|
fn GetShell() -> string {
|
||||||
const char* shell = getenv("SHELL");
|
const string_view shell = getenv("SHELL");
|
||||||
|
|
||||||
return shell ? shell : "";
|
if (shell.ends_with("bash"))
|
||||||
|
return "Bash";
|
||||||
|
if (shell.ends_with("zsh"))
|
||||||
|
return "Zsh";
|
||||||
|
if (shell.ends_with("fish"))
|
||||||
|
return "Fish";
|
||||||
|
if (shell.ends_with("nu"))
|
||||||
|
return "Nushell";
|
||||||
|
if (shell.ends_with("sh"))
|
||||||
|
return "SH";
|
||||||
|
|
||||||
|
return !shell.empty() ? string(shell) : "";
|
||||||
}
|
}
|
||||||
|
|
||||||
fn GetHost() -> string {
|
fn GetHost() -> string {
|
||||||
|
@ -691,4 +723,13 @@ fn GetKernelVersion() -> string {
|
||||||
return static_cast<const char*>(uts.release);
|
return static_cast<const char*>(uts.release);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn GetDiskUsage() -> pair<u64, u64> {
|
||||||
|
struct statvfs stat;
|
||||||
|
if (statvfs("/", &stat) == -1) {
|
||||||
|
ERROR_LOG("statvfs() failed: {}", strerror(errno));
|
||||||
|
return { 0, 0 };
|
||||||
|
}
|
||||||
|
return { (stat.f_blocks * stat.f_frsize) - (stat.f_bfree * stat.f_frsize), stat.f_blocks * stat.f_frsize };
|
||||||
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -8,9 +8,7 @@
|
||||||
#include <guiddef.h>
|
#include <guiddef.h>
|
||||||
#include <variant>
|
#include <variant>
|
||||||
#include <winrt/base.h>
|
#include <winrt/base.h>
|
||||||
#endif
|
#else
|
||||||
|
|
||||||
#ifdef __APPLE__
|
|
||||||
#include <variant>
|
#include <variant>
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -151,13 +149,13 @@ enum class NowPlayingCode : u8 {
|
||||||
* @brief Represents a Linux-specific error.
|
* @brief Represents a Linux-specific error.
|
||||||
*/
|
*/
|
||||||
using LinuxError = std::string;
|
using LinuxError = std::string;
|
||||||
#elif defined(__APPLE__)
|
#elifdef __APPLE__
|
||||||
/**
|
/**
|
||||||
* @typedef MacError
|
* @typedef MacError
|
||||||
* @brief Represents a macOS-specific error.
|
* @brief Represents a macOS-specific error.
|
||||||
*/
|
*/
|
||||||
using MacError = std::string;
|
using MacError = std::string;
|
||||||
#elif defined(_WIN32)
|
#elifdef _WIN32
|
||||||
/**
|
/**
|
||||||
* @typedef WindowsError
|
* @typedef WindowsError
|
||||||
* @brief Represents a Windows-specific error.
|
* @brief Represents a Windows-specific error.
|
||||||
|
@ -170,9 +168,9 @@ using NowPlayingError = std::variant<
|
||||||
NowPlayingCode,
|
NowPlayingCode,
|
||||||
#ifdef __linux__
|
#ifdef __linux__
|
||||||
LinuxError
|
LinuxError
|
||||||
#elif defined(__APPLE__)
|
#elifdef __APPLE__
|
||||||
MacError
|
MacError
|
||||||
#elif defined(_WIN32)
|
#elifdef _WIN32
|
||||||
WindowsError
|
WindowsError
|
||||||
#endif
|
#endif
|
||||||
>;
|
>;
|
||||||
|
|
Loading…
Add table
Reference in a new issue