hyprland/
config.rs

1//! # Hyprland Configuration in Rust
2//!
3use crate::dispatch::{gen_dispatch_str, DispatchType};
4use crate::keyword::Keyword;
5
6/// Module providing stuff for adding an removing keybinds
7pub mod binds {
8    use super::*;
9
10    trait Join: IntoIterator {
11        fn join(&self) -> String;
12    }
13
14    /// Type for a key held by a bind
15    #[derive(Debug, Clone)]
16    pub enum Key<'a> {
17        /// Variant for if the bind holds a modded key
18        Mod(
19            /// Mods
20            Vec<Mod>,
21            /// Key
22            &'a str,
23        ),
24        /// Variant for a regular key
25        Key(&'a str),
26    }
27
28    impl std::fmt::Display for Key<'_> {
29        fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
30            write!(
31                f,
32                "{}",
33                match self {
34                    Key::Mod(m, s) => format!("{}_{s}", m.join()),
35                    Key::Key(s) => s.to_string(),
36                }
37            )
38        }
39    }
40
41    #[derive(Debug, Clone, Copy)]
42    #[allow(missing_docs)]
43    /// Enum for mod keys used in bind combinations
44    pub enum Mod {
45        SUPER,
46        SHIFT,
47        ALT,
48        CTRL,
49        NONE,
50    }
51
52    impl ToString for Mod {
53        fn to_string(&self) -> String {
54            match self {
55                Mod::NONE => "",
56                Mod::SUPER => "SUPER",
57                Mod::SHIFT => "SHIFT",
58                Mod::ALT => "ALT",
59                Mod::CTRL => "CTRL",
60            }
61            .to_string()
62        }
63    }
64
65    impl Join for Vec<Mod> {
66        fn join(&self) -> String {
67            let mut buf = String::new();
68            for i in self {
69                buf.push_str(&i.to_string());
70            }
71            buf
72        }
73    }
74
75    #[derive(Debug, Clone, Copy)]
76    #[allow(non_camel_case_types)]
77    /// Enum for bind flags
78    pub enum Flag {
79        /// Works when screen is locked
80        l,
81        /// Used for mouse binds
82        m,
83        /// Repeats when held
84        e,
85        /// Activates on release
86        r,
87    }
88
89    impl ToString for Flag {
90        fn to_string(&self) -> String {
91            match self {
92                Flag::l => "l",
93                Flag::m => "m",
94                Flag::e => "e",
95                Flag::r => "r",
96            }
97            .to_string()
98        }
99    }
100
101    impl Join for Vec<Flag> {
102        fn join(&self) -> String {
103            let mut buf = String::new();
104            for i in self {
105                buf.push_str(&i.to_string());
106            }
107            buf
108        }
109    }
110
111    /// A struct providing a key bind
112    #[derive(Debug, Clone)]
113    pub struct Binding<'a> {
114        /// All the mods
115        pub mods: Vec<Mod>,
116        /// The key
117        pub key: Key<'a>,
118        /// Bind flags
119        pub flags: Vec<Flag>,
120        /// The dispatcher to be called once complete
121        pub dispatcher: DispatchType<'a>,
122    }
123
124    /// Struct to hold methods for adding and removing binds
125    pub struct Binder;
126
127    impl Binder {
128        pub(crate) fn gen_str(binding: Binding) -> crate::Result<String> {
129            Ok(format!(
130                "{mods},{key},{dispatcher}",
131                mods = binding.mods.join(),
132                key = binding.key,
133                dispatcher = gen_dispatch_str(binding.dispatcher, false)?
134            ))
135        }
136        /// Binds a keybinding
137        pub fn bind(binding: Binding) -> crate::Result<()> {
138            Keyword::set(
139                format!("bind{}", binding.flags.join()),
140                Self::gen_str(binding)?,
141            )?;
142            Ok(())
143        }
144        /// Binds a keybinding (async)
145        pub async fn bind_async(binding: Binding<'_>) -> crate::Result<()> {
146            Keyword::set_async(
147                format!("bind{}", binding.flags.join()),
148                Self::gen_str(binding)?,
149            )
150            .await?;
151            Ok(())
152        }
153    }
154    /// Very macro basic abstraction over [Binder] for internal use, **Dont use this instead use [crate::bind]**
155    #[macro_export]
156    #[doc(hidden)]
157    macro_rules! bind_raw {
158        (sync $mods:expr,$key:expr,$flags:expr,$dis:expr ) => {{
159            use $crate::config::binds::*;
160            let binding = Binding {
161                mods: $mods,
162                key: $key,
163                flags: $flags,
164                dispatcher: $dis,
165            };
166            Binder::bind(binding)
167        }};
168        ($mods:expr,$key:expr,$flags:expr,$dis:expr ) => {{
169            use $crate::config::binds::*;
170            let binding = Binding {
171                mods: $mods,
172                key: $key,
173                flags: $flags,
174                dispatcher: $dis,
175            };
176            Binder::bind_async(binding)
177        }};
178    }
179
180    /// Macro abstraction over [Binder]
181    #[macro_export]
182    macro_rules! bind {
183        ($( $flag:ident ) *|$( $mod:ident ) *,$keyt:ident, $( $key:expr ), * => $dis:ident, $( $arg:expr ), *) => {
184            $crate::bind_raw!(
185                sync
186                vec![$(Mod::$mod), *],
187                Key::$keyt( $( $key ), * ),
188                vec![$(Flag::$flag), *],
189                DispatchType::$dis( $($arg),* )
190            )
191        };
192        ($( $flag:ident ) *|$( $mod:ident ) *,$keyt:ident,$( $key:expr ), * => $dis:ident ) => {
193            $crate::bind_raw!(
194                sync
195                vec![$(Mod::$mod), *],
196                Key::$keyt( $( $key ), * ),
197                vec![$(Flag::$flag), *],
198                DispatchType::$dis
199            )
200        };
201        ($( $mod:ident ) *,$keyt:ident,$( $key:expr ), * => $dis:ident, $( $arg:expr ), *) => {
202            $crate::bind_raw!(
203                sync
204                vec![$(Mod::$mod), *],
205                Key::$keyt( $( $key ), * ),
206                vec![],
207                DispatchType::$dis( $($arg),* )
208            )
209        };
210        ($( $mod:ident ) *,$keyt:ident,$( $key:expr ), * => $dis:ident ) => {
211            $crate::bind_raw!(
212                sync
213                vec![$(Mod::$mod), *],
214                Key::$keyt( $( $key ), * ),
215                vec![],
216                DispatchType::$dis
217            )
218        };
219        (async ; $( $flag:ident ) *|$( $mod:ident ) *,$keyt:ident, $( $key:expr ), * => $dis:ident, $( $arg:expr ), *) => {
220            $crate::bind_raw!(
221                vec![$(Mod::$mod), *],
222                Key::$keyt( $( $key ), * ),
223                vec![$(Flag::$flag), *],
224                DispatchType::$dis( $($arg),* )
225            )
226        };
227        (async ; $( $flag:ident ) *|$( $mod:ident ) *,$keyt:ident,$( $key:expr ), * => $dis:ident ) => {
228            $crate::bind_raw!(
229                vec![$(Mod::$mod), *],
230                Key::$keyt( $( $key ), * ),
231                vec![$(Flag::$flag), *],
232                DispatchType::$dis
233            )
234        };
235        (async ; $( $mod:ident ) *,$keyt:ident,$( $key:expr ), * => $dis:ident, $( $arg:expr ), *) => {
236            $crate::bind_raw!(
237                vec![$(Mod::$mod), *],
238                Key::$keyt( $( $key ), * ),
239                vec![],
240                DispatchType::$dis( $($arg),* )
241            )
242        };
243        (async ; $( $mod:ident ) *,$keyt:ident,$( $key:expr ), * => $dis:ident ) => {
244            $crate::bind_raw!(
245                vec![$(Mod::$mod), *],
246                Key::$keyt( $( $key ), * ),
247                vec![],
248                DispatchType::$dis
249            )
250        };
251    }
252}
253
254#[test]
255fn test_binds() {
256    use binds::*;
257    let binding = Binding {
258        mods: vec![Mod::SUPER],
259        key: Key::Key("v"),
260        flags: vec![],
261        dispatcher: DispatchType::ToggleFloating(None),
262    };
263    let built_bind = match Binder::gen_str(binding) {
264        Ok(v) => v,
265        Err(e) => panic!("Error occured: {e}"),
266    };
267    assert_eq!(built_bind, "SUPER,v,/togglefloating");
268}