Skip to main content

hyprshell_hyprland/
shared.rs

1//! # The Shared Module
2//!
3//! This module provides shared private and public functions, structs, enum, and types
4use derive_more::Display;
5use serde::{Deserialize, Serialize};
6use std::hash::{Hash, Hasher};
7use std::path::PathBuf;
8use std::{env, fmt};
9
10/// The address struct holds a address as a tuple with a single value
11/// and has methods to reveal the address in different data formats
12#[derive(
13    Debug, Deserialize, Serialize, Clone, Eq, PartialEq, Hash, Ord, PartialOrd, derive_more::Display,
14)]
15pub struct Address(String);
16impl Address {
17    #[inline(always)]
18    pub(crate) fn fmt_new(address: &str) -> Self {
19        // this way is faster than std::fmt
20        Self("0x".to_owned() + address)
21    }
22    /// This creates a new address from a value that implements [ToString]
23    pub fn new<T: ToString>(string: T) -> Self {
24        let str = string.to_string();
25        if str.starts_with("0x") {
26            Self(str)
27        } else {
28            Self("0x".to_owned() + str.as_str())
29        }
30    }
31}
32
33/// This trait provides a standardized way to get data
34pub trait HyprData {
35    /// This method gets the data
36    fn get() -> crate::Result<Self>
37    where
38        Self: Sized;
39    /// This method gets the data (async)
40    #[cfg(any(feature = "async-lite", feature = "tokio"))]
41    async fn get_async() -> crate::Result<Self>
42    where
43        Self: Sized;
44    /// This method gets the data
45    fn instance_get(instance: &Instance) -> crate::Result<Self>
46    where
47        Self: Sized;
48    /// This method gets the data (async)
49    #[cfg(any(feature = "async-lite", feature = "tokio"))]
50    async fn instance_get_async(instance: &Instance) -> crate::Result<Self>
51    where
52        Self: Sized;
53}
54
55/// This trait provides a standardized way to get data in a from of a vector
56pub trait HyprDataVec<T>: HyprData {
57    /// This method returns a vector of data
58    fn to_vec(self) -> Vec<T>;
59}
60
61/// Trait for helper functions to get the active of the implementor
62pub trait HyprDataActive {
63    /// This method gets the active data
64    fn get_active() -> crate::Result<Self>
65    where
66        Self: Sized;
67    /// This method gets the active data (async)
68    #[cfg(any(feature = "async-lite", feature = "tokio"))]
69    async fn get_active_async() -> crate::Result<Self>
70    where
71        Self: Sized;
72    /// This method gets the active data
73    fn instance_get_active(instance: &Instance) -> crate::Result<Self>
74    where
75        Self: Sized;
76    /// This method gets the active data (async)
77    #[cfg(any(feature = "async-lite", feature = "tokio"))]
78    async fn instance_get_active_async(instance: &Instance) -> crate::Result<Self>
79    where
80        Self: Sized;
81}
82
83/// Trait for helper functions to get the active of the implementor, but for optional ones
84pub trait HyprDataActiveOptional {
85    /// This method gets the active data
86    fn get_active() -> crate::Result<Option<Self>>
87    where
88        Self: Sized;
89    /// This method gets the active data (async)
90    #[cfg(any(feature = "async-lite", feature = "tokio"))]
91    async fn get_active_async() -> crate::Result<Option<Self>>
92    where
93        Self: Sized;
94    /// This method gets the active data
95    fn instance_get_active(instance: &Instance) -> crate::Result<Option<Self>>
96    where
97        Self: Sized;
98    /// This method gets the active data (async)
99    #[cfg(any(feature = "async-lite", feature = "tokio"))]
100    async fn instance_get_active_async(instance: &Instance) -> crate::Result<Option<Self>>
101    where
102        Self: Sized;
103}
104
105/// This type provides the id used to identify workspaces
106/// > its a type because it might change at some point
107pub type WorkspaceId = i32;
108
109/// This type provides the id used to identify monitors
110/// > its a type because it might change at some point
111pub type MonitorId = i128;
112
113#[inline]
114fn ser_spec_opt(opt: &Option<String>) -> String {
115    match opt {
116        Some(name) => "special:".to_owned() + name,
117        None => "special".to_owned(),
118    }
119}
120
121/// This enum holds workspace data
122#[derive(Serialize, Deserialize, Debug, Clone, PartialEq, Eq, Display, PartialOrd, Ord)]
123#[serde(untagged)]
124pub enum WorkspaceType {
125    /// A named workspace
126    Regular(
127        /// The name
128        String,
129    ),
130    /// The special workspace
131    #[display("{}", ser_spec_opt(_0))]
132    Special(
133        /// The name, if exists
134        Option<String>,
135    ),
136}
137
138impl From<&WorkspaceType> for String {
139    fn from(value: &WorkspaceType) -> Self {
140        value.to_string()
141    }
142}
143macro_rules! from {
144    ($($ty:ty),+$(,)?) => {
145        $(
146            impl TryFrom<$ty> for WorkspaceType {
147                type Error = crate::error::HyprError;
148                fn try_from(int: $ty) -> Result<Self, Self::Error> {
149                    match int {
150                        1.. => Ok(WorkspaceType::Regular(int.to_string())),
151                        _ => crate::error::hypr_err!("Conversion error: Unrecognised id"),
152                    }
153                }
154            }
155        )+
156    };
157}
158from![u8, u16, u32, u64, usize, i8, i16, i32, i64, isize];
159
160impl Hash for WorkspaceType {
161    fn hash<H: Hasher>(&self, state: &mut H) {
162        match self {
163            WorkspaceType::Regular(name) => name.hash(state),
164            WorkspaceType::Special(value) => match value {
165                Some(name) => name.hash(state),
166                None => "".hash(state),
167            },
168        }
169    }
170}
171
172pub(crate) fn get_hypr_path() -> crate::Result<PathBuf> {
173    let mut buf = if let Some(runtime_path) = env::var_os("XDG_RUNTIME_DIR") {
174        std::path::PathBuf::from(runtime_path)
175    } else if let Ok(uid) = env::var("UID") {
176        std::path::PathBuf::from("/run/user/".to_owned() + &uid)
177    } else {
178        hypr_err!("Could not find XDG_RUNTIME_DIR or UID");
179    };
180    buf.push("hypr");
181    Ok(buf)
182}
183
184/// This enum defines the possible command flags that can be used.
185#[derive(Debug, Default, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
186pub enum CommandFlag {
187    /// The JSON flag.
188    #[default]
189    JSON,
190    /// An empty flag.
191    Empty,
192}
193
194/// This struct defines the content of a command, which consists of a flag and a data string.
195#[derive(Debug, Default, Clone, PartialEq, Eq, Serialize, Deserialize)]
196pub struct CommandContent {
197    /// The flag for the command.
198    pub flag: CommandFlag,
199    /// The data string for the command.
200    pub data: String,
201}
202
203impl CommandContent {
204    /// Converts the command content to a byte vector.
205    ///
206    /// # Examples
207    ///
208    /// ```
209    /// use hyprland::shared::*;
210    ///
211    /// let content = CommandContent { flag: CommandFlag::JSON, data: "foo".to_string() };
212    /// let bytes = content.as_bytes();
213    /// assert_eq!(bytes, b"j/foo");
214    /// ```
215    pub fn as_bytes(&self) -> Vec<u8> {
216        self.to_string().into_bytes()
217    }
218}
219
220impl fmt::Display for CommandContent {
221    /// Formats the command content as a string for display.
222    ///
223    /// # Examples
224    ///
225    /// ```
226    /// use hyprland::shared::*;
227    ///
228    /// let content = CommandContent { flag: CommandFlag::JSON, data: "foo".to_string() };
229    /// let s = format!("{}", content);
230    /// assert_eq!(s, "j/foo");
231    /// ```
232    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
233        match &self.flag {
234            CommandFlag::JSON => write!(f, "j/{}", &self.data),
235            CommandFlag::Empty => write!(f, "/{}", &self.data),
236        }
237    }
238}
239
240/// Creates a `CommandContent` instance with the given flag and formatted data.
241///
242/// # Arguments
243///
244/// * `$flag` - A `CommandFlag` variant (`JSON` or `Empty`) that represents the flag for the command.
245/// * `$($k:tt)*` - A format string and its arguments to be used as the data in the `CommandContent` instance.
246#[macro_export]
247macro_rules! command {
248    ($flag:ident, $($k:tt)*) => {{
249        $crate::shared::CommandContent {
250            flag: $crate::shared::CommandFlag::$flag,
251            data: format!($($k)*),
252        }
253    }};
254}
255use crate::error::hypr_err;
256use crate::instance::Instance;
257pub use command;
258
259#[derive(Debug, Clone, Copy, PartialEq, Eq, derive_more::Display)]
260#[allow(missing_docs)]
261/// Enum for mod keys used in bind combinations
262pub enum Mod {
263    #[display("SUPER")]
264    SUPER,
265    #[display("SHIFT")]
266    SHIFT,
267    #[display("ALT")]
268    ALT,
269    #[display("CTRL")]
270    CTRL,
271    #[display("")]
272    NONE,
273}