stuf
This commit is contained in:
parent
013ecdda58
commit
3f4e26ec0f
19 changed files with 3244 additions and 427 deletions
|
@ -13,10 +13,11 @@ AlignConsecutiveShortCaseStatements:
|
||||||
AlignOperands: DontAlign
|
AlignOperands: DontAlign
|
||||||
AllowShortBlocksOnASingleLine: Always
|
AllowShortBlocksOnASingleLine: Always
|
||||||
AllowShortCaseLabelsOnASingleLine: true
|
AllowShortCaseLabelsOnASingleLine: true
|
||||||
AllowShortFunctionsOnASingleLine: All
|
AllowShortFunctionsOnASingleLine: Empty
|
||||||
AllowShortLoopsOnASingleLine: true
|
AllowShortLoopsOnASingleLine: true
|
||||||
BinPackArguments: false
|
BinPackArguments: false
|
||||||
ColumnLimit: 120
|
BreakBeforeBraces: Attach
|
||||||
|
ColumnLimit: 0
|
||||||
ConstructorInitializerIndentWidth: 2
|
ConstructorInitializerIndentWidth: 2
|
||||||
ContinuationIndentWidth: 2
|
ContinuationIndentWidth: 2
|
||||||
Cpp11BracedListStyle: false
|
Cpp11BracedListStyle: false
|
||||||
|
|
2582
include/argparse.hpp
Normal file
2582
include/argparse.hpp
Normal file
File diff suppressed because it is too large
Load diff
|
@ -40,7 +40,8 @@ namespace matchit {
|
||||||
|
|
||||||
public:
|
public:
|
||||||
template <typename V>
|
template <typename V>
|
||||||
constexpr explicit MatchHelper(V&& value) : mValue { std::forward<V>(value) } {}
|
constexpr explicit MatchHelper(V&& value)
|
||||||
|
: mValue { std::forward<V>(value) } {}
|
||||||
template <typename... PatternPair>
|
template <typename... PatternPair>
|
||||||
constexpr auto operator()(const PatternPair&... patterns) {
|
constexpr auto operator()(const PatternPair&... patterns) {
|
||||||
return matchPatterns(std::forward<ValueRefT>(mValue), patterns...);
|
return matchPatterns(std::forward<ValueRefT>(mValue), patterns...);
|
||||||
|
@ -116,14 +117,18 @@ namespace matchit {
|
||||||
template <typename T>
|
template <typename T>
|
||||||
class EvalTraits<Nullary<T>> {
|
class EvalTraits<Nullary<T>> {
|
||||||
public:
|
public:
|
||||||
constexpr static decltype(auto) evalImpl(const Nullary<T>& e) { return e(); }
|
constexpr static decltype(auto) evalImpl(const Nullary<T>& e) {
|
||||||
|
return e();
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// Only allowed in nullary
|
// Only allowed in nullary
|
||||||
template <typename T>
|
template <typename T>
|
||||||
class EvalTraits<Id<T>> {
|
class EvalTraits<Id<T>> {
|
||||||
public:
|
public:
|
||||||
constexpr static decltype(auto) evalImpl(const Id<T>& id) { return *const_cast<Id<T>&>(id); }
|
constexpr static decltype(auto) evalImpl(const Id<T>& id) {
|
||||||
|
return *const_cast<Id<T>&>(id);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename Pred>
|
template <typename Pred>
|
||||||
|
@ -283,9 +288,11 @@ namespace matchit {
|
||||||
S mEnd;
|
S mEnd;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
constexpr Subrange(const I begin, const S end) : mBegin { begin }, mEnd { end } {}
|
constexpr Subrange(const I begin, const S end)
|
||||||
|
: mBegin { begin }, mEnd { end } {}
|
||||||
|
|
||||||
constexpr Subrange(const Subrange& other) : mBegin { other.begin() }, mEnd { other.end() } {}
|
constexpr Subrange(const Subrange& other)
|
||||||
|
: mBegin { other.begin() }, mEnd { other.end() } {}
|
||||||
|
|
||||||
Subrange& operator=(const Subrange& other) {
|
Subrange& operator=(const Subrange& other) {
|
||||||
mBegin = other.begin();
|
mBegin = other.begin();
|
||||||
|
@ -293,9 +300,15 @@ namespace matchit {
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
size_t size() const { return static_cast<size_t>(std::distance(mBegin, mEnd)); }
|
size_t size() const {
|
||||||
auto begin() const { return mBegin; }
|
return static_cast<size_t>(std::distance(mBegin, mEnd));
|
||||||
auto end() const { return mEnd; }
|
}
|
||||||
|
auto begin() const {
|
||||||
|
return mBegin;
|
||||||
|
}
|
||||||
|
auto end() const {
|
||||||
|
return mEnd;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename I, typename S>
|
template <typename I, typename S>
|
||||||
|
@ -465,7 +478,8 @@ namespace matchit {
|
||||||
using RetType = std::common_type_t<typename PatternPairs::RetType...>;
|
using RetType = std::common_type_t<typename PatternPairs::RetType...>;
|
||||||
};
|
};
|
||||||
|
|
||||||
enum class IdProcess : int32_t { kCANCEL, kCONFIRM };
|
enum class IdProcess : int32_t { kCANCEL,
|
||||||
|
kCONFIRM };
|
||||||
|
|
||||||
template <typename Pattern>
|
template <typename Pattern>
|
||||||
constexpr void processId(const Pattern& pattern, int32_t depth, IdProcess idProcess) {
|
constexpr void processId(const Pattern& pattern, int32_t depth, IdProcess idProcess) {
|
||||||
|
@ -497,7 +511,9 @@ namespace matchit {
|
||||||
mMemHolder[mSize] = std::forward<T>(t);
|
mMemHolder[mSize] = std::forward<T>(t);
|
||||||
++mSize;
|
++mSize;
|
||||||
}
|
}
|
||||||
constexpr auto back() -> ElementT& { return mMemHolder[mSize - 1]; }
|
constexpr auto back() -> ElementT& {
|
||||||
|
return mMemHolder[mSize - 1];
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
template <>
|
template <>
|
||||||
|
@ -526,12 +542,15 @@ namespace matchit {
|
||||||
using RetType = std::invoke_result_t<Func>;
|
using RetType = std::invoke_result_t<Func>;
|
||||||
using PatternT = Pattern;
|
using PatternT = Pattern;
|
||||||
|
|
||||||
constexpr PatternPair(const Pattern& pattern, const Func& func) : mPattern { pattern }, mHandler { func } {}
|
constexpr PatternPair(const Pattern& pattern, const Func& func)
|
||||||
|
: mPattern { pattern }, mHandler { func } {}
|
||||||
template <typename Value, typename ContextT>
|
template <typename Value, typename ContextT>
|
||||||
constexpr bool matchValue(Value&& value, ContextT& context) const {
|
constexpr bool matchValue(Value&& value, ContextT& context) const {
|
||||||
return matchPattern(std::forward<Value>(value), mPattern, /*depth*/ 0, context);
|
return matchPattern(std::forward<Value>(value), mPattern, /*depth*/ 0, context);
|
||||||
}
|
}
|
||||||
constexpr auto execute() const { return mHandler(); }
|
constexpr auto execute() const {
|
||||||
|
return mHandler();
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
const Pattern mPattern;
|
const Pattern mPattern;
|
||||||
|
@ -556,7 +575,8 @@ namespace matchit {
|
||||||
template <typename Pattern>
|
template <typename Pattern>
|
||||||
class PatternHelper {
|
class PatternHelper {
|
||||||
public:
|
public:
|
||||||
constexpr explicit PatternHelper(const Pattern& pattern) : mPattern { pattern } {}
|
constexpr explicit PatternHelper(const Pattern& pattern)
|
||||||
|
: mPattern { pattern } {}
|
||||||
template <typename Func>
|
template <typename Func>
|
||||||
constexpr auto operator=(Func&& func) {
|
constexpr auto operator=(Func&& func) {
|
||||||
auto f = toNullary(func);
|
auto f = toNullary(func);
|
||||||
|
@ -641,8 +661,11 @@ namespace matchit {
|
||||||
template <typename... Patterns>
|
template <typename... Patterns>
|
||||||
class Or {
|
class Or {
|
||||||
public:
|
public:
|
||||||
constexpr explicit Or(const Patterns&... patterns) : mPatterns { patterns... } {}
|
constexpr explicit Or(const Patterns&... patterns)
|
||||||
constexpr const auto& patterns() const { return mPatterns; }
|
: mPatterns { patterns... } {}
|
||||||
|
constexpr const auto& patterns() const {
|
||||||
|
return mPatterns;
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::tuple<InternalPatternT<Patterns>...> mPatterns;
|
std::tuple<InternalPatternT<Patterns>...> mPatterns;
|
||||||
|
@ -713,8 +736,12 @@ namespace matchit {
|
||||||
public:
|
public:
|
||||||
constexpr App(Unary&& unary, const Pattern& pattern)
|
constexpr App(Unary&& unary, const Pattern& pattern)
|
||||||
: mUnary { std::forward<Unary>(unary) }, mPattern { pattern } {}
|
: mUnary { std::forward<Unary>(unary) }, mPattern { pattern } {}
|
||||||
constexpr const auto& unary() const { return mUnary; }
|
constexpr const auto& unary() const {
|
||||||
constexpr const auto& pattern() const { return mPattern; }
|
return mUnary;
|
||||||
|
}
|
||||||
|
constexpr const auto& pattern() const {
|
||||||
|
return mPattern;
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
const Unary mUnary;
|
const Unary mUnary;
|
||||||
|
@ -775,8 +802,11 @@ namespace matchit {
|
||||||
template <typename... Patterns>
|
template <typename... Patterns>
|
||||||
class And {
|
class And {
|
||||||
public:
|
public:
|
||||||
constexpr explicit And(const Patterns&... patterns) : mPatterns { patterns... } {}
|
constexpr explicit And(const Patterns&... patterns)
|
||||||
constexpr const auto& patterns() const { return mPatterns; }
|
: mPatterns { patterns... } {}
|
||||||
|
constexpr const auto& patterns() const {
|
||||||
|
return mPatterns;
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
std::tuple<InternalPatternT<Patterns>...> mPatterns;
|
std::tuple<InternalPatternT<Patterns>...> mPatterns;
|
||||||
|
@ -835,8 +865,11 @@ namespace matchit {
|
||||||
template <typename Pattern>
|
template <typename Pattern>
|
||||||
class Not {
|
class Not {
|
||||||
public:
|
public:
|
||||||
explicit Not(const Pattern& pattern) : mPattern { pattern } {}
|
explicit Not(const Pattern& pattern)
|
||||||
const auto& pattern() const { return mPattern; }
|
: mPattern { pattern } {}
|
||||||
|
const auto& pattern() const {
|
||||||
|
return mPattern;
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
InternalPatternT<Pattern> mPattern;
|
InternalPatternT<Pattern> mPattern;
|
||||||
|
@ -935,9 +968,12 @@ namespace matchit {
|
||||||
ValueVariant<Type> mVariant;
|
ValueVariant<Type> mVariant;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
constexpr IdBlockBase() : mDepth {}, mVariant {} {}
|
constexpr IdBlockBase()
|
||||||
|
: mDepth {}, mVariant {} {}
|
||||||
|
|
||||||
constexpr auto& variant() { return mVariant; }
|
constexpr auto& variant() {
|
||||||
|
return mVariant;
|
||||||
|
}
|
||||||
constexpr void reset(const int32_t depth) {
|
constexpr void reset(const int32_t depth) {
|
||||||
if (mDepth - depth >= 0) {
|
if (mDepth - depth >= 0) {
|
||||||
mVariant = {};
|
mVariant = {};
|
||||||
|
@ -1061,12 +1097,16 @@ namespace matchit {
|
||||||
using BlockVT = std::variant<BlockT, BlockT*>;
|
using BlockVT = std::variant<BlockT, BlockT*>;
|
||||||
BlockVT mBlock = BlockT {};
|
BlockVT mBlock = BlockT {};
|
||||||
|
|
||||||
constexpr decltype(auto) internalValue() const { return block().get(); }
|
constexpr decltype(auto) internalValue() const {
|
||||||
|
return block().get();
|
||||||
|
}
|
||||||
|
|
||||||
public:
|
public:
|
||||||
constexpr Id() = default;
|
constexpr Id() = default;
|
||||||
|
|
||||||
constexpr Id(const Id& id) { mBlock = BlockVT { &id.block() }; }
|
constexpr Id(const Id& id) {
|
||||||
|
mBlock = BlockVT { &id.block() };
|
||||||
|
}
|
||||||
|
|
||||||
// non-const to inform users not to mark Id as const.
|
// non-const to inform users not to mark Id as const.
|
||||||
template <typename Pattern>
|
template <typename Pattern>
|
||||||
|
@ -1075,7 +1115,9 @@ namespace matchit {
|
||||||
}
|
}
|
||||||
|
|
||||||
// non-const to inform users not to mark Id as const.
|
// non-const to inform users not to mark Id as const.
|
||||||
constexpr auto at(const Ooo&) { return OooBinder<Type> { *this }; }
|
constexpr auto at(const Ooo&) {
|
||||||
|
return OooBinder<Type> { *this };
|
||||||
|
}
|
||||||
|
|
||||||
constexpr BlockT& block() const {
|
constexpr BlockT& block() const {
|
||||||
return std::visit(
|
return std::visit(
|
||||||
|
@ -1094,13 +1136,23 @@ namespace matchit {
|
||||||
IdUtil<Type>::bindValue(block().variant(), std::forward<Value>(v), StorePointer<Type, Value> {});
|
IdUtil<Type>::bindValue(block().variant(), std::forward<Value>(v), StorePointer<Type, Value> {});
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
constexpr void reset(int32_t depth) const { return block().reset(depth); }
|
constexpr void reset(int32_t depth) const {
|
||||||
constexpr void confirm(int32_t depth) const { return block().confirm(depth); }
|
return block().reset(depth);
|
||||||
constexpr bool hasValue() const { return block().hasValue(); }
|
}
|
||||||
|
constexpr void confirm(int32_t depth) const {
|
||||||
|
return block().confirm(depth);
|
||||||
|
}
|
||||||
|
constexpr bool hasValue() const {
|
||||||
|
return block().hasValue();
|
||||||
|
}
|
||||||
// non-const to inform users not to mark Id as const.
|
// non-const to inform users not to mark Id as const.
|
||||||
constexpr decltype(auto) get() { return block().get(); }
|
constexpr decltype(auto) get() {
|
||||||
|
return block().get();
|
||||||
|
}
|
||||||
// non-const to inform users not to mark Id as const.
|
// non-const to inform users not to mark Id as const.
|
||||||
constexpr decltype(auto) operator*() { return get(); }
|
constexpr decltype(auto) operator*() {
|
||||||
|
return get();
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
template <typename Type>
|
template <typename Type>
|
||||||
|
@ -1127,8 +1179,11 @@ namespace matchit {
|
||||||
template <typename... Patterns>
|
template <typename... Patterns>
|
||||||
class Ds {
|
class Ds {
|
||||||
public:
|
public:
|
||||||
constexpr explicit Ds(const Patterns&... patterns) : mPatterns { patterns... } {}
|
constexpr explicit Ds(const Patterns&... patterns)
|
||||||
constexpr const auto& patterns() const { return mPatterns; }
|
: mPatterns { patterns... } {}
|
||||||
|
constexpr const auto& patterns() const {
|
||||||
|
return mPatterns;
|
||||||
|
}
|
||||||
|
|
||||||
using Type = std::tuple<InternalPatternT<Patterns>...>;
|
using Type = std::tuple<InternalPatternT<Patterns>...>;
|
||||||
|
|
||||||
|
@ -1146,8 +1201,11 @@ namespace matchit {
|
||||||
Id<T> mId;
|
Id<T> mId;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit OooBinder(const Id<T>& id) : mId { id } {}
|
explicit OooBinder(const Id<T>& id)
|
||||||
decltype(auto) binder() const { return mId; }
|
: mId { id } {}
|
||||||
|
decltype(auto) binder() const {
|
||||||
|
return mId;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
class Ooo {
|
class Ooo {
|
||||||
|
@ -1568,9 +1626,14 @@ namespace matchit {
|
||||||
template <typename Pattern, typename Pred>
|
template <typename Pattern, typename Pred>
|
||||||
class PostCheck {
|
class PostCheck {
|
||||||
public:
|
public:
|
||||||
constexpr explicit PostCheck(const Pattern& pattern, const Pred& pred) : mPattern { pattern }, mPred { pred } {}
|
constexpr explicit PostCheck(const Pattern& pattern, const Pred& pred)
|
||||||
constexpr bool check() const { return mPred(); }
|
: mPattern { pattern }, mPred { pred } {}
|
||||||
constexpr const auto& pattern() const { return mPattern; }
|
constexpr bool check() const {
|
||||||
|
return mPred();
|
||||||
|
}
|
||||||
|
constexpr const auto& pattern() const {
|
||||||
|
return mPattern;
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
const Pattern mPattern;
|
const Pattern mPattern;
|
||||||
|
@ -1742,9 +1805,13 @@ namespace matchit {
|
||||||
return dynamic_cast<T*>(std::addressof(b));
|
return dynamic_cast<T*>(std::addressof(b));
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr auto operator()(const T& b) const { return std::addressof(b); }
|
constexpr auto operator()(const T& b) const {
|
||||||
|
return std::addressof(b);
|
||||||
|
}
|
||||||
|
|
||||||
constexpr auto operator()(T& b) const { return std::addressof(b); }
|
constexpr auto operator()(T& b) const {
|
||||||
|
return std::addressof(b);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
static_assert(std::is_invocable_v<AsPointer<int>, int>);
|
static_assert(std::is_invocable_v<AsPointer<int>, int>);
|
|
@ -88,7 +88,14 @@ add_project_arguments(common_cpp_args, language : 'cpp')
|
||||||
# ------- #
|
# ------- #
|
||||||
# Files #
|
# Files #
|
||||||
# ------- #
|
# ------- #
|
||||||
base_sources = files('src/core/system_data.cpp', 'src/core/package.cpp', 'src/config/config.cpp', 'src/config/weather.cpp', 'src/main.cpp')
|
base_sources = files(
|
||||||
|
'src/core/system_data.cpp',
|
||||||
|
'src/core/package.cpp',
|
||||||
|
'src/config/config.cpp',
|
||||||
|
'src/config/weather.cpp',
|
||||||
|
'src/ui/ui.cpp',
|
||||||
|
'src/main.cpp',
|
||||||
|
)
|
||||||
|
|
||||||
platform_sources = {
|
platform_sources = {
|
||||||
'darwin' : ['src/os/macos.cpp', 'src/os/macos/bridge.mm'],
|
'darwin' : ['src/os/macos.cpp', 'src/os/macos/bridge.mm'],
|
||||||
|
|
|
@ -124,7 +124,9 @@ location = "London" # Your city name
|
||||||
const Result<String> envUser = util::helpers::GetEnv("USER");
|
const Result<String> envUser = util::helpers::GetEnv("USER");
|
||||||
const Result<String> envLogname = util::helpers::GetEnv("LOGNAME");
|
const Result<String> envLogname = util::helpers::GetEnv("LOGNAME");
|
||||||
|
|
||||||
defaultName = pwdName ? pwdName : envUser ? *envUser : envLogname ? *envLogname : "User";
|
defaultName = pwdName ? pwdName : envUser ? *envUser
|
||||||
|
: envLogname ? *envLogname
|
||||||
|
: "User";
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
std::ofstream file(configPath);
|
std::ofstream file(configPath);
|
||||||
|
|
|
@ -10,12 +10,11 @@
|
||||||
#else
|
#else
|
||||||
#include <pwd.h> // getpwuid, passwd
|
#include <pwd.h> // getpwuid, passwd
|
||||||
#include <unistd.h> // getuid
|
#include <unistd.h> // getuid
|
||||||
|
|
||||||
#include "src/util/helpers.hpp"
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "src/util/defs.hpp"
|
#include "src/util/defs.hpp"
|
||||||
#include "src/util/error.hpp"
|
#include "src/util/error.hpp"
|
||||||
|
#include "src/util/helpers.hpp"
|
||||||
#include "src/util/logging.hpp"
|
#include "src/util/logging.hpp"
|
||||||
#include "src/util/types.hpp"
|
#include "src/util/types.hpp"
|
||||||
|
|
||||||
|
@ -92,7 +91,9 @@ struct NowPlaying {
|
||||||
* @param tbl The TOML table to parse, containing [now_playing].
|
* @param tbl The TOML table to parse, containing [now_playing].
|
||||||
* @return A NowPlaying instance with the parsed values, or defaults otherwise.
|
* @return A NowPlaying instance with the parsed values, or defaults otherwise.
|
||||||
*/
|
*/
|
||||||
static fn fromToml(const toml::table& tbl) -> NowPlaying { return { .enabled = tbl["enabled"].value_or(false) }; }
|
static fn fromToml(const toml::table& tbl) -> NowPlaying {
|
||||||
|
return { .enabled = tbl["enabled"].value_or(false) };
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|
357
src/main.cpp
357
src/main.cpp
|
@ -1,10 +1,9 @@
|
||||||
#include <format> // std::format
|
#include <format> // std::format
|
||||||
#include <ftxui/dom/elements.hpp> // ftxui::{Element, hbox, vbox, text, separator, filler, etc.}
|
#include <ftxui/dom/elements.hpp> // ftxui::{Element, hbox, vbox, text, separator, filler, etc.}
|
||||||
#include <ftxui/dom/node.hpp> // ftxui::{Render}
|
#include <ftxui/dom/node.hpp> // ftxui::{Render}
|
||||||
#include <ftxui/screen/color.hpp> // ftxui::Color
|
|
||||||
#include <ftxui/screen/screen.hpp> // ftxui::{Screen, Dimension::Full}
|
#include <ftxui/screen/screen.hpp> // ftxui::{Screen, Dimension::Full}
|
||||||
#include <ftxui/screen/string.hpp> // ftxui::string_width
|
|
||||||
#include <ranges> // std::ranges::{iota, to, transform}
|
#include "src/ui/ui.hpp"
|
||||||
|
|
||||||
#ifdef __cpp_lib_print
|
#ifdef __cpp_lib_print
|
||||||
#include <print> // std::print
|
#include <print> // std::print
|
||||||
|
@ -13,341 +12,57 @@
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#include "src/config/config.hpp"
|
#include "src/config/config.hpp"
|
||||||
#include "src/config/weather.hpp"
|
|
||||||
#include "src/core/system_data.hpp"
|
#include "src/core/system_data.hpp"
|
||||||
#include "src/util/defs.hpp"
|
#include "src/util/defs.hpp"
|
||||||
#include "src/util/logging.hpp"
|
#include "src/util/logging.hpp"
|
||||||
#include "src/util/types.hpp"
|
#include "src/util/types.hpp"
|
||||||
|
|
||||||
namespace ui {
|
#include "include/argparse.hpp"
|
||||||
using ftxui::Color;
|
|
||||||
using util::types::StringView, util::types::i32;
|
|
||||||
|
|
||||||
// Color themes
|
using util::types::i32;
|
||||||
struct Theme {
|
|
||||||
Color::Palette16 icon;
|
|
||||||
Color::Palette16 label;
|
|
||||||
Color::Palette16 value;
|
|
||||||
Color::Palette16 border;
|
|
||||||
};
|
|
||||||
|
|
||||||
static constexpr Theme DEFAULT_THEME = {
|
fn main(const i32 argc, char* argv[]) -> i32 {
|
||||||
.icon = Color::Cyan,
|
|
||||||
.label = Color::Yellow,
|
|
||||||
.value = Color::White,
|
|
||||||
.border = Color::GrayLight,
|
|
||||||
};
|
|
||||||
|
|
||||||
struct Icons {
|
|
||||||
StringView user;
|
|
||||||
StringView palette;
|
|
||||||
StringView calendar;
|
|
||||||
StringView host;
|
|
||||||
StringView kernel;
|
|
||||||
StringView os;
|
|
||||||
StringView memory;
|
|
||||||
StringView weather;
|
|
||||||
StringView music;
|
|
||||||
StringView disk;
|
|
||||||
StringView shell;
|
|
||||||
StringView package;
|
|
||||||
StringView desktop;
|
|
||||||
StringView windowManager;
|
|
||||||
};
|
|
||||||
|
|
||||||
[[maybe_unused]] static constexpr Icons NONE = {
|
|
||||||
.user = "",
|
|
||||||
.palette = "",
|
|
||||||
.calendar = "",
|
|
||||||
.host = "",
|
|
||||||
.kernel = "",
|
|
||||||
.os = "",
|
|
||||||
.memory = "",
|
|
||||||
.weather = "",
|
|
||||||
.music = "",
|
|
||||||
.disk = "",
|
|
||||||
.shell = "",
|
|
||||||
.package = "",
|
|
||||||
.desktop = "",
|
|
||||||
.windowManager = "",
|
|
||||||
};
|
|
||||||
|
|
||||||
[[maybe_unused]] static constexpr Icons NERD = {
|
|
||||||
.user = " ",
|
|
||||||
.palette = " ",
|
|
||||||
.calendar = " ",
|
|
||||||
.host = " ",
|
|
||||||
.kernel = " ",
|
|
||||||
.os = " ",
|
|
||||||
.memory = " ",
|
|
||||||
.weather = " ",
|
|
||||||
.music = " ",
|
|
||||||
.disk = " ",
|
|
||||||
.shell = " ",
|
|
||||||
.package = " ",
|
|
||||||
.desktop = " ",
|
|
||||||
.windowManager = " ",
|
|
||||||
};
|
|
||||||
|
|
||||||
[[maybe_unused]] static constexpr Icons EMOJI = {
|
|
||||||
.user = " 👤 ",
|
|
||||||
.palette = " 🎨 ",
|
|
||||||
.calendar = " 📅 ",
|
|
||||||
.host = " 💻 ",
|
|
||||||
.kernel = " 🫀 ",
|
|
||||||
.os = " 🤖 ",
|
|
||||||
.memory = " 🧠 ",
|
|
||||||
.weather = " 🌈 ",
|
|
||||||
.music = " 🎵 ",
|
|
||||||
.disk = " 💾 ",
|
|
||||||
.shell = " 💲 ",
|
|
||||||
.package = " 📦 ",
|
|
||||||
.desktop = " 🖥️ ",
|
|
||||||
.windowManager = " 🪟 ",
|
|
||||||
};
|
|
||||||
|
|
||||||
static constexpr inline Icons ICON_TYPE = NERD;
|
|
||||||
} // namespace ui
|
|
||||||
|
|
||||||
namespace {
|
|
||||||
using namespace util::logging;
|
|
||||||
using namespace ftxui;
|
using namespace ftxui;
|
||||||
|
|
||||||
struct RowInfo {
|
|
||||||
StringView icon;
|
|
||||||
StringView label;
|
|
||||||
String value;
|
|
||||||
};
|
|
||||||
|
|
||||||
fn CreateColorCircles() -> Element {
|
|
||||||
auto colorView =
|
|
||||||
std::views::iota(0, 16) | std::views::transform([](i32 colorIndex) {
|
|
||||||
return ftxui::hbox(
|
|
||||||
{ ftxui::text("◯") | ftxui::bold | ftxui::color(static_cast<ftxui::Color::Palette256>(colorIndex)),
|
|
||||||
ftxui::text(" ") }
|
|
||||||
);
|
|
||||||
});
|
|
||||||
|
|
||||||
return hbox(Elements(std::ranges::begin(colorView), std::ranges::end(colorView)));
|
|
||||||
}
|
|
||||||
|
|
||||||
fn get_visual_width(const String& str) -> usize { return ftxui::string_width(str); }
|
|
||||||
fn get_visual_width_sv(const StringView& sview) -> usize { return ftxui::string_width(String(sview)); }
|
|
||||||
|
|
||||||
fn find_max_label_len(const std::vector<RowInfo>& rows) -> usize {
|
|
||||||
usize maxWidth = 0;
|
|
||||||
for (const RowInfo& row : rows) maxWidth = std::max(maxWidth, get_visual_width_sv(row.label));
|
|
||||||
|
|
||||||
return maxWidth;
|
|
||||||
};
|
|
||||||
|
|
||||||
fn SystemInfoBox(const Config& config, const os::SystemData& data) -> Element {
|
|
||||||
const String& name = config.general.name;
|
|
||||||
const Weather& weather = config.weather;
|
|
||||||
|
|
||||||
const auto& [userIcon, paletteIcon, calendarIcon, hostIcon, kernelIcon, osIcon, memoryIcon, weatherIcon, musicIcon, diskIcon, shellIcon, packageIcon, deIcon, wmIcon] =
|
|
||||||
ui::ICON_TYPE;
|
|
||||||
|
|
||||||
std::vector<RowInfo> initialRows; // Date, Weather
|
|
||||||
std::vector<RowInfo> systemInfoRows; // Host, Kernel, OS, RAM, Disk, Shell, Packages
|
|
||||||
std::vector<RowInfo> envInfoRows; // DE, WM
|
|
||||||
|
|
||||||
if (data.date)
|
|
||||||
initialRows.push_back({ .icon = calendarIcon, .label = "Date", .value = *data.date });
|
|
||||||
|
|
||||||
if (weather.enabled && data.weather) {
|
|
||||||
const weather::Output& weatherInfo = *data.weather;
|
|
||||||
String weatherValue = weather.showTownName
|
|
||||||
? std::format("{}°F in {}", std::lround(weatherInfo.main.temp), weatherInfo.name)
|
|
||||||
: std::format("{}°F, {}", std::lround(weatherInfo.main.temp), weatherInfo.weather[0].description);
|
|
||||||
initialRows.push_back({ .icon = weatherIcon, .label = "Weather", .value = std::move(weatherValue) });
|
|
||||||
} else if (weather.enabled && !data.weather.has_value())
|
|
||||||
debug_at(data.weather.error());
|
|
||||||
|
|
||||||
if (data.host && !data.host->empty())
|
|
||||||
systemInfoRows.push_back({ .icon = hostIcon, .label = "Host", .value = *data.host });
|
|
||||||
|
|
||||||
if (data.osVersion)
|
|
||||||
systemInfoRows.push_back({ .icon = osIcon, .label = "OS", .value = *data.osVersion });
|
|
||||||
|
|
||||||
if (data.kernelVersion)
|
|
||||||
systemInfoRows.push_back({ .icon = kernelIcon, .label = "Kernel", .value = *data.kernelVersion });
|
|
||||||
|
|
||||||
if (data.memInfo)
|
|
||||||
systemInfoRows.push_back(
|
|
||||||
{ .icon = memoryIcon, .label = "RAM", .value = std::format("{}", BytesToGiB { *data.memInfo }) }
|
|
||||||
);
|
|
||||||
else if (!data.memInfo.has_value())
|
|
||||||
debug_at(data.memInfo.error());
|
|
||||||
|
|
||||||
if (data.diskUsage)
|
|
||||||
systemInfoRows.push_back(
|
|
||||||
{
|
|
||||||
.icon = diskIcon,
|
|
||||||
.label = "Disk",
|
|
||||||
.value =
|
|
||||||
std::format("{}/{}", BytesToGiB { data.diskUsage->usedBytes }, BytesToGiB { data.diskUsage->totalBytes }),
|
|
||||||
}
|
|
||||||
);
|
|
||||||
|
|
||||||
if (data.shell)
|
|
||||||
systemInfoRows.push_back({ .icon = shellIcon, .label = "Shell", .value = *data.shell });
|
|
||||||
|
|
||||||
if (data.packageCount) {
|
|
||||||
if (*data.packageCount > 0)
|
|
||||||
systemInfoRows.push_back(
|
|
||||||
{ .icon = packageIcon, .label = "Packages", .value = std::format("{}", *data.packageCount) }
|
|
||||||
);
|
|
||||||
else
|
|
||||||
debug_log("Package count is 0, skipping");
|
|
||||||
}
|
|
||||||
|
|
||||||
bool addedDe = false;
|
|
||||||
if (data.desktopEnv && (!data.windowMgr || *data.desktopEnv != *data.windowMgr)) {
|
|
||||||
envInfoRows.push_back({ .icon = deIcon, .label = "DE", .value = *data.desktopEnv });
|
|
||||||
addedDe = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (data.windowMgr) {
|
|
||||||
if (!addedDe || (data.desktopEnv && *data.desktopEnv != *data.windowMgr))
|
|
||||||
envInfoRows.push_back({ .icon = wmIcon, .label = "WM", .value = *data.windowMgr });
|
|
||||||
}
|
|
||||||
|
|
||||||
bool nowPlayingActive = false;
|
|
||||||
String npText;
|
|
||||||
|
|
||||||
if (config.nowPlaying.enabled && data.nowPlaying) {
|
|
||||||
const String title = data.nowPlaying->title.value_or("Unknown Title");
|
|
||||||
const String artist = data.nowPlaying->artist.value_or("Unknown Artist");
|
|
||||||
npText = artist + " - " + title;
|
|
||||||
nowPlayingActive = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
usize maxContentWidth = 0;
|
|
||||||
|
|
||||||
const usize greetingWidth = get_visual_width_sv(userIcon) + get_visual_width_sv("Hello ") + get_visual_width(name) +
|
|
||||||
get_visual_width_sv("! ");
|
|
||||||
maxContentWidth = std::max(maxContentWidth, greetingWidth);
|
|
||||||
|
|
||||||
const usize paletteWidth =
|
|
||||||
get_visual_width_sv(userIcon) + (16 * (get_visual_width_sv("◯") + get_visual_width_sv(" ")));
|
|
||||||
maxContentWidth = std::max(maxContentWidth, paletteWidth);
|
|
||||||
|
|
||||||
const usize iconActualWidth = get_visual_width_sv(userIcon);
|
|
||||||
|
|
||||||
const usize maxLabelWidthInitial = find_max_label_len(initialRows);
|
|
||||||
const usize maxLabelWidthSystem = find_max_label_len(systemInfoRows);
|
|
||||||
const usize maxLabelWidthEnv = find_max_label_len(envInfoRows);
|
|
||||||
|
|
||||||
const usize requiredWidthInitialW = iconActualWidth + maxLabelWidthInitial;
|
|
||||||
const usize requiredWidthSystemW = iconActualWidth + maxLabelWidthSystem;
|
|
||||||
const usize requiredWidthEnvW = iconActualWidth + maxLabelWidthEnv;
|
|
||||||
|
|
||||||
fn calculateRowVisualWidth = [&](const RowInfo& row, const usize requiredLabelVisualWidth) -> usize {
|
|
||||||
return requiredLabelVisualWidth + get_visual_width(row.value) + get_visual_width_sv(" ");
|
|
||||||
};
|
|
||||||
|
|
||||||
for (const RowInfo& row : initialRows)
|
|
||||||
maxContentWidth = std::max(maxContentWidth, calculateRowVisualWidth(row, requiredWidthInitialW));
|
|
||||||
|
|
||||||
for (const RowInfo& row : systemInfoRows)
|
|
||||||
maxContentWidth = std::max(maxContentWidth, calculateRowVisualWidth(row, requiredWidthSystemW));
|
|
||||||
|
|
||||||
for (const RowInfo& row : envInfoRows)
|
|
||||||
maxContentWidth = std::max(maxContentWidth, calculateRowVisualWidth(row, requiredWidthEnvW));
|
|
||||||
|
|
||||||
const usize targetBoxWidth = maxContentWidth + 2;
|
|
||||||
|
|
||||||
usize npFixedWidthLeft = 0;
|
|
||||||
usize npFixedWidthRight = 0;
|
|
||||||
|
|
||||||
if (nowPlayingActive) {
|
|
||||||
npFixedWidthLeft = get_visual_width_sv(musicIcon) + get_visual_width_sv("Playing") + get_visual_width_sv(" ");
|
|
||||||
npFixedWidthRight = get_visual_width_sv(" ");
|
|
||||||
}
|
|
||||||
|
|
||||||
i32 paragraphLimit = 1;
|
|
||||||
|
|
||||||
if (nowPlayingActive) {
|
|
||||||
i32 availableForParagraph =
|
|
||||||
static_cast<i32>(targetBoxWidth) - static_cast<i32>(npFixedWidthLeft) - static_cast<i32>(npFixedWidthRight);
|
|
||||||
|
|
||||||
availableForParagraph -= 2;
|
|
||||||
|
|
||||||
paragraphLimit = std::max(1, availableForParagraph);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn createStandardRow = [&](const RowInfo& row, const usize sectionRequiredVisualWidth) {
|
|
||||||
return hbox(
|
|
||||||
{
|
|
||||||
hbox(
|
|
||||||
{
|
|
||||||
text(String(row.icon)) | color(ui::DEFAULT_THEME.icon),
|
|
||||||
text(String(row.label)) | color(ui::DEFAULT_THEME.label),
|
|
||||||
}
|
|
||||||
) |
|
|
||||||
size(WIDTH, EQUAL, static_cast<int>(sectionRequiredVisualWidth)),
|
|
||||||
filler(),
|
|
||||||
text(row.value) | color(ui::DEFAULT_THEME.value),
|
|
||||||
text(" "),
|
|
||||||
}
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
Elements content;
|
|
||||||
|
|
||||||
content.push_back(text(String(userIcon) + "Hello " + name + "! ") | bold | color(Color::Cyan));
|
|
||||||
content.push_back(separator() | color(ui::DEFAULT_THEME.border));
|
|
||||||
content.push_back(hbox({ text(String(paletteIcon)) | color(ui::DEFAULT_THEME.icon), CreateColorCircles() }));
|
|
||||||
|
|
||||||
const bool section1Present = !initialRows.empty();
|
|
||||||
const bool section2Present = !systemInfoRows.empty();
|
|
||||||
const bool section3Present = !envInfoRows.empty();
|
|
||||||
|
|
||||||
if (section1Present)
|
|
||||||
content.push_back(separator() | color(ui::DEFAULT_THEME.border));
|
|
||||||
|
|
||||||
for (const RowInfo& row : initialRows) content.push_back(createStandardRow(row, requiredWidthInitialW));
|
|
||||||
|
|
||||||
if ((section1Present && (section2Present || section3Present)) || (!section1Present && section2Present))
|
|
||||||
content.push_back(separator() | color(ui::DEFAULT_THEME.border));
|
|
||||||
|
|
||||||
for (const RowInfo& row : systemInfoRows) content.push_back(createStandardRow(row, requiredWidthSystemW));
|
|
||||||
|
|
||||||
if (section2Present && section3Present)
|
|
||||||
content.push_back(separator() | color(ui::DEFAULT_THEME.border));
|
|
||||||
|
|
||||||
for (const RowInfo& row : envInfoRows) content.push_back(createStandardRow(row, requiredWidthEnvW));
|
|
||||||
|
|
||||||
if ((section1Present || section2Present || section3Present) && nowPlayingActive)
|
|
||||||
content.push_back(separator() | color(ui::DEFAULT_THEME.border));
|
|
||||||
|
|
||||||
if (nowPlayingActive) {
|
|
||||||
content.push_back(hbox(
|
|
||||||
{ text(String(musicIcon)) | color(ui::DEFAULT_THEME.icon),
|
|
||||||
text("Playing") | color(ui::DEFAULT_THEME.label),
|
|
||||||
text(" "),
|
|
||||||
filler(),
|
|
||||||
paragraphAlignRight(npText) | color(Color::Magenta) | size(WIDTH, LESS_THAN, paragraphLimit),
|
|
||||||
text(" ") }
|
|
||||||
));
|
|
||||||
}
|
|
||||||
|
|
||||||
return vbox(content) | borderRounded | color(Color::White);
|
|
||||||
}
|
|
||||||
} // namespace
|
|
||||||
|
|
||||||
fn main() -> i32 {
|
|
||||||
using os::SystemData;
|
using os::SystemData;
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
winrt::init_apartment();
|
winrt::init_apartment();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
argparse::ArgumentParser parser("draconis", "0.1.0");
|
||||||
|
|
||||||
|
parser
|
||||||
|
.add_argument("--log-level")
|
||||||
|
.help("Set the log level")
|
||||||
|
.default_value("info")
|
||||||
|
.choices("trace", "debug", "info", "warn", "error", "fatal");
|
||||||
|
|
||||||
|
parser
|
||||||
|
.add_argument("-V", "--verbose")
|
||||||
|
.help("Enable verbose logging. Alias for --log-level=debug")
|
||||||
|
.flag();
|
||||||
|
|
||||||
|
try {
|
||||||
|
parser.parse_args(argc, argv);
|
||||||
|
} catch (const util::types::Exception& err) {
|
||||||
|
#ifdef __cpp_lib_print
|
||||||
|
std::println(stderr, "{}", err.what());
|
||||||
|
#else
|
||||||
|
std::cerr << err.what() << '\n';
|
||||||
|
#endif
|
||||||
|
|
||||||
|
std::cerr << parser;
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (parser["--verbose"] == true || parser["-v"] == true)
|
||||||
|
info_log("Verbose logging enabled");
|
||||||
|
|
||||||
const Config& config = Config::getInstance();
|
const Config& config = Config::getInstance();
|
||||||
const SystemData data = SystemData(config);
|
const SystemData data = SystemData(config);
|
||||||
|
|
||||||
Element document = vbox({ hbox({ SystemInfoBox(config, data), filler() }) });
|
Element document = ui::CreateUI(config, data);
|
||||||
|
|
||||||
Screen screen = Screen::Create(Dimension::Full(), Dimension::Fit(document));
|
Screen screen = Screen::Create(Dimension::Full(), Dimension::Fit(document));
|
||||||
Render(screen, document);
|
Render(screen, document);
|
||||||
|
|
|
@ -72,9 +72,13 @@ namespace os {
|
||||||
return Err(DracError(DracErrorCode::NotSupported, "Now playing is not supported on Haiku"));
|
return Err(DracError(DracErrorCode::NotSupported, "Now playing is not supported on Haiku"));
|
||||||
}
|
}
|
||||||
|
|
||||||
fn GetWindowManager() -> Result<String> { return "app_server"; }
|
fn GetWindowManager() -> Result<String> {
|
||||||
|
return "app_server";
|
||||||
|
}
|
||||||
|
|
||||||
fn GetDesktopEnvironment() -> Result<String> { return "Haiku Desktop Environment"; }
|
fn GetDesktopEnvironment() -> Result<String> {
|
||||||
|
return "Haiku Desktop Environment";
|
||||||
|
}
|
||||||
|
|
||||||
fn GetShell() -> Result<String> {
|
fn GetShell() -> Result<String> {
|
||||||
if (const Result<String> shellPath = GetEnv("SHELL")) {
|
if (const Result<String> shellPath = GetEnv("SHELL")) {
|
||||||
|
|
|
@ -48,15 +48,26 @@ namespace os {
|
||||||
return mem;
|
return mem;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn GetNowPlaying() -> Result<MediaInfo> { return GetCurrentPlayingInfo(); }
|
fn GetNowPlaying() -> Result<MediaInfo> {
|
||||||
|
return GetCurrentPlayingInfo();
|
||||||
|
}
|
||||||
|
|
||||||
fn GetOSVersion() -> Result<String> { return GetMacOSVersion(); }
|
fn GetOSVersion() -> Result<String> {
|
||||||
|
return GetMacOSVersion();
|
||||||
|
}
|
||||||
|
|
||||||
fn GetDesktopEnvironment() -> Result<String> { return "Aqua"; }
|
fn GetDesktopEnvironment() -> Result<String> {
|
||||||
|
return "Aqua";
|
||||||
|
}
|
||||||
|
|
||||||
fn GetWindowManager() -> Result<String> {
|
fn GetWindowManager() -> Result<String> {
|
||||||
constexpr Array<StringView, 6> knownWms = {
|
constexpr Array<StringView, 6> knownWms = {
|
||||||
"yabai", "kwm", "chunkwm", "amethyst", "spectacle", "rectangle",
|
"yabai",
|
||||||
|
"kwm",
|
||||||
|
"chunkwm",
|
||||||
|
"amethyst",
|
||||||
|
"spectacle",
|
||||||
|
"rectangle",
|
||||||
};
|
};
|
||||||
|
|
||||||
Array<i32, 3> request = { CTL_KERN, KERN_PROC, KERN_PROC_ALL };
|
Array<i32, 3> request = { CTL_KERN, KERN_PROC, KERN_PROC_ALL };
|
||||||
|
|
|
@ -110,9 +110,13 @@ namespace os {
|
||||||
return Err(DracError(DracErrorCode::NotSupported, "Now playing is not supported on SerenityOS"));
|
return Err(DracError(DracErrorCode::NotSupported, "Now playing is not supported on SerenityOS"));
|
||||||
}
|
}
|
||||||
|
|
||||||
fn GetWindowManager() -> Result<String> { return "WindowManager"; }
|
fn GetWindowManager() -> Result<String> {
|
||||||
|
return "WindowManager";
|
||||||
|
}
|
||||||
|
|
||||||
fn GetDesktopEnvironment() -> Result<String> { return "SerenityOS Desktop"; }
|
fn GetDesktopEnvironment() -> Result<String> {
|
||||||
|
return "SerenityOS Desktop";
|
||||||
|
}
|
||||||
|
|
||||||
fn GetShell() -> Result<String> {
|
fn GetShell() -> Result<String> {
|
||||||
uid_t userId = getuid();
|
uid_t userId = getuid();
|
||||||
|
@ -166,7 +170,9 @@ namespace os {
|
||||||
} // namespace os
|
} // namespace os
|
||||||
|
|
||||||
namespace package {
|
namespace package {
|
||||||
fn GetSerenityCount() -> Result<u64> { return CountUniquePackages("/usr/Ports/installed.db"); }
|
fn GetSerenityCount() -> Result<u64> {
|
||||||
|
return CountUniquePackages("/usr/Ports/installed.db");
|
||||||
|
}
|
||||||
} // namespace package
|
} // namespace package
|
||||||
|
|
||||||
#endif // __serenity__
|
#endif // __serenity__
|
||||||
|
|
306
src/ui/ui.cpp
Normal file
306
src/ui/ui.cpp
Normal file
|
@ -0,0 +1,306 @@
|
||||||
|
#include "ui.hpp"
|
||||||
|
|
||||||
|
#include "src/util/types.hpp"
|
||||||
|
|
||||||
|
namespace ui {
|
||||||
|
using namespace ftxui;
|
||||||
|
using namespace util::types;
|
||||||
|
|
||||||
|
constexpr Theme DEFAULT_THEME = {
|
||||||
|
.icon = Color::Cyan,
|
||||||
|
.label = Color::Yellow,
|
||||||
|
.value = Color::White,
|
||||||
|
.border = Color::GrayLight,
|
||||||
|
};
|
||||||
|
|
||||||
|
[[maybe_unused]] static constexpr Icons NONE = {
|
||||||
|
.user = "",
|
||||||
|
.palette = "",
|
||||||
|
.calendar = "",
|
||||||
|
.host = "",
|
||||||
|
.kernel = "",
|
||||||
|
.os = "",
|
||||||
|
.memory = "",
|
||||||
|
.weather = "",
|
||||||
|
.music = "",
|
||||||
|
.disk = "",
|
||||||
|
.shell = "",
|
||||||
|
.package = "",
|
||||||
|
.desktop = "",
|
||||||
|
.windowManager = "",
|
||||||
|
};
|
||||||
|
|
||||||
|
[[maybe_unused]] static constexpr Icons NERD = {
|
||||||
|
.user = " ",
|
||||||
|
.palette = " ",
|
||||||
|
.calendar = " ",
|
||||||
|
.host = " ",
|
||||||
|
.kernel = " ",
|
||||||
|
.os = " ",
|
||||||
|
.memory = " ",
|
||||||
|
.weather = " ",
|
||||||
|
.music = " ",
|
||||||
|
.disk = " ",
|
||||||
|
.shell = " ",
|
||||||
|
.package = " ",
|
||||||
|
.desktop = " ",
|
||||||
|
.windowManager = " ",
|
||||||
|
};
|
||||||
|
|
||||||
|
[[maybe_unused]] static constexpr Icons EMOJI = {
|
||||||
|
.user = " 👤 ",
|
||||||
|
.palette = " 🎨 ",
|
||||||
|
.calendar = " 📅 ",
|
||||||
|
.host = " 💻 ",
|
||||||
|
.kernel = " 🫀 ",
|
||||||
|
.os = " 🤖 ",
|
||||||
|
.memory = " 🧠 ",
|
||||||
|
.weather = " 🌈 ",
|
||||||
|
.music = " 🎵 ",
|
||||||
|
.disk = " 💾 ",
|
||||||
|
.shell = " 💲 ",
|
||||||
|
.package = " 📦 ",
|
||||||
|
.desktop = " 🖥️ ",
|
||||||
|
.windowManager = " 🪟 ",
|
||||||
|
};
|
||||||
|
|
||||||
|
constexpr inline Icons ICON_TYPE = NERD;
|
||||||
|
|
||||||
|
struct RowInfo {
|
||||||
|
StringView icon;
|
||||||
|
StringView label;
|
||||||
|
String value;
|
||||||
|
};
|
||||||
|
|
||||||
|
namespace {
|
||||||
|
fn CreateColorCircles() -> Element {
|
||||||
|
auto colorView =
|
||||||
|
std::views::iota(0, 16) | std::views::transform([](i32 colorIndex) {
|
||||||
|
return ftxui::hbox(
|
||||||
|
{ ftxui::text("◯") | ftxui::bold | ftxui::color(static_cast<ftxui::Color::Palette256>(colorIndex)),
|
||||||
|
ftxui::text(" ") }
|
||||||
|
);
|
||||||
|
});
|
||||||
|
|
||||||
|
return hbox(Elements(std::ranges::begin(colorView), std::ranges::end(colorView)));
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_visual_width(const String& str) -> usize {
|
||||||
|
return ftxui::string_width(str);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn get_visual_width_sv(const StringView& sview) -> usize {
|
||||||
|
return ftxui::string_width(String(sview));
|
||||||
|
}
|
||||||
|
|
||||||
|
fn find_max_label_len(const std::vector<RowInfo>& rows) -> usize {
|
||||||
|
usize maxWidth = 0;
|
||||||
|
for (const RowInfo& row : rows) maxWidth = std::max(maxWidth, get_visual_width_sv(row.label));
|
||||||
|
|
||||||
|
return maxWidth;
|
||||||
|
};
|
||||||
|
|
||||||
|
fn CreateInfoBox(const Config& config, const os::SystemData& data) -> Element {
|
||||||
|
const String& name = config.general.name;
|
||||||
|
const Weather& weather = config.weather;
|
||||||
|
|
||||||
|
const auto& [userIcon, paletteIcon, calendarIcon, hostIcon, kernelIcon, osIcon, memoryIcon, weatherIcon, musicIcon, diskIcon, shellIcon, packageIcon, deIcon, wmIcon] =
|
||||||
|
ui::ICON_TYPE;
|
||||||
|
|
||||||
|
std::vector<RowInfo> initialRows; // Date, Weather
|
||||||
|
std::vector<RowInfo> systemInfoRows; // Host, Kernel, OS, RAM, Disk, Shell, Packages
|
||||||
|
std::vector<RowInfo> envInfoRows; // DE, WM
|
||||||
|
|
||||||
|
if (data.date)
|
||||||
|
initialRows.push_back({ .icon = calendarIcon, .label = "Date", .value = *data.date });
|
||||||
|
|
||||||
|
if (weather.enabled && data.weather) {
|
||||||
|
const weather::Output& weatherInfo = *data.weather;
|
||||||
|
String weatherValue = weather.showTownName
|
||||||
|
? std::format("{}°F in {}", std::lround(weatherInfo.main.temp), weatherInfo.name)
|
||||||
|
: std::format("{}°F, {}", std::lround(weatherInfo.main.temp), weatherInfo.weather[0].description);
|
||||||
|
initialRows.push_back({ .icon = weatherIcon, .label = "Weather", .value = std::move(weatherValue) });
|
||||||
|
} else if (weather.enabled && !data.weather.has_value())
|
||||||
|
debug_at(data.weather.error());
|
||||||
|
|
||||||
|
if (data.host && !data.host->empty())
|
||||||
|
systemInfoRows.push_back({ .icon = hostIcon, .label = "Host", .value = *data.host });
|
||||||
|
|
||||||
|
if (data.osVersion)
|
||||||
|
systemInfoRows.push_back({ .icon = osIcon, .label = "OS", .value = *data.osVersion });
|
||||||
|
|
||||||
|
if (data.kernelVersion)
|
||||||
|
systemInfoRows.push_back({ .icon = kernelIcon, .label = "Kernel", .value = *data.kernelVersion });
|
||||||
|
|
||||||
|
if (data.memInfo)
|
||||||
|
systemInfoRows.push_back(
|
||||||
|
{ .icon = memoryIcon, .label = "RAM", .value = std::format("{}", BytesToGiB { *data.memInfo }) }
|
||||||
|
);
|
||||||
|
else if (!data.memInfo.has_value())
|
||||||
|
debug_at(data.memInfo.error());
|
||||||
|
|
||||||
|
if (data.diskUsage)
|
||||||
|
systemInfoRows.push_back(
|
||||||
|
{
|
||||||
|
.icon = diskIcon,
|
||||||
|
.label = "Disk",
|
||||||
|
.value =
|
||||||
|
std::format("{}/{}", BytesToGiB { data.diskUsage->usedBytes }, BytesToGiB { data.diskUsage->totalBytes }),
|
||||||
|
}
|
||||||
|
);
|
||||||
|
|
||||||
|
if (data.shell)
|
||||||
|
systemInfoRows.push_back({ .icon = shellIcon, .label = "Shell", .value = *data.shell });
|
||||||
|
|
||||||
|
if (data.packageCount) {
|
||||||
|
if (*data.packageCount > 0)
|
||||||
|
systemInfoRows.push_back(
|
||||||
|
{ .icon = packageIcon, .label = "Packages", .value = std::format("{}", *data.packageCount) }
|
||||||
|
);
|
||||||
|
else
|
||||||
|
debug_log("Package count is 0, skipping");
|
||||||
|
}
|
||||||
|
|
||||||
|
bool addedDe = false;
|
||||||
|
|
||||||
|
if (data.desktopEnv && (!data.windowMgr || *data.desktopEnv != *data.windowMgr)) {
|
||||||
|
envInfoRows.push_back({ .icon = deIcon, .label = "DE", .value = *data.desktopEnv });
|
||||||
|
addedDe = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (data.windowMgr)
|
||||||
|
if (!addedDe || (data.desktopEnv && *data.desktopEnv != *data.windowMgr))
|
||||||
|
envInfoRows.push_back({ .icon = wmIcon, .label = "WM", .value = *data.windowMgr });
|
||||||
|
|
||||||
|
bool nowPlayingActive = false;
|
||||||
|
String npText;
|
||||||
|
|
||||||
|
if (config.nowPlaying.enabled && data.nowPlaying) {
|
||||||
|
const String title = data.nowPlaying->title.value_or("Unknown Title");
|
||||||
|
const String artist = data.nowPlaying->artist.value_or("Unknown Artist");
|
||||||
|
npText = artist + " - " + title;
|
||||||
|
nowPlayingActive = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
usize maxContentWidth = 0;
|
||||||
|
|
||||||
|
const usize greetingWidth = get_visual_width_sv(userIcon) + get_visual_width_sv("Hello ") + get_visual_width(name) +
|
||||||
|
get_visual_width_sv("! ");
|
||||||
|
maxContentWidth = std::max(maxContentWidth, greetingWidth);
|
||||||
|
|
||||||
|
const usize paletteWidth =
|
||||||
|
get_visual_width_sv(userIcon) + (16 * (get_visual_width_sv("◯") + get_visual_width_sv(" ")));
|
||||||
|
maxContentWidth = std::max(maxContentWidth, paletteWidth);
|
||||||
|
|
||||||
|
const usize iconActualWidth = get_visual_width_sv(userIcon);
|
||||||
|
|
||||||
|
const usize maxLabelWidthInitial = find_max_label_len(initialRows);
|
||||||
|
const usize maxLabelWidthSystem = find_max_label_len(systemInfoRows);
|
||||||
|
const usize maxLabelWidthEnv = find_max_label_len(envInfoRows);
|
||||||
|
|
||||||
|
const usize requiredWidthInitialW = iconActualWidth + maxLabelWidthInitial;
|
||||||
|
const usize requiredWidthSystemW = iconActualWidth + maxLabelWidthSystem;
|
||||||
|
const usize requiredWidthEnvW = iconActualWidth + maxLabelWidthEnv;
|
||||||
|
|
||||||
|
fn calculateRowVisualWidth = [&](const RowInfo& row, const usize requiredLabelVisualWidth) -> usize {
|
||||||
|
return requiredLabelVisualWidth + get_visual_width(row.value) + get_visual_width_sv(" ");
|
||||||
|
};
|
||||||
|
|
||||||
|
for (const RowInfo& row : initialRows)
|
||||||
|
maxContentWidth = std::max(maxContentWidth, calculateRowVisualWidth(row, requiredWidthInitialW));
|
||||||
|
|
||||||
|
for (const RowInfo& row : systemInfoRows)
|
||||||
|
maxContentWidth = std::max(maxContentWidth, calculateRowVisualWidth(row, requiredWidthSystemW));
|
||||||
|
|
||||||
|
for (const RowInfo& row : envInfoRows)
|
||||||
|
maxContentWidth = std::max(maxContentWidth, calculateRowVisualWidth(row, requiredWidthEnvW));
|
||||||
|
|
||||||
|
const usize targetBoxWidth = maxContentWidth + 2;
|
||||||
|
|
||||||
|
usize npFixedWidthLeft = 0;
|
||||||
|
usize npFixedWidthRight = 0;
|
||||||
|
|
||||||
|
if (nowPlayingActive) {
|
||||||
|
npFixedWidthLeft = get_visual_width_sv(musicIcon) + get_visual_width_sv("Playing") + get_visual_width_sv(" ");
|
||||||
|
npFixedWidthRight = get_visual_width_sv(" ");
|
||||||
|
}
|
||||||
|
|
||||||
|
i32 paragraphLimit = 1;
|
||||||
|
|
||||||
|
if (nowPlayingActive) {
|
||||||
|
i32 availableForParagraph =
|
||||||
|
static_cast<i32>(targetBoxWidth) - static_cast<i32>(npFixedWidthLeft) - static_cast<i32>(npFixedWidthRight);
|
||||||
|
|
||||||
|
availableForParagraph -= 2;
|
||||||
|
|
||||||
|
paragraphLimit = std::max(1, availableForParagraph);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn createStandardRow = [&](const RowInfo& row, const usize sectionRequiredVisualWidth) {
|
||||||
|
return hbox(
|
||||||
|
{
|
||||||
|
hbox(
|
||||||
|
{
|
||||||
|
text(String(row.icon)) | color(ui::DEFAULT_THEME.icon),
|
||||||
|
text(String(row.label)) | color(ui::DEFAULT_THEME.label),
|
||||||
|
}
|
||||||
|
) |
|
||||||
|
size(WIDTH, EQUAL, static_cast<int>(sectionRequiredVisualWidth)),
|
||||||
|
filler(),
|
||||||
|
text(row.value) | color(ui::DEFAULT_THEME.value),
|
||||||
|
text(" "),
|
||||||
|
}
|
||||||
|
);
|
||||||
|
};
|
||||||
|
|
||||||
|
Elements content;
|
||||||
|
|
||||||
|
content.push_back(text(String(userIcon) + "Hello " + name + "! ") | bold | color(Color::Cyan));
|
||||||
|
content.push_back(separator() | color(ui::DEFAULT_THEME.border));
|
||||||
|
content.push_back(hbox({ text(String(paletteIcon)) | color(ui::DEFAULT_THEME.icon), CreateColorCircles() }));
|
||||||
|
|
||||||
|
const bool section1Present = !initialRows.empty();
|
||||||
|
const bool section2Present = !systemInfoRows.empty();
|
||||||
|
const bool section3Present = !envInfoRows.empty();
|
||||||
|
|
||||||
|
if (section1Present)
|
||||||
|
content.push_back(separator() | color(ui::DEFAULT_THEME.border));
|
||||||
|
|
||||||
|
for (const RowInfo& row : initialRows) content.push_back(createStandardRow(row, requiredWidthInitialW));
|
||||||
|
|
||||||
|
if ((section1Present && (section2Present || section3Present)) || (!section1Present && section2Present))
|
||||||
|
content.push_back(separator() | color(ui::DEFAULT_THEME.border));
|
||||||
|
|
||||||
|
for (const RowInfo& row : systemInfoRows) content.push_back(createStandardRow(row, requiredWidthSystemW));
|
||||||
|
|
||||||
|
if (section2Present && section3Present)
|
||||||
|
content.push_back(separator() | color(ui::DEFAULT_THEME.border));
|
||||||
|
|
||||||
|
for (const RowInfo& row : envInfoRows) content.push_back(createStandardRow(row, requiredWidthEnvW));
|
||||||
|
|
||||||
|
if ((section1Present || section2Present || section3Present) && nowPlayingActive)
|
||||||
|
content.push_back(separator() | color(ui::DEFAULT_THEME.border));
|
||||||
|
|
||||||
|
if (nowPlayingActive) {
|
||||||
|
content.push_back(hbox(
|
||||||
|
{
|
||||||
|
text(String(musicIcon)) | color(ui::DEFAULT_THEME.icon),
|
||||||
|
text("Playing") | color(ui::DEFAULT_THEME.label),
|
||||||
|
text(" "),
|
||||||
|
filler(),
|
||||||
|
paragraphAlignRight(npText) | color(Color::Magenta) | size(WIDTH, LESS_THAN, paragraphLimit),
|
||||||
|
text(" "),
|
||||||
|
}
|
||||||
|
));
|
||||||
|
}
|
||||||
|
|
||||||
|
return vbox(content) | borderRounded | color(Color::White);
|
||||||
|
}
|
||||||
|
} // namespace
|
||||||
|
|
||||||
|
fn CreateUI(const Config& config, const os::SystemData& data) -> Element {
|
||||||
|
Element infoBox = CreateInfoBox(config, data);
|
||||||
|
|
||||||
|
return hbox({ infoBox, filler() });
|
||||||
|
}
|
||||||
|
} // namespace ui
|
45
src/ui/ui.hpp
Normal file
45
src/ui/ui.hpp
Normal file
|
@ -0,0 +1,45 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <ftxui/dom/elements.hpp> // ftxui::Element
|
||||||
|
#include <ftxui/screen/color.hpp> // ftxui::Color
|
||||||
|
|
||||||
|
#include "src/config/config.hpp"
|
||||||
|
#include "src/core/system_data.hpp"
|
||||||
|
#include "src/util/types.hpp"
|
||||||
|
|
||||||
|
namespace ui {
|
||||||
|
struct Theme {
|
||||||
|
ftxui::Color::Palette16 icon;
|
||||||
|
ftxui::Color::Palette16 label;
|
||||||
|
ftxui::Color::Palette16 value;
|
||||||
|
ftxui::Color::Palette16 border;
|
||||||
|
};
|
||||||
|
|
||||||
|
extern const Theme DEFAULT_THEME;
|
||||||
|
|
||||||
|
struct Icons {
|
||||||
|
util::types::StringView user;
|
||||||
|
util::types::StringView palette;
|
||||||
|
util::types::StringView calendar;
|
||||||
|
util::types::StringView host;
|
||||||
|
util::types::StringView kernel;
|
||||||
|
util::types::StringView os;
|
||||||
|
util::types::StringView memory;
|
||||||
|
util::types::StringView weather;
|
||||||
|
util::types::StringView music;
|
||||||
|
util::types::StringView disk;
|
||||||
|
util::types::StringView shell;
|
||||||
|
util::types::StringView package;
|
||||||
|
util::types::StringView desktop;
|
||||||
|
util::types::StringView windowManager;
|
||||||
|
};
|
||||||
|
|
||||||
|
extern const Icons ICON_TYPE;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Creates the main UI element based on system data and configuration.
|
||||||
|
* @param config The application configuration.
|
||||||
|
* @param data The collected system data. @return The root ftxui::Element for rendering.
|
||||||
|
*/
|
||||||
|
fn CreateUI(const Config& config, const os::SystemData& data) -> ftxui::Element;
|
||||||
|
} // namespace ui
|
|
@ -12,7 +12,7 @@
|
||||||
|
|
||||||
#include "src/util/types.hpp"
|
#include "src/util/types.hpp"
|
||||||
|
|
||||||
#include "include/matchit.h"
|
#include "include/matchit.hpp"
|
||||||
|
|
||||||
namespace util {
|
namespace util {
|
||||||
namespace error {
|
namespace error {
|
||||||
|
@ -77,7 +77,8 @@ namespace util {
|
||||||
}
|
}
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
explicit DracError(const winrt::hresult_error& e) : message(winrt::to_string(e.message())) {
|
explicit DracError(const winrt::hresult_error& e)
|
||||||
|
: message(winrt::to_string(e.message())) {
|
||||||
using namespace matchit;
|
using namespace matchit;
|
||||||
using enum DracErrorCode;
|
using enum DracErrorCode;
|
||||||
|
|
||||||
|
|
|
@ -74,7 +74,10 @@ namespace util::logging {
|
||||||
* @enum LogLevel
|
* @enum LogLevel
|
||||||
* @brief Represents different log levels.
|
* @brief Represents different log levels.
|
||||||
*/
|
*/
|
||||||
enum class LogLevel : u8 { Debug, Info, Warn, Error };
|
enum class LogLevel : u8 { Debug,
|
||||||
|
Info,
|
||||||
|
Warn,
|
||||||
|
Error };
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Directly applies ANSI color codes to text
|
* @brief Directly applies ANSI color codes to text
|
||||||
|
@ -227,7 +230,8 @@ namespace util::logging {
|
||||||
#ifdef __cpp_lib_print
|
#ifdef __cpp_lib_print
|
||||||
std::print("\n{}", Italic(Colorize(fullDebugLine, LogLevelConst::DEBUG_INFO_COLOR)));
|
std::print("\n{}", Italic(Colorize(fullDebugLine, LogLevelConst::DEBUG_INFO_COLOR)));
|
||||||
#else
|
#else
|
||||||
std::cout << '\n' << Italic(Colorize(fullDebugLine, LogLevelConst::DEBUG_INFO_COLOR));
|
std::cout << '\n'
|
||||||
|
<< Italic(Colorize(fullDebugLine, LogLevelConst::DEBUG_INFO_COLOR));
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
|
@ -131,6 +131,7 @@ namespace util::types {
|
||||||
|
|
||||||
MediaInfo() = default;
|
MediaInfo() = default;
|
||||||
|
|
||||||
MediaInfo(Option<String> title, Option<String> artist) : title(std::move(title)), artist(std::move(artist)) {}
|
MediaInfo(Option<String> title, Option<String> artist)
|
||||||
|
: title(std::move(title)), artist(std::move(artist)) {}
|
||||||
};
|
};
|
||||||
} // namespace util::types
|
} // namespace util::types
|
||||||
|
|
|
@ -27,7 +27,10 @@ namespace dbus {
|
||||||
bool m_isInitialized = false;
|
bool m_isInitialized = false;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
Error() : m_isInitialized(true) { dbus_error_init(&m_err); }
|
Error()
|
||||||
|
: m_isInitialized(true) {
|
||||||
|
dbus_error_init(&m_err);
|
||||||
|
}
|
||||||
|
|
||||||
~Error() {
|
~Error() {
|
||||||
if (m_isInitialized)
|
if (m_isInitialized)
|
||||||
|
@ -37,7 +40,8 @@ namespace dbus {
|
||||||
Error(const Error&) = delete;
|
Error(const Error&) = delete;
|
||||||
fn operator=(const Error&)->Error& = delete;
|
fn operator=(const Error&)->Error& = delete;
|
||||||
|
|
||||||
Error(Error&& other) noexcept : m_err(other.m_err), m_isInitialized(other.m_isInitialized) {
|
Error(Error&& other) noexcept
|
||||||
|
: m_err(other.m_err), m_isInitialized(other.m_isInitialized) {
|
||||||
other.m_isInitialized = false;
|
other.m_isInitialized = false;
|
||||||
dbus_error_init(&other.m_err);
|
dbus_error_init(&other.m_err);
|
||||||
}
|
}
|
||||||
|
@ -60,30 +64,40 @@ namespace dbus {
|
||||||
* @brief Checks if the D-Bus error is set.
|
* @brief Checks if the D-Bus error is set.
|
||||||
* @return True if an error is set, false otherwise.
|
* @return True if an error is set, false otherwise.
|
||||||
*/
|
*/
|
||||||
[[nodiscard]] fn isSet() const -> bool { return m_isInitialized && dbus_error_is_set(&m_err); }
|
[[nodiscard]] fn isSet() const -> bool {
|
||||||
|
return m_isInitialized && dbus_error_is_set(&m_err);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Gets the error message.
|
* @brief Gets the error message.
|
||||||
* @return The error message string, or "" if not set or not initialized.
|
* @return The error message string, or "" if not set or not initialized.
|
||||||
*/
|
*/
|
||||||
[[nodiscard]] fn message() const -> const char* { return isSet() ? m_err.message : ""; }
|
[[nodiscard]] fn message() const -> const char* {
|
||||||
|
return isSet() ? m_err.message : "";
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Gets the error name.
|
* @brief Gets the error name.
|
||||||
* @return The error name string (e.g., "org.freedesktop.DBus.Error.Failed"), or "" if not set or not initialized.
|
* @return The error name string (e.g., "org.freedesktop.DBus.Error.Failed"), or "" if not set or not initialized.
|
||||||
*/
|
*/
|
||||||
[[nodiscard]] fn name() const -> const char* { return isSet() ? m_err.name : ""; }
|
[[nodiscard]] fn name() const -> const char* {
|
||||||
|
return isSet() ? m_err.name : "";
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Gets a pointer to the underlying DBusError. Use with caution.
|
* @brief Gets a pointer to the underlying DBusError. Use with caution.
|
||||||
* @return Pointer to the DBusError struct.
|
* @return Pointer to the DBusError struct.
|
||||||
*/
|
*/
|
||||||
[[nodiscard]] fn get() -> DBusError* { return &m_err; }
|
[[nodiscard]] fn get() -> DBusError* {
|
||||||
|
return &m_err;
|
||||||
|
}
|
||||||
/**
|
/**
|
||||||
* @brief Gets a const pointer to the underlying DBusError.
|
* @brief Gets a const pointer to the underlying DBusError.
|
||||||
* @return Const pointer to the DBusError struct.
|
* @return Const pointer to the DBusError struct.
|
||||||
*/
|
*/
|
||||||
[[nodiscard]] fn get() const -> const DBusError* { return &m_err; }
|
[[nodiscard]] fn get() const -> const DBusError* {
|
||||||
|
return &m_err;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Converts the D-Bus error to a DraconisError.
|
* @brief Converts the D-Bus error to a DraconisError.
|
||||||
|
@ -107,7 +121,8 @@ namespace dbus {
|
||||||
DBusMessageIter m_iter {};
|
DBusMessageIter m_iter {};
|
||||||
bool m_isValid = false;
|
bool m_isValid = false;
|
||||||
|
|
||||||
explicit MessageIter(const DBusMessageIter& iter, const bool isValid) : m_iter(iter), m_isValid(isValid) {}
|
explicit MessageIter(const DBusMessageIter& iter, const bool isValid)
|
||||||
|
: m_iter(iter), m_isValid(isValid) {}
|
||||||
|
|
||||||
friend class Message;
|
friend class Message;
|
||||||
|
|
||||||
|
@ -131,7 +146,9 @@ namespace dbus {
|
||||||
/**
|
/**
|
||||||
* @brief Checks if the iterator is validly initialized.
|
* @brief Checks if the iterator is validly initialized.
|
||||||
*/
|
*/
|
||||||
[[nodiscard]] fn isValid() const -> bool { return m_isValid; }
|
[[nodiscard]] fn isValid() const -> bool {
|
||||||
|
return m_isValid;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Gets the D-Bus type code of the current argument.
|
* @brief Gets the D-Bus type code of the current argument.
|
||||||
|
@ -154,7 +171,9 @@ namespace dbus {
|
||||||
* @brief Advances the iterator to the next argument.
|
* @brief Advances the iterator to the next argument.
|
||||||
* @return True if successful (moved to a next element), false if at the end or iterator is invalid.
|
* @return True if successful (moved to a next element), false if at the end or iterator is invalid.
|
||||||
*/
|
*/
|
||||||
fn next() -> bool { return m_isValid && dbus_message_iter_next(&m_iter); }
|
fn next() -> bool {
|
||||||
|
return m_isValid && dbus_message_iter_next(&m_iter);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Recurses into a container-type argument (e.g., array, struct, variant).
|
* @brief Recurses into a container-type argument (e.g., array, struct, variant).
|
||||||
|
@ -197,7 +216,8 @@ namespace dbus {
|
||||||
DBusMessage* m_msg = nullptr;
|
DBusMessage* m_msg = nullptr;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit Message(DBusMessage* msg = nullptr) : m_msg(msg) {}
|
explicit Message(DBusMessage* msg = nullptr)
|
||||||
|
: m_msg(msg) {}
|
||||||
|
|
||||||
~Message() {
|
~Message() {
|
||||||
if (m_msg)
|
if (m_msg)
|
||||||
|
@ -207,7 +227,8 @@ namespace dbus {
|
||||||
Message(const Message&) = delete;
|
Message(const Message&) = delete;
|
||||||
fn operator=(const Message&)->Message& = delete;
|
fn operator=(const Message&)->Message& = delete;
|
||||||
|
|
||||||
Message(Message&& other) noexcept : m_msg(std::exchange(other.m_msg, nullptr)) {}
|
Message(Message&& other) noexcept
|
||||||
|
: m_msg(std::exchange(other.m_msg, nullptr)) {}
|
||||||
|
|
||||||
fn operator=(Message&& other) noexcept -> Message& {
|
fn operator=(Message&& other) noexcept -> Message& {
|
||||||
if (this != &other) {
|
if (this != &other) {
|
||||||
|
@ -222,7 +243,9 @@ namespace dbus {
|
||||||
* @brief Gets the underlying DBusMessage pointer. Use with caution.
|
* @brief Gets the underlying DBusMessage pointer. Use with caution.
|
||||||
* @return The raw DBusMessage pointer, or nullptr if not holding a message.
|
* @return The raw DBusMessage pointer, or nullptr if not holding a message.
|
||||||
*/
|
*/
|
||||||
[[nodiscard]] fn get() const -> DBusMessage* { return m_msg; }
|
[[nodiscard]] fn get() const -> DBusMessage* {
|
||||||
|
return m_msg;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Initializes a message iterator for reading arguments from this message.
|
* @brief Initializes a message iterator for reading arguments from this message.
|
||||||
|
@ -296,7 +319,8 @@ namespace dbus {
|
||||||
DBusConnection* m_conn = nullptr;
|
DBusConnection* m_conn = nullptr;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit Connection(DBusConnection* conn = nullptr) : m_conn(conn) {}
|
explicit Connection(DBusConnection* conn = nullptr)
|
||||||
|
: m_conn(conn) {}
|
||||||
|
|
||||||
~Connection() {
|
~Connection() {
|
||||||
if (m_conn)
|
if (m_conn)
|
||||||
|
@ -306,7 +330,8 @@ namespace dbus {
|
||||||
Connection(const Connection&) = delete;
|
Connection(const Connection&) = delete;
|
||||||
fn operator=(const Connection&)->Connection& = delete;
|
fn operator=(const Connection&)->Connection& = delete;
|
||||||
|
|
||||||
Connection(Connection&& other) noexcept : m_conn(std::exchange(other.m_conn, nullptr)) {}
|
Connection(Connection&& other) noexcept
|
||||||
|
: m_conn(std::exchange(other.m_conn, nullptr)) {}
|
||||||
|
|
||||||
fn operator=(Connection&& other) noexcept -> Connection& {
|
fn operator=(Connection&& other) noexcept -> Connection& {
|
||||||
if (this != &other) {
|
if (this != &other) {
|
||||||
|
@ -322,7 +347,9 @@ namespace dbus {
|
||||||
* @brief Gets the underlying DBusConnection pointer. Use with caution.
|
* @brief Gets the underlying DBusConnection pointer. Use with caution.
|
||||||
* @return The raw DBusConnection pointer, or nullptr if not holding a connection.
|
* @return The raw DBusConnection pointer, or nullptr if not holding a connection.
|
||||||
*/
|
*/
|
||||||
[[nodiscard]] fn get() const -> DBusConnection* { return m_conn; }
|
[[nodiscard]] fn get() const -> DBusConnection* {
|
||||||
|
return m_conn;
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Sends a message and waits for a reply, blocking execution.
|
* @brief Sends a message and waits for a reply, blocking execution.
|
||||||
|
|
|
@ -16,9 +16,15 @@ namespace wl {
|
||||||
using display = wl_display;
|
using display = wl_display;
|
||||||
|
|
||||||
// NOLINTBEGIN(readability-identifier-naming)
|
// NOLINTBEGIN(readability-identifier-naming)
|
||||||
inline fn connect(const char* name) -> display* { return wl_display_connect(name); }
|
inline fn connect(const char* name) -> display* {
|
||||||
inline fn disconnect(display* display) -> void { wl_display_disconnect(display); }
|
return wl_display_connect(name);
|
||||||
inline fn get_fd(display* display) -> int { return wl_display_get_fd(display); }
|
}
|
||||||
|
inline fn disconnect(display* display) -> void {
|
||||||
|
wl_display_disconnect(display);
|
||||||
|
}
|
||||||
|
inline fn get_fd(display* display) -> int {
|
||||||
|
return wl_display_get_fd(display);
|
||||||
|
}
|
||||||
// NOLINTEND(readability-identifier-naming)
|
// NOLINTEND(readability-identifier-naming)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -77,7 +83,8 @@ namespace wl {
|
||||||
fn operator=(const DisplayGuard&)->DisplayGuard& = delete;
|
fn operator=(const DisplayGuard&)->DisplayGuard& = delete;
|
||||||
|
|
||||||
// Movable
|
// Movable
|
||||||
DisplayGuard(DisplayGuard&& other) noexcept : m_display(std::exchange(other.m_display, nullptr)) {}
|
DisplayGuard(DisplayGuard&& other) noexcept
|
||||||
|
: m_display(std::exchange(other.m_display, nullptr)) {}
|
||||||
fn operator=(DisplayGuard&& other) noexcept -> DisplayGuard& {
|
fn operator=(DisplayGuard&& other) noexcept -> DisplayGuard& {
|
||||||
if (this != &other) {
|
if (this != &other) {
|
||||||
if (m_display)
|
if (m_display)
|
||||||
|
@ -89,10 +96,16 @@ namespace wl {
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] explicit operator bool() const { return m_display != nullptr; }
|
[[nodiscard]] explicit operator bool() const {
|
||||||
|
return m_display != nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
[[nodiscard]] fn get() const -> display* { return m_display; }
|
[[nodiscard]] fn get() const -> display* {
|
||||||
[[nodiscard]] fn fd() const -> util::types::i32 { return get_fd(m_display); }
|
return m_display;
|
||||||
|
}
|
||||||
|
[[nodiscard]] fn fd() const -> util::types::i32 {
|
||||||
|
return get_fd(m_display);
|
||||||
|
}
|
||||||
};
|
};
|
||||||
} // namespace wl
|
} // namespace wl
|
||||||
|
|
||||||
|
|
|
@ -53,8 +53,12 @@ namespace xcb {
|
||||||
inline fn connect(const char* displayname, int* screenp) -> connection_t* {
|
inline fn connect(const char* displayname, int* screenp) -> connection_t* {
|
||||||
return xcb_connect(displayname, screenp);
|
return xcb_connect(displayname, screenp);
|
||||||
}
|
}
|
||||||
inline fn disconnect(connection_t* conn) -> void { xcb_disconnect(conn); }
|
inline fn disconnect(connection_t* conn) -> void {
|
||||||
inline fn connection_has_error(connection_t* conn) -> int { return xcb_connection_has_error(conn); }
|
xcb_disconnect(conn);
|
||||||
|
}
|
||||||
|
inline fn connection_has_error(connection_t* conn) -> int {
|
||||||
|
return xcb_connection_has_error(conn);
|
||||||
|
}
|
||||||
inline fn intern_atom(connection_t* conn, const uint8_t only_if_exists, const uint16_t name_len, const char* name)
|
inline fn intern_atom(connection_t* conn, const uint8_t only_if_exists, const uint16_t name_len, const char* name)
|
||||||
-> intern_atom_cookie_t {
|
-> intern_atom_cookie_t {
|
||||||
return xcb_intern_atom(conn, only_if_exists, name_len, name);
|
return xcb_intern_atom(conn, only_if_exists, name_len, name);
|
||||||
|
@ -81,7 +85,9 @@ namespace xcb {
|
||||||
inline fn get_property_value_length(const get_property_reply_t* reply) -> int {
|
inline fn get_property_value_length(const get_property_reply_t* reply) -> int {
|
||||||
return xcb_get_property_value_length(reply);
|
return xcb_get_property_value_length(reply);
|
||||||
}
|
}
|
||||||
inline fn get_property_value(const get_property_reply_t* reply) -> void* { return xcb_get_property_value(reply); }
|
inline fn get_property_value(const get_property_reply_t* reply) -> void* {
|
||||||
|
return xcb_get_property_value(reply);
|
||||||
|
}
|
||||||
// NOLINTEND(readability-identifier-naming)
|
// NOLINTEND(readability-identifier-naming)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -96,7 +102,8 @@ namespace xcb {
|
||||||
* Opens an XCB connection
|
* Opens an XCB connection
|
||||||
* @param name Display name (nullptr for default)
|
* @param name Display name (nullptr for default)
|
||||||
*/
|
*/
|
||||||
explicit DisplayGuard(const util::types::CStr name = nullptr) : m_connection(connect(name, nullptr)) {}
|
explicit DisplayGuard(const util::types::CStr name = nullptr)
|
||||||
|
: m_connection(connect(name, nullptr)) {}
|
||||||
~DisplayGuard() {
|
~DisplayGuard() {
|
||||||
if (m_connection)
|
if (m_connection)
|
||||||
disconnect(m_connection);
|
disconnect(m_connection);
|
||||||
|
@ -107,7 +114,8 @@ namespace xcb {
|
||||||
fn operator=(const DisplayGuard&)->DisplayGuard& = delete;
|
fn operator=(const DisplayGuard&)->DisplayGuard& = delete;
|
||||||
|
|
||||||
// Movable
|
// Movable
|
||||||
DisplayGuard(DisplayGuard&& other) noexcept : m_connection(std::exchange(other.m_connection, nullptr)) {}
|
DisplayGuard(DisplayGuard&& other) noexcept
|
||||||
|
: m_connection(std::exchange(other.m_connection, nullptr)) {}
|
||||||
fn operator=(DisplayGuard&& other) noexcept -> DisplayGuard& {
|
fn operator=(DisplayGuard&& other) noexcept -> DisplayGuard& {
|
||||||
if (this != &other) {
|
if (this != &other) {
|
||||||
if (m_connection)
|
if (m_connection)
|
||||||
|
@ -118,11 +126,17 @@ namespace xcb {
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] explicit operator bool() const { return m_connection && !connection_has_error(m_connection); }
|
[[nodiscard]] explicit operator bool() const {
|
||||||
|
return m_connection && !connection_has_error(m_connection);
|
||||||
|
}
|
||||||
|
|
||||||
[[nodiscard]] fn get() const -> connection_t* { return m_connection; }
|
[[nodiscard]] fn get() const -> connection_t* {
|
||||||
|
return m_connection;
|
||||||
|
}
|
||||||
|
|
||||||
[[nodiscard]] fn setup() const -> const setup_t* { return m_connection ? xcb_get_setup(m_connection) : nullptr; }
|
[[nodiscard]] fn setup() const -> const setup_t* {
|
||||||
|
return m_connection ? xcb_get_setup(m_connection) : nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
[[nodiscard]] fn rootScreen() const -> screen_t* {
|
[[nodiscard]] fn rootScreen() const -> screen_t* {
|
||||||
const setup_t* setup = this->setup();
|
const setup_t* setup = this->setup();
|
||||||
|
@ -140,7 +154,8 @@ namespace xcb {
|
||||||
|
|
||||||
public:
|
public:
|
||||||
ReplyGuard() = default;
|
ReplyGuard() = default;
|
||||||
explicit ReplyGuard(T* reply) : m_reply(reply) {}
|
explicit ReplyGuard(T* reply)
|
||||||
|
: m_reply(reply) {}
|
||||||
|
|
||||||
~ReplyGuard() {
|
~ReplyGuard() {
|
||||||
if (m_reply)
|
if (m_reply)
|
||||||
|
@ -152,7 +167,8 @@ namespace xcb {
|
||||||
fn operator=(const ReplyGuard&)->ReplyGuard& = delete;
|
fn operator=(const ReplyGuard&)->ReplyGuard& = delete;
|
||||||
|
|
||||||
// Movable
|
// Movable
|
||||||
ReplyGuard(ReplyGuard&& other) noexcept : m_reply(std::exchange(other.m_reply, nullptr)) {}
|
ReplyGuard(ReplyGuard&& other) noexcept
|
||||||
|
: m_reply(std::exchange(other.m_reply, nullptr)) {}
|
||||||
fn operator=(ReplyGuard&& other) noexcept -> ReplyGuard& {
|
fn operator=(ReplyGuard&& other) noexcept -> ReplyGuard& {
|
||||||
if (this != &other) {
|
if (this != &other) {
|
||||||
if (m_reply)
|
if (m_reply)
|
||||||
|
@ -163,11 +179,19 @@ namespace xcb {
|
||||||
return *this;
|
return *this;
|
||||||
}
|
}
|
||||||
|
|
||||||
[[nodiscard]] explicit operator bool() const { return m_reply != nullptr; }
|
[[nodiscard]] explicit operator bool() const {
|
||||||
|
return m_reply != nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
[[nodiscard]] fn get() const -> T* { return m_reply; }
|
[[nodiscard]] fn get() const -> T* {
|
||||||
[[nodiscard]] fn operator->() const->T* { return m_reply; }
|
return m_reply;
|
||||||
[[nodiscard]] fn operator*() const->T& { return *m_reply; }
|
}
|
||||||
|
[[nodiscard]] fn operator->() const->T* {
|
||||||
|
return m_reply;
|
||||||
|
}
|
||||||
|
[[nodiscard]] fn operator*() const->T& {
|
||||||
|
return *m_reply;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
} // namespace xcb
|
} // namespace xcb
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue