um i think this owrks
This commit is contained in:
parent
cf51e3e569
commit
2219182539
9 changed files with 306 additions and 334 deletions
|
@ -1,8 +1,11 @@
|
|||
AlignAfterOpenBracket: BlockIndent
|
||||
AlignArrayOfStructures: Right
|
||||
AlignConsecutiveAssignments: true
|
||||
AlignConsecutiveShortCaseStatements:
|
||||
Enabled: true
|
||||
AlignConsecutiveDeclarations: true
|
||||
AllowShortBlocksOnASingleLine: Always
|
||||
AllowShortCaseLabelsOnASingleLine: true
|
||||
AllowShortEnumsOnASingleLine: true
|
||||
AllowShortFunctionsOnASingleLine: All
|
||||
AllowShortLoopsOnASingleLine: true
|
||||
|
|
73
meson.build
73
meson.build
|
@ -4,12 +4,12 @@
|
|||
project(
|
||||
'draconis++',
|
||||
'cpp',
|
||||
version: '0.1.0',
|
||||
default_options: [
|
||||
version : '0.1.0',
|
||||
default_options : [
|
||||
'default_library=static',
|
||||
'warning_level=everything',
|
||||
'buildtype=debugoptimized',
|
||||
'b_vscrt=mt',
|
||||
'warning_level=3',
|
||||
],
|
||||
)
|
||||
|
||||
|
@ -32,29 +32,34 @@ common_warning_flags = [
|
|||
]
|
||||
|
||||
common_cpp_flags = {
|
||||
'common': [
|
||||
'common' : [
|
||||
'-fno-strict-enums',
|
||||
'-fvisibility=hidden',
|
||||
'-fvisibility-inlines-hidden',
|
||||
'-std=c++26',
|
||||
],
|
||||
'msvc': [
|
||||
'msvc' : [
|
||||
'-DNOMINMAX',
|
||||
'/MT',
|
||||
'/Zc:__cplusplus',
|
||||
'/Zc:preprocessor',
|
||||
'/external:W0',
|
||||
'/external:anglebrackets',
|
||||
'/std:c++latest',
|
||||
'/w44668',
|
||||
'/w44710',
|
||||
'/w44820',
|
||||
],
|
||||
'unix_extra': [
|
||||
'unix_extra' : [
|
||||
'-march=native',
|
||||
'-nostdlib++',
|
||||
],
|
||||
'windows_extra': '-DCURL_STATICLIB',
|
||||
'windows_extra' : '-DCURL_STATICLIB',
|
||||
}
|
||||
|
||||
# Configure Objective-C++ for macOS
|
||||
if host_system == 'darwin'
|
||||
add_languages('objcpp', native: false)
|
||||
add_languages('objcpp', native : false)
|
||||
objcpp = meson.get_compiler('objcpp')
|
||||
objcpp_flags = common_warning_flags + [
|
||||
'-Wno-switch-default',
|
||||
|
@ -62,7 +67,7 @@ if host_system == 'darwin'
|
|||
'-fvisibility=hidden',
|
||||
'-fvisibility-inlines-hidden',
|
||||
]
|
||||
add_project_arguments(objcpp.get_supported_arguments(objcpp_flags), language: 'objcpp')
|
||||
add_project_arguments(objcpp.get_supported_arguments(objcpp_flags), language : 'objcpp')
|
||||
endif
|
||||
|
||||
# Apply C++ compiler arguments
|
||||
|
@ -79,7 +84,7 @@ else
|
|||
common_cpp_args = cpp.get_supported_arguments(common_cpp_args)
|
||||
endif
|
||||
|
||||
add_project_arguments(common_cpp_args, language: 'cpp')
|
||||
add_project_arguments(common_cpp_args, language : 'cpp')
|
||||
|
||||
# ------- #
|
||||
# Files #
|
||||
|
@ -87,9 +92,9 @@ add_project_arguments(common_cpp_args, language: 'cpp')
|
|||
base_sources = files('src/config/config.cpp', 'src/config/weather.cpp', 'src/main.cpp')
|
||||
|
||||
platform_sources = {
|
||||
'linux': ['src/os/linux.cpp', 'src/os/linux/issetugid_stub.cpp', 'src/os/linux/display_guards.cpp'],
|
||||
'darwin': ['src/os/macos.cpp', 'src/os/macos/bridge.mm'],
|
||||
'windows': ['src/os/windows.cpp'],
|
||||
'linux' : ['src/os/linux.cpp', 'src/os/linux/issetugid_stub.cpp', 'src/os/linux/display_guards.cpp'],
|
||||
'darwin' : ['src/os/macos.cpp', 'src/os/macos/bridge.mm'],
|
||||
'windows' : ['src/os/windows.cpp'],
|
||||
}
|
||||
|
||||
sources = base_sources + files(platform_sources.get(host_system, []))
|
||||
|
@ -98,9 +103,9 @@ sources = base_sources + files(platform_sources.get(host_system, []))
|
|||
# Dependencies Config #
|
||||
# --------------------- #
|
||||
common_deps = [
|
||||
dependency('libcurl', include_type: 'system', static: true),
|
||||
dependency('tomlplusplus', include_type: 'system', static: true),
|
||||
dependency('openssl', include_type: 'system', static: true, required: false),
|
||||
dependency('libcurl', include_type : 'system', static : true),
|
||||
dependency('tomlplusplus', include_type : 'system', static : true),
|
||||
dependency('openssl', include_type : 'system', static : true, required : false),
|
||||
]
|
||||
|
||||
# Platform-specific dependencies
|
||||
|
@ -110,8 +115,8 @@ if host_system == 'darwin'
|
|||
platform_deps += [
|
||||
dependency(
|
||||
'appleframeworks',
|
||||
modules: ['foundation', 'mediaplayer', 'systemconfiguration'],
|
||||
static: true,
|
||||
modules : ['foundation', 'mediaplayer', 'systemconfiguration'],
|
||||
static : true,
|
||||
),
|
||||
dependency('iconv'),
|
||||
]
|
||||
|
@ -128,8 +133,8 @@ elif host_system == 'linux'
|
|||
dependency('xau'),
|
||||
dependency('xdmcp'),
|
||||
dependency('wayland-client'),
|
||||
dependency('sigc++-3.0', include_type: 'system'),
|
||||
dependency('dbus-cxx', include_type: 'system'),
|
||||
dependency('sigc++-3.0', include_type : 'system'),
|
||||
dependency('dbus-cxx', include_type : 'system'),
|
||||
]
|
||||
endif
|
||||
|
||||
|
@ -137,30 +142,30 @@ endif
|
|||
ftxui_components = ['ftxui::screen', 'ftxui::dom', 'ftxui::component']
|
||||
ftxui_dep = dependency(
|
||||
'ftxui',
|
||||
modules: ftxui_components,
|
||||
include_type: 'system',
|
||||
static: true,
|
||||
required: false,
|
||||
modules : ftxui_components,
|
||||
include_type : 'system',
|
||||
static : true,
|
||||
required : false,
|
||||
)
|
||||
|
||||
if not ftxui_dep.found()
|
||||
ftxui_dep = declare_dependency(
|
||||
dependencies: [
|
||||
dependency('ftxui-dom', fallback: ['ftxui', 'dom_dep']),
|
||||
dependency('ftxui-screen', fallback: ['ftxui', 'screen_dep']),
|
||||
dependency('ftxui-component', fallback: ['ftxui', 'component_dep']),
|
||||
dependencies : [
|
||||
dependency('ftxui-dom', fallback : ['ftxui', 'dom_dep']),
|
||||
dependency('ftxui-screen', fallback : ['ftxui', 'screen_dep']),
|
||||
dependency('ftxui-component', fallback : ['ftxui', 'component_dep']),
|
||||
],
|
||||
)
|
||||
endif
|
||||
|
||||
glaze_dep = dependency('glaze', include_type: 'system', required: false)
|
||||
glaze_dep = dependency('glaze', include_type : 'system', required : false)
|
||||
|
||||
if not glaze_dep.found()
|
||||
cmake = import('cmake')
|
||||
|
||||
glaze_proj = cmake.subproject('glaze')
|
||||
|
||||
glaze_dep = glaze_proj.dependency('glaze_glaze', include_type: 'system')
|
||||
glaze_dep = glaze_proj.dependency('glaze_glaze', include_type : 'system')
|
||||
endif
|
||||
|
||||
# Combine all dependencies
|
||||
|
@ -184,8 +189,8 @@ endif
|
|||
executable(
|
||||
'draconis++',
|
||||
sources,
|
||||
objc_args: objc_args,
|
||||
link_args: link_args,
|
||||
dependencies: deps,
|
||||
install: true,
|
||||
objc_args : objc_args,
|
||||
link_args : link_args,
|
||||
dependencies : deps,
|
||||
install : true,
|
||||
)
|
||||
|
|
|
@ -1,6 +1,5 @@
|
|||
#include <cstdlib>
|
||||
#include <filesystem>
|
||||
#include <iostream>
|
||||
#include <stdexcept>
|
||||
|
||||
#include "config.h"
|
||||
|
@ -149,6 +148,8 @@ fn Config::getInstance() -> Config {
|
|||
}
|
||||
|
||||
const toml::parse_result config = toml::parse_file(configPath.string());
|
||||
|
||||
DEBUG_LOG("Config loaded from {}", configPath.string());
|
||||
return fromToml(config);
|
||||
} catch (const std::exception& e) {
|
||||
DEBUG_LOG("Config loading failed: {}, using defaults", e.what());
|
||||
|
|
31
src/main.cpp
31
src/main.cpp
|
@ -146,19 +146,19 @@ namespace {
|
|||
|
||||
// Single-threaded execution for core system info (faster on Windows)
|
||||
data.date = GetDate();
|
||||
data.host = GetHost();
|
||||
data.kernel_version = GetKernelVersion();
|
||||
data.os_version = GetOSVersion();
|
||||
data.mem_info = GetMemInfo();
|
||||
data.host = os::GetHost();
|
||||
data.kernel_version = os::GetKernelVersion();
|
||||
data.os_version = os::GetOSVersion();
|
||||
data.mem_info = os::GetMemInfo();
|
||||
|
||||
// Desktop environment info
|
||||
data.desktop_environment = GetDesktopEnvironment();
|
||||
data.window_manager = GetWindowManager();
|
||||
data.desktop_environment = os::GetDesktopEnvironment();
|
||||
data.window_manager = os::GetWindowManager();
|
||||
|
||||
// Parallel execution for disk/shell only
|
||||
auto diskShell = std::async(std::launch::async, [] {
|
||||
auto [used, total] = GetDiskUsage();
|
||||
return std::make_tuple(used, total, GetShell());
|
||||
auto [used, total] = os::GetDiskUsage();
|
||||
return std::make_tuple(used, total, os::GetShell());
|
||||
});
|
||||
|
||||
// Conditional tasks
|
||||
|
@ -169,7 +169,7 @@ namespace {
|
|||
weather = std::async(std::launch::async, [&config] { return config.weather.getWeatherInfo(); });
|
||||
|
||||
if (config.now_playing.enabled)
|
||||
nowPlaying = std::async(std::launch::async, GetNowPlaying);
|
||||
nowPlaying = std::async(std::launch::async, os::GetNowPlaying);
|
||||
|
||||
// Get remaining results
|
||||
auto [used, total, shell] = diskShell.get();
|
||||
|
@ -330,17 +330,8 @@ namespace {
|
|||
|
||||
if (std::holds_alternative<NowPlayingCode>(error))
|
||||
switch (std::get<NowPlayingCode>(error)) {
|
||||
case NowPlayingCode::NoPlayers:
|
||||
DEBUG_LOG("No players found");
|
||||
break;
|
||||
case NowPlayingCode::NoActivePlayer:
|
||||
DEBUG_LOG("No active player found");
|
||||
break;
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wcovered-switch-default"
|
||||
default:
|
||||
std::unreachable();
|
||||
#pragma clang diagnostic pop
|
||||
case NowPlayingCode::NoPlayers: DEBUG_LOG("No players found"); break;
|
||||
case NowPlayingCode::NoActivePlayer: DEBUG_LOG("No active player found"); break;
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
|
|
|
@ -219,13 +219,13 @@ namespace {
|
|||
fn DetectFromProcesses() -> Option<String> {
|
||||
// clang-format off
|
||||
const Array<Pair<StringView, StringView>, 7> processChecks = {{
|
||||
{ "plasmashell", "KDE" },
|
||||
{ "gnome-shell", "GNOME" },
|
||||
{ "xfce4-session", "XFCE" },
|
||||
{ "mate-session", "MATE" },
|
||||
{ "cinnamon-session", "Cinnamon" },
|
||||
{ "budgie-wm", "Budgie" },
|
||||
{ "lxqt-session", "LXQt" },
|
||||
{ "plasmashell", "KDE" },
|
||||
{ "gnome-shell", "GNOME" },
|
||||
{ "xfce4-session", "XFCE" },
|
||||
{ "mate-session", "MATE" },
|
||||
{ "cinnamon-session", "Cinnamon" },
|
||||
{ "budgie-wm", "Budgie" },
|
||||
{ "lxqt-session", "LXQt" },
|
||||
}};
|
||||
// clang-format on
|
||||
|
||||
|
|
84
src/os/os.h
84
src/os/os.h
|
@ -3,53 +3,55 @@
|
|||
#include "../util/macros.h"
|
||||
#include "../util/types.h"
|
||||
|
||||
/**
|
||||
* @brief Get the amount of installed RAM in bytes.
|
||||
*/
|
||||
fn GetMemInfo() -> Result<u64, String>;
|
||||
namespace os {
|
||||
/**
|
||||
* @brief Get the amount of installed RAM in bytes.
|
||||
*/
|
||||
fn GetMemInfo() -> Result<u64, String>;
|
||||
|
||||
/**
|
||||
* @brief Get the currently playing song metadata.
|
||||
*/
|
||||
fn GetNowPlaying() -> Result<String, NowPlayingError>;
|
||||
/**
|
||||
* @brief Get the currently playing song metadata.
|
||||
*/
|
||||
fn GetNowPlaying() -> Result<String, NowPlayingError>;
|
||||
|
||||
/**
|
||||
* @brief Get the OS version.
|
||||
*/
|
||||
fn GetOSVersion() -> Result<String, String>;
|
||||
/**
|
||||
* @brief Get the OS version.
|
||||
*/
|
||||
fn GetOSVersion() -> Result<String, String>;
|
||||
|
||||
/**
|
||||
* @brief Get the current desktop environment.
|
||||
*/
|
||||
fn GetDesktopEnvironment() -> Option<String>;
|
||||
/**
|
||||
* @brief Get the current desktop environment.
|
||||
*/
|
||||
fn GetDesktopEnvironment() -> Option<String>;
|
||||
|
||||
/**
|
||||
* @brief Get the current window manager.
|
||||
*/
|
||||
fn GetWindowManager() -> String;
|
||||
/**
|
||||
* @brief Get the current window manager.
|
||||
*/
|
||||
fn GetWindowManager() -> String;
|
||||
|
||||
/**
|
||||
* @brief Get the current shell.
|
||||
*/
|
||||
fn GetShell() -> String;
|
||||
/**
|
||||
* @brief Get the current shell.
|
||||
*/
|
||||
fn GetShell() -> String;
|
||||
|
||||
/**
|
||||
* @brief Get the product family
|
||||
*/
|
||||
fn GetHost() -> String;
|
||||
/**
|
||||
* @brief Get the product family
|
||||
*/
|
||||
fn GetHost() -> String;
|
||||
|
||||
/**
|
||||
* @brief Get the kernel version.
|
||||
*/
|
||||
fn GetKernelVersion() -> String;
|
||||
/**
|
||||
* @brief Get the kernel version.
|
||||
*/
|
||||
fn GetKernelVersion() -> String;
|
||||
|
||||
/**
|
||||
* @brief Get the number of installed packages.
|
||||
*/
|
||||
fn GetPackageCount() -> u64;
|
||||
/**
|
||||
* @brief Get the number of installed packages.
|
||||
*/
|
||||
fn GetPackageCount() -> u64;
|
||||
|
||||
/**
|
||||
* @brief Get the current disk usage.
|
||||
* @return std::pair<u64, u64> Used space/total space
|
||||
*/
|
||||
fn GetDiskUsage() -> Pair<u64, u64>;
|
||||
/**
|
||||
* @brief Get the current disk usage.
|
||||
* @return std::pair<u64, u64> Used space/total space
|
||||
*/
|
||||
fn GetDiskUsage() -> Pair<u64, u64>;
|
||||
}
|
|
@ -9,20 +9,57 @@
|
|||
// clang-format on
|
||||
|
||||
#include <cstring>
|
||||
#include <guiddef.h>
|
||||
#include <ranges>
|
||||
#include <winrt/Windows.Foundation.h>
|
||||
#include <winrt/Windows.Media.Control.h>
|
||||
#include <winrt/Windows.Storage.h>
|
||||
#include <winrt/Windows.System.Diagnostics.h>
|
||||
#include <winrt/Windows.System.Profile.h>
|
||||
#include <winrt/base.h>
|
||||
#include <winrt/impl/Windows.Media.Control.2.h>
|
||||
|
||||
#include "os.h"
|
||||
|
||||
using RtlGetVersionPtr = NTSTATUS(WINAPI*)(PRTL_OSVERSIONINFOW);
|
||||
|
||||
// NOLINTBEGIN(*-pro-type-cstyle-cast,*-no-int-to-ptr,*-pro-type-reinterpret-cast)
|
||||
namespace {
|
||||
struct OSVersion {
|
||||
u16 major;
|
||||
u16 minor;
|
||||
u16 build;
|
||||
u16 revision;
|
||||
|
||||
static fn parseDeviceFamilyVersion(const winrt::hstring& versionString) -> OSVersion {
|
||||
try {
|
||||
const u64 versionUl = std::stoull(winrt::to_string(versionString));
|
||||
return {
|
||||
.major = static_cast<u16>((versionUl >> 48) & 0xFFFF),
|
||||
.minor = static_cast<u16>((versionUl >> 32) & 0xFFFF),
|
||||
.build = static_cast<u16>((versionUl >> 16) & 0xFFFF),
|
||||
.revision = static_cast<u16>(versionUl & 0xFFFF),
|
||||
};
|
||||
} catch (const std::invalid_argument& e) {
|
||||
ERROR_LOG("Invalid argument: {}", e.what());
|
||||
} catch (const std::out_of_range& e) {
|
||||
ERROR_LOG("Value out of range: {}", e.what());
|
||||
} catch (const winrt::hresult_error& e) { ERROR_LOG("Windows error: {}", winrt::to_string(e.message())); }
|
||||
|
||||
return { .major = 0, .minor = 0, .build = 0, .revision = 0 };
|
||||
}
|
||||
};
|
||||
|
||||
// clang-format off
|
||||
constexpr Array<Pair<StringView, StringView>, 3> windowsShellMap = {{
|
||||
{ "cmd", "Command Prompt" },
|
||||
{ "powershell", "PowerShell" },
|
||||
{ "pwsh", "PowerShell Core" },
|
||||
}};
|
||||
|
||||
constexpr Array<Pair<StringView, StringView>, 3> msysShellMap = {{
|
||||
{ "bash", "Bash" },
|
||||
{ "zsh", "Zsh" },
|
||||
{ "fish", "Fish" },
|
||||
}};
|
||||
// clang-format on
|
||||
|
||||
class ProcessSnapshot {
|
||||
public:
|
||||
ProcessSnapshot() : h_snapshot(CreateToolhelp32Snapshot(TH32CS_SNAPPROCESS, 0)) {}
|
||||
|
@ -39,8 +76,8 @@ namespace {
|
|||
|
||||
[[nodiscard]] fn isValid() const -> bool { return h_snapshot != INVALID_HANDLE_VALUE; }
|
||||
|
||||
[[nodiscard]] fn getProcesses() const -> std::vector<std::pair<DWORD, String>> {
|
||||
std::vector<std::pair<DWORD, String>> processes;
|
||||
[[nodiscard]] fn getProcesses() const -> Vec<Pair<DWORD, String>> {
|
||||
Vec<Pair<DWORD, String>> processes;
|
||||
|
||||
if (!isValid())
|
||||
return processes;
|
||||
|
@ -51,12 +88,9 @@ namespace {
|
|||
if (!Process32First(h_snapshot, &pe32))
|
||||
return processes;
|
||||
|
||||
// Get first process
|
||||
if (Process32First(h_snapshot, &pe32)) {
|
||||
// Add first process to vector
|
||||
processes.emplace_back(pe32.th32ProcessID, String(reinterpret_cast<const char*>(pe32.szExeFile)));
|
||||
|
||||
// Add remaining processes
|
||||
while (Process32Next(h_snapshot, &pe32))
|
||||
processes.emplace_back(pe32.th32ProcessID, String(reinterpret_cast<const char*>(pe32.szExeFile)));
|
||||
}
|
||||
|
@ -79,10 +113,9 @@ namespace {
|
|||
return "";
|
||||
}
|
||||
|
||||
// For string values, allocate one less byte to avoid the null terminator
|
||||
String value((type == REG_SZ || type == REG_EXPAND_SZ) ? dataSize - 1 : dataSize, '\0');
|
||||
|
||||
if (RegQueryValueExA(key, valueName.c_str(), nullptr, nullptr, std::bit_cast<LPBYTE>(value.data()), &dataSize) !=
|
||||
if (RegQueryValueExA(key, valueName.c_str(), nullptr, nullptr, reinterpret_cast<LPBYTE>(value.data()), &dataSize) !=
|
||||
ERROR_SUCCESS) {
|
||||
RegCloseKey(key);
|
||||
return "";
|
||||
|
@ -92,12 +125,12 @@ namespace {
|
|||
return value;
|
||||
}
|
||||
|
||||
fn GetProcessInfo() -> std::vector<std::pair<DWORD, String>> {
|
||||
fn GetProcessInfo() -> Vec<Pair<DWORD, String>> {
|
||||
const ProcessSnapshot snapshot;
|
||||
return snapshot.isValid() ? snapshot.getProcesses() : std::vector<std::pair<DWORD, String>> {};
|
||||
}
|
||||
|
||||
fn IsProcessRunning(const std::vector<String>& processes, const String& name) -> bool {
|
||||
fn IsProcessRunning(const Vec<String>& processes, const String& name) -> bool {
|
||||
return std::ranges::any_of(processes, [&name](const String& proc) -> bool {
|
||||
return _stricmp(proc.c_str(), name.c_str()) == 0;
|
||||
});
|
||||
|
@ -143,139 +176,130 @@ namespace {
|
|||
|
||||
return "";
|
||||
}
|
||||
|
||||
template <usize sz>
|
||||
fn FindShellInProcessTree(const DWORD startPid, const Array<Pair<StringView, StringView>, sz>& shellMap)
|
||||
-> std::optional<String> {
|
||||
DWORD pid = startPid;
|
||||
while (pid != 0) {
|
||||
String processName = GetProcessName(pid);
|
||||
|
||||
if (processName.empty()) {
|
||||
pid = GetParentProcessId(pid);
|
||||
continue;
|
||||
}
|
||||
|
||||
std::ranges::transform(processName, processName.begin(), [](const u8 character) {
|
||||
return static_cast<char>(std::tolower(static_cast<unsigned char>(character)));
|
||||
});
|
||||
|
||||
if (processName.length() > 4 && processName.substr(processName.length() - 4) == ".exe")
|
||||
processName.resize(processName.length() - 4);
|
||||
|
||||
auto iter = std::ranges::find_if(shellMap, [&](const auto& pair) {
|
||||
return std::string_view { processName } == pair.first;
|
||||
});
|
||||
|
||||
if (iter != std::ranges::end(shellMap))
|
||||
return String { iter->second };
|
||||
|
||||
pid = GetParentProcessId(pid);
|
||||
}
|
||||
|
||||
return std::nullopt;
|
||||
}
|
||||
|
||||
fn GetBuildNumber() -> Option<u64> {
|
||||
try {
|
||||
using namespace winrt::Windows::System::Profile;
|
||||
const auto versionInfo = AnalyticsInfo::VersionInfo();
|
||||
const winrt::hstring familyVersion = versionInfo.DeviceFamilyVersion();
|
||||
|
||||
if (!familyVersion.empty()) {
|
||||
const u64 versionUl = std::stoull(winrt::to_string(familyVersion));
|
||||
return (versionUl >> 16) & 0xFFFF;
|
||||
}
|
||||
} catch (const winrt::hresult_error& e) {
|
||||
DEBUG_LOG("WinRT error getting build number: {}", winrt::to_string(e.message()));
|
||||
} catch (const Exception& e) { DEBUG_LOG("Standard exception getting build number: {}", e.what()); }
|
||||
|
||||
return None;
|
||||
}
|
||||
}
|
||||
|
||||
fn GetMemInfo() -> Result<u64, String> {
|
||||
fn os::GetMemInfo() -> Result<u64, String> {
|
||||
try {
|
||||
using namespace winrt::Windows::System::Diagnostics;
|
||||
const SystemDiagnosticInfo diag = SystemDiagnosticInfo::GetForCurrentSystem();
|
||||
return diag.MemoryUsage().GetReport().TotalPhysicalSizeInBytes();
|
||||
return winrt::Windows::System::Diagnostics::SystemDiagnosticInfo::GetForCurrentSystem()
|
||||
.MemoryUsage()
|
||||
.GetReport()
|
||||
.TotalPhysicalSizeInBytes();
|
||||
} catch (const winrt::hresult_error& e) {
|
||||
return Err(std::format("Failed to get memory info: {}", to_string(e.message())));
|
||||
}
|
||||
}
|
||||
|
||||
fn GetNowPlaying() -> Result<String, NowPlayingError> {
|
||||
fn os::GetNowPlaying() -> Result<String, NowPlayingError> {
|
||||
using namespace winrt::Windows::Media::Control;
|
||||
using namespace winrt::Windows::Foundation;
|
||||
|
||||
using MediaProperties = GlobalSystemMediaTransportControlsSessionMediaProperties;
|
||||
using Session = GlobalSystemMediaTransportControlsSession;
|
||||
using SessionManager = GlobalSystemMediaTransportControlsSessionManager;
|
||||
using Session = GlobalSystemMediaTransportControlsSession;
|
||||
using SessionManager = GlobalSystemMediaTransportControlsSessionManager;
|
||||
|
||||
try {
|
||||
// Request the session manager asynchronously
|
||||
const IAsyncOperation<SessionManager> sessionManagerOp = SessionManager::RequestAsync();
|
||||
const SessionManager sessionManager = sessionManagerOp.get();
|
||||
|
||||
if (const Session currentSession = sessionManager.GetCurrentSession()) {
|
||||
// Try to get the media properties asynchronously
|
||||
const MediaProperties mediaProperties = currentSession.TryGetMediaPropertiesAsync().get();
|
||||
if (const Session currentSession = sessionManager.GetCurrentSession())
|
||||
return winrt::to_string(currentSession.TryGetMediaPropertiesAsync().get().Title());
|
||||
|
||||
// Convert the hstring title to string
|
||||
return to_string(mediaProperties.Title());
|
||||
}
|
||||
|
||||
// If we reach this point, there is no current session
|
||||
return Err(NowPlayingCode::NoActivePlayer);
|
||||
} catch (const winrt::hresult_error& e) { return Err(e); }
|
||||
}
|
||||
|
||||
fn GetOSVersion() -> Result<String, String> {
|
||||
constexpr OSVERSIONINFOEXW osvi = { sizeof(OSVERSIONINFOEXW), 0, 0, 0, 0, { 0 }, 0, 0, 0, 0, 0 };
|
||||
NTSTATUS status = 0;
|
||||
fn os::GetOSVersion() -> Result<String, String> {
|
||||
try {
|
||||
const String regSubKey = R"(SOFTWARE\Microsoft\Windows NT\CurrentVersion)";
|
||||
|
||||
if (const HMODULE ntdllHandle = GetModuleHandleW(L"ntdll.dll"))
|
||||
if (const auto rtlGetVersion = std::bit_cast<RtlGetVersionPtr>(GetProcAddress(ntdllHandle, "RtlGetVersion")))
|
||||
status = rtlGetVersion(std::bit_cast<PRTL_OSVERSIONINFOW>(&osvi));
|
||||
String productName = GetRegistryValue(HKEY_LOCAL_MACHINE, regSubKey, "ProductName");
|
||||
const String displayVersion = GetRegistryValue(HKEY_LOCAL_MACHINE, regSubKey, "DisplayVersion");
|
||||
|
||||
String productName;
|
||||
String edition;
|
||||
if (productName.empty())
|
||||
return Err("Failed to read ProductName");
|
||||
|
||||
if (status == 0) {
|
||||
DWORD productType = 0;
|
||||
if (GetProductInfo(
|
||||
osvi.dwMajorVersion, osvi.dwMinorVersion, osvi.wServicePackMajor, osvi.wServicePackMinor, &productType
|
||||
)) {
|
||||
if (osvi.dwMajorVersion == 10) {
|
||||
if (osvi.dwBuildNumber >= 22000)
|
||||
productName = "Windows 11";
|
||||
else
|
||||
productName = "Windows 10";
|
||||
if (const Option<u64> buildNumber = GetBuildNumber()) {
|
||||
if (*buildNumber >= 22000)
|
||||
if (const usize pos = productName.find("Windows 10");
|
||||
pos != String::npos && (pos == 0 || !isalnum(static_cast<u8>(productName[pos - 1]))) &&
|
||||
(pos + 10 == productName.length() || !isalnum(static_cast<u8>(productName[pos + 10]))))
|
||||
productName.replace(pos, 10, "Windows 11");
|
||||
} else
|
||||
DEBUG_LOG("Warning: Could not get build number via WinRT; Win11 patch relies on registry ProductName only.");
|
||||
|
||||
switch (productType) {
|
||||
case PRODUCT_PROFESSIONAL:
|
||||
edition = " Pro";
|
||||
break;
|
||||
case PRODUCT_ENTERPRISE:
|
||||
edition = " Enterprise";
|
||||
break;
|
||||
case PRODUCT_EDUCATION:
|
||||
edition = " Education";
|
||||
break;
|
||||
case PRODUCT_HOME_BASIC:
|
||||
case PRODUCT_HOME_PREMIUM:
|
||||
edition = " Home";
|
||||
break;
|
||||
case PRODUCT_CLOUDEDITION:
|
||||
edition = " Cloud";
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
productName =
|
||||
GetRegistryValue(HKEY_LOCAL_MACHINE, R"(SOFTWARE\Microsoft\Windows NT\CurrentVersion)", "ProductName");
|
||||
|
||||
if (const i32 buildNumber = stoi(
|
||||
GetRegistryValue(HKEY_LOCAL_MACHINE, R"(SOFTWARE\Microsoft\Windows NT\CurrentVersion)", "CurrentBuildNumber")
|
||||
);
|
||||
buildNumber >= 22000 && productName.find("Windows 10") != String::npos)
|
||||
productName.replace(productName.find("Windows 10"), 10, "Windows 11");
|
||||
}
|
||||
|
||||
if (!productName.empty()) {
|
||||
String result = productName + edition;
|
||||
|
||||
const String displayVersion =
|
||||
GetRegistryValue(HKEY_LOCAL_MACHINE, R"(SOFTWARE\Microsoft\Windows NT\CurrentVersion)", "DisplayVersion");
|
||||
|
||||
if (!displayVersion.empty())
|
||||
result += " " + displayVersion;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
return "Windows";
|
||||
return displayVersion.empty() ? productName : productName + " " + displayVersion;
|
||||
} catch (const Exception& e) { return Err(std::format("Exception occurred getting OS version: {}", e.what())); }
|
||||
}
|
||||
|
||||
fn GetHost() -> String {
|
||||
String hostName = GetRegistryValue(HKEY_LOCAL_MACHINE, R"(SYSTEM\HardwareConfig\Current)", "SystemFamily");
|
||||
|
||||
return hostName;
|
||||
fn os::GetHost() -> String {
|
||||
return GetRegistryValue(HKEY_LOCAL_MACHINE, R"(SYSTEM\HardwareConfig\Current)", "SystemFamily");
|
||||
}
|
||||
|
||||
fn GetKernelVersion() -> String {
|
||||
// ReSharper disable once CppLocalVariableMayBeConst
|
||||
if (HMODULE ntdllHandle = GetModuleHandleW(L"ntdll.dll")) {
|
||||
if (const auto rtlGetVersion = std::bit_cast<RtlGetVersionPtr>(GetProcAddress(ntdllHandle, "RtlGetVersion"))) {
|
||||
RTL_OSVERSIONINFOW osInfo = {};
|
||||
osInfo.dwOSVersionInfoSize = sizeof(osInfo);
|
||||
fn os::GetKernelVersion() -> String {
|
||||
try {
|
||||
using namespace winrt::Windows::System::Profile;
|
||||
|
||||
if (rtlGetVersion(&osInfo) == 0) {
|
||||
return std::format(
|
||||
"{}.{}.{}.{}", osInfo.dwMajorVersion, osInfo.dwMinorVersion, osInfo.dwBuildNumber, osInfo.dwPlatformId
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
const AnalyticsVersionInfo versionInfo = AnalyticsInfo::VersionInfo();
|
||||
|
||||
if (const winrt::hstring familyVersion = versionInfo.DeviceFamilyVersion(); !familyVersion.empty())
|
||||
if (auto [major, minor, build, revision] = OSVersion::parseDeviceFamilyVersion(familyVersion); build > 0)
|
||||
return std::format("{}.{}.{}.{}", major, minor, build, revision);
|
||||
} catch (const winrt::hresult_error& e) {
|
||||
ERROR_LOG("WinRT error: {}", winrt::to_string(e.message()));
|
||||
} catch (const Exception& e) { ERROR_LOG("Failed to get kernel version: {}", e.what()); }
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
fn GetWindowManager() -> String {
|
||||
fn os::GetWindowManager() -> String {
|
||||
const auto processInfo = GetProcessInfo();
|
||||
std::vector<String> processNames;
|
||||
|
||||
|
@ -300,7 +324,7 @@ fn GetWindowManager() -> String {
|
|||
return "Windows Manager";
|
||||
}
|
||||
|
||||
fn GetDesktopEnvironment() -> Option<String> {
|
||||
fn os::GetDesktopEnvironment() -> Option<String> {
|
||||
const String buildStr =
|
||||
GetRegistryValue(HKEY_LOCAL_MACHINE, R"(SOFTWARE\Microsoft\Windows NT\CurrentVersion)", "CurrentBuildNumber");
|
||||
|
||||
|
@ -347,97 +371,45 @@ fn GetDesktopEnvironment() -> Option<String> {
|
|||
}
|
||||
}
|
||||
|
||||
fn GetShell() -> String {
|
||||
// TODO: update this to use GetEnv
|
||||
fn os::GetShell() -> String {
|
||||
const DWORD currentPid = GetCurrentProcessId();
|
||||
|
||||
const std::unordered_map<String, String> knownShells = {
|
||||
{ "cmd.exe", "Command Prompt" },
|
||||
{ "powershell.exe", "PowerShell" },
|
||||
{ "pwsh.exe", "PowerShell Core" },
|
||||
{ "windowsterminal.exe", "Windows Terminal" },
|
||||
{ "mintty.exe", "Mintty" },
|
||||
{ "bash.exe", "Windows Subsystem for Linux" }
|
||||
};
|
||||
if (const Result<String, EnvError> msystemResult = GetEnv("MSYSTEM")) {
|
||||
String shellPath;
|
||||
if (const Result<String, EnvError> shellResult = GetEnv("SHELL"); !shellResult->empty())
|
||||
shellPath = *shellResult;
|
||||
else if (const Result<String, EnvError> loginShellResult = GetEnv("LOGINSHELL"); !loginShellResult->empty())
|
||||
shellPath = *loginShellResult;
|
||||
|
||||
char* msystemEnv = nullptr;
|
||||
if (_dupenv_s(&msystemEnv, nullptr, "MSYSTEM") == 0 && msystemEnv != nullptr) {
|
||||
const std::unique_ptr<char, decltype(&free)> msystemEnvGuard(msystemEnv, free);
|
||||
if (!shellPath.empty()) {
|
||||
const usize lastSlash = shellPath.find_last_of("\\/");
|
||||
String shellExe = (lastSlash != String::npos) ? shellPath.substr(lastSlash + 1) : shellPath;
|
||||
|
||||
char* shell = nullptr;
|
||||
size_t shellLen = 0;
|
||||
_dupenv_s(&shell, &shellLen, "SHELL");
|
||||
const std::unique_ptr<char, decltype(&free)> shellGuard(shell, free);
|
||||
std::ranges::transform(shellExe, shellExe.begin(), [](const u8 c) { return std::tolower(c); });
|
||||
|
||||
if (!shell || strlen(shell) == 0) {
|
||||
char* loginShell = nullptr;
|
||||
size_t loginShellLen = 0;
|
||||
_dupenv_s(&loginShell, &loginShellLen, "LOGINSHELL");
|
||||
const std::unique_ptr<char, decltype(&free)> loginShellGuard(loginShell, free);
|
||||
shell = loginShell;
|
||||
if (shellExe.ends_with(".exe"))
|
||||
shellExe.resize(shellExe.length() - 4);
|
||||
|
||||
const auto iter =
|
||||
std::ranges::find_if(msysShellMap, [&](const auto& pair) { return StringView { shellExe } == pair.first; });
|
||||
|
||||
if (iter != std::ranges::end(msysShellMap))
|
||||
return String { iter->second };
|
||||
}
|
||||
|
||||
if (shell) {
|
||||
String shellExe;
|
||||
const String shellPath = shell;
|
||||
const size_t lastSlash = shellPath.find_last_of("\\/");
|
||||
shellExe = (lastSlash != String::npos) ? shellPath.substr(lastSlash + 1) : shellPath;
|
||||
std::ranges::transform(shellExe, shellExe.begin(), ::tolower);
|
||||
if (const Option<String> msysShell = FindShellInProcessTree(currentPid, msysShellMap))
|
||||
return *msysShell;
|
||||
|
||||
// Use a map for shell name lookup instead of multiple if statements
|
||||
const std::unordered_map<StringView, String> shellNames = {
|
||||
{ "bash", "Bash" },
|
||||
{ "zsh", "Zsh" },
|
||||
{ "fish", "Fish" }
|
||||
};
|
||||
|
||||
for (const auto& [pattern, name] : shellNames) {
|
||||
if (shellExe.find(pattern) != String::npos)
|
||||
return name;
|
||||
}
|
||||
|
||||
return shellExe.empty() ? "MSYS2" : "MSYS2/" + shellExe;
|
||||
}
|
||||
|
||||
const auto processInfo = GetProcessInfo();
|
||||
DWORD pid = GetCurrentProcessId();
|
||||
|
||||
while (pid != 0) {
|
||||
String processName = GetProcessName(pid);
|
||||
std::ranges::transform(processName, processName.begin(), ::tolower);
|
||||
|
||||
const std::unordered_map<String, String> msysShells = {
|
||||
{ "bash.exe", "Bash" },
|
||||
{ "zsh.exe", "Zsh" },
|
||||
{ "fish.exe", "Fish" },
|
||||
{ "mintty.exe", "Mintty" }
|
||||
};
|
||||
|
||||
for (const auto& [msysShellExe, shellName] : msysShells) {
|
||||
if (processName == msysShellExe)
|
||||
return shellName;
|
||||
}
|
||||
|
||||
pid = GetParentProcessId(pid);
|
||||
}
|
||||
|
||||
return "MSYS2";
|
||||
return "MSYS2 Environment";
|
||||
}
|
||||
|
||||
DWORD pid = GetCurrentProcessId();
|
||||
while (pid != 0) {
|
||||
String processName = GetProcessName(pid);
|
||||
std::ranges::transform(processName, processName.begin(), ::tolower);
|
||||
if (const Option<String> windowsShell = FindShellInProcessTree(currentPid, windowsShellMap))
|
||||
return *windowsShell;
|
||||
|
||||
if (auto shellIterator = knownShells.find(processName); shellIterator != knownShells.end())
|
||||
return shellIterator->second;
|
||||
|
||||
pid = GetParentProcessId(pid);
|
||||
}
|
||||
|
||||
return "Windows Console";
|
||||
return "Unknown Shell";
|
||||
}
|
||||
|
||||
fn GetDiskUsage() -> std::pair<u64, u64> {
|
||||
fn os::GetDiskUsage() -> Pair<u64, u64> {
|
||||
ULARGE_INTEGER freeBytes, totalBytes;
|
||||
|
||||
if (GetDiskFreeSpaceExW(L"C:\\", nullptr, &totalBytes, &freeBytes))
|
||||
|
@ -445,6 +417,5 @@ fn GetDiskUsage() -> std::pair<u64, u64> {
|
|||
|
||||
return { 0, 0 };
|
||||
}
|
||||
// NOLINTEND(*-pro-type-cstyle-cast,*-no-int-to-ptr,*-pro-type-reinterpret-cast)
|
||||
|
||||
#endif
|
||||
|
|
|
@ -17,9 +17,10 @@
|
|||
|
||||
#ifdef None
|
||||
#undef None
|
||||
#define None std::nullopt
|
||||
#endif
|
||||
|
||||
#define None std::nullopt
|
||||
|
||||
namespace term {
|
||||
enum class Emphasis : u8 { none = 0, bold = 1, italic = 2 };
|
||||
|
||||
|
@ -49,16 +50,14 @@ namespace term {
|
|||
struct FgColor {
|
||||
Color col;
|
||||
|
||||
constexpr explicit FgColor(Color color) : col(color) {}
|
||||
constexpr explicit FgColor(const Color color) : col(color) {}
|
||||
|
||||
[[nodiscard]] fn ansiCode() const -> String { return std::format("\033[{}m", static_cast<int>(col)); }
|
||||
};
|
||||
|
||||
constexpr fn Fg(Color color) -> FgColor { return FgColor(color); }
|
||||
|
||||
struct Style {
|
||||
Emphasis emph = Emphasis::none;
|
||||
FgColor fg_col = FgColor(static_cast<Color>(-1)); // Invalid color
|
||||
FgColor fg_col = FgColor(static_cast<Color>(-1));
|
||||
|
||||
[[nodiscard]] fn ansiCode() const -> String {
|
||||
String result;
|
||||
|
@ -77,8 +76,13 @@ namespace term {
|
|||
}
|
||||
};
|
||||
|
||||
constexpr fn operator|(Emphasis emph, FgColor fgColor)->Style { return { .emph = emph, .fg_col = fgColor }; }
|
||||
constexpr fn operator|(FgColor fgColor, Emphasis emph)->Style { return { .emph = emph, .fg_col = fgColor }; }
|
||||
constexpr fn operator|(const Emphasis emph, const FgColor fgColor)->Style {
|
||||
return { .emph = emph, .fg_col = fgColor };
|
||||
}
|
||||
|
||||
constexpr fn operator|(const FgColor fgColor, const Emphasis emph)->Style {
|
||||
return { .emph = emph, .fg_col = fgColor };
|
||||
}
|
||||
|
||||
constexpr CStr reset = "\033[0m";
|
||||
|
||||
|
@ -122,19 +126,11 @@ fn LogImpl(const LogLevel level, const std::source_location& loc, std::format_st
|
|||
|
||||
const auto [color, levelStr] = [&] {
|
||||
switch (level) {
|
||||
case LogLevel::DEBUG:
|
||||
return std::make_pair(log_colors::debug, "DEBUG");
|
||||
case LogLevel::INFO:
|
||||
return std::make_pair(log_colors::info, "INFO ");
|
||||
case LogLevel::WARN:
|
||||
return std::make_pair(log_colors::warn, "WARN ");
|
||||
case LogLevel::ERROR:
|
||||
return std::make_pair(log_colors::error, "ERROR");
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wcovered-switch-default"
|
||||
default:
|
||||
std::unreachable();
|
||||
#pragma clang diagnostic pop
|
||||
case LogLevel::DEBUG: return std::make_pair(log_colors::debug, "DEBUG");
|
||||
case LogLevel::INFO: return std::make_pair(log_colors::info, "INFO ");
|
||||
case LogLevel::WARN: return std::make_pair(log_colors::warn, "WARN ");
|
||||
case LogLevel::ERROR: return std::make_pair(log_colors::error, "ERROR");
|
||||
default: std::unreachable();
|
||||
}
|
||||
}();
|
||||
|
||||
|
@ -142,20 +138,22 @@ fn LogImpl(const LogLevel level, const std::source_location& loc, std::format_st
|
|||
|
||||
using namespace term;
|
||||
|
||||
Print(Fg(log_colors::timestamp), "[{:%H:%M:%S}] ", now);
|
||||
Print(Emphasis::bold | Fg(color), "{} ", levelStr);
|
||||
Print(FgColor(log_colors::timestamp), "[{:%H:%M:%S}] ", now);
|
||||
Print(Emphasis::bold | FgColor(color), "{} ", levelStr);
|
||||
Print(fmt, std::forward<Args>(args)...);
|
||||
|
||||
#ifndef NDEBUG
|
||||
Print(Fg(log_colors::file_info), "\n{:>14} ", "╰──");
|
||||
Print(Emphasis::italic | Fg(log_colors::file_info), "{}:{}", filename, loc.line());
|
||||
Print(FgColor(log_colors::file_info), "\n{:>14} ", "╰──");
|
||||
Print(Emphasis::italic | FgColor(log_colors::file_info), "{}:{}", filename, loc.line());
|
||||
#endif
|
||||
|
||||
Print("\n");
|
||||
}
|
||||
|
||||
#ifdef __clang__
|
||||
#pragma clang diagnostic push
|
||||
#pragma clang diagnostic ignored "-Wunused-macros"
|
||||
#endif
|
||||
#ifdef NDEBUG
|
||||
#define DEBUG_LOG(...) static_cast<void>(0)
|
||||
#else
|
||||
|
@ -164,4 +162,6 @@ fn LogImpl(const LogLevel level, const std::source_location& loc, std::format_st
|
|||
#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 ERROR_LOG(...) LogImpl(LogLevel::ERROR, std::source_location::current(), __VA_ARGS__)
|
||||
#ifdef __clang__
|
||||
#pragma clang diagnostic pop
|
||||
#endif
|
||||
|
|
|
@ -1,15 +1,12 @@
|
|||
#pragma once
|
||||
|
||||
#include <array>
|
||||
#include <cstddef>
|
||||
#include <cstdint>
|
||||
#include <cstdlib>
|
||||
#include <expected>
|
||||
#include <map>
|
||||
#include <memory>
|
||||
#include <optional>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include <utility>
|
||||
#include <vector>
|
||||
|
||||
|
@ -183,8 +180,8 @@ using Option = std::optional<Tp>;
|
|||
* @typedef Array
|
||||
* @brief Represents a fixed-size array.
|
||||
*/
|
||||
template <typename Tp, std::size_t nm>
|
||||
using Array = std::array<Tp, nm>;
|
||||
template <typename Tp, usize sz>
|
||||
using Array = std::array<Tp, sz>;
|
||||
|
||||
/**
|
||||
* @typedef Vec
|
||||
|
@ -264,18 +261,20 @@ enum class EnvError : u8 { NotFound, AccessError };
|
|||
|
||||
inline auto GetEnv(const String& name) -> Result<String, EnvError> {
|
||||
#ifdef _WIN32
|
||||
char* rawPtr = nullptr;
|
||||
size_t bufferSize = 0;
|
||||
char* rawPtr = nullptr;
|
||||
usize bufferSize = 0;
|
||||
|
||||
if (_dupenv_s(&rawPtr, &bufferSize, name.c_str()) != 0)
|
||||
return std::unexpected(EnvError::AccessError);
|
||||
const i32 err = _dupenv_s(&rawPtr, &bufferSize, name.c_str());
|
||||
|
||||
if (!rawPtr)
|
||||
return std::unexpected(EnvError::NotFound);
|
||||
const UniquePointer<char, decltype(&free)> ptrManager(rawPtr, free);
|
||||
|
||||
const String result(rawPtr);
|
||||
free(rawPtr);
|
||||
return result;
|
||||
if (err != 0)
|
||||
return Err(EnvError::AccessError);
|
||||
|
||||
if (!ptrManager)
|
||||
return Err(EnvError::NotFound);
|
||||
|
||||
return ptrManager.get();
|
||||
#else
|
||||
CStr value = std::getenv(name.c_str());
|
||||
|
||||
|
|
Loading…
Add table
Reference in a new issue