hyprland 0.3.13

A unoffical rust wrapper for hyprland's IPC
Documentation
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
//! # Dispatch module
//!
//! This module is used for calling dispatchers and changing keywords
//!
//! ## Usage
//!
//! ```rust
//! use hyprland::shared::HResult;
//! use hyprland::dispatch::{Dispatch, DispatchType};
//! fn main() -> HResult<()> {
//!    Dispatch::call(DispatchType::Exec("kitty"))?;
//!
//!    Ok(())
//! }
//! ````

use crate::shared::*;
use std::string::ToString;
//use strum::Display;
use derive_more::Display;

/// This enum is for identifying a window
#[derive(Debug, Clone)]
pub enum WindowIdentifier<'a> {
    /// The address of a window
    Address(Address),
    /// A Regular Expression to match the window class (handled by Hyprland)
    ClassRegularExpression(&'a str),
    /// The window title
    Title(&'a str),
    /// The window's process Id
    ProcessId(u32),
}

impl std::fmt::Display for WindowIdentifier<'_> {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        let out = match self {
            WindowIdentifier::Address(addr) => format!("address:{addr}"),
            WindowIdentifier::ProcessId(id) => format!("pid:{id}"),
            WindowIdentifier::ClassRegularExpression(regex) => regex.to_string(),
            WindowIdentifier::Title(title) => format!("title:{title}"),
        };
        write!(f, "{out}")
    }
}

/// This enum holds the fullscreen types
#[derive(Debug, Clone, Display)]
pub enum FullscreenType {
    /// Fills the whole screen
    #[display(fmt = "0")]
    Real,
    /// Maximizes the window
    #[display(fmt = "1")]
    Maximize,
    /// Passes no param
    #[display(fmt = "")]
    NoParam,
}

/// This enum holds directions, typically used for moving
#[derive(Debug, Clone, Display)]
#[allow(missing_docs)]
pub enum Direction {
    #[display(fmt = "u")]
    Up,
    #[display(fmt = "d")]
    Down,
    #[display(fmt = "r")]
    Right,
    #[display(fmt = "l")]
    Left,
}

/// This enum is used for resizing and moving windows precisely
#[derive(Debug, Clone)]
pub enum Position {
    /// A delta
    Delta(i16, i16),
    /// The exact size
    Exact(i16, i16),
}

impl std::fmt::Display for Position {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        let out = match self {
            Position::Delta(x, y) => format!("{x} {y}"),
            Position::Exact(w, h) => format!("exact {w} {h}"),
        };
        write!(f, "{out}")
    }
}

/// This enum holds a direction for cycling
#[allow(missing_docs)]
#[derive(Debug, Clone, Display)]
pub enum CycleDirection {
    #[display(fmt = "")]
    Next,
    #[display(fmt = "prev")]
    Previous,
}

/// This enum holds a direction for switch windows in a group
#[allow(missing_docs)]
#[derive(Debug, Clone, Display)]
pub enum WindowSwitchDirection {
    #[display(fmt = "b")]
    Back,
    #[display(fmt = "f")]
    Forward,
}

/// This enum is used for identifying monitors
#[derive(Debug, Clone)]
pub enum MonitorIdentifier<'a> {
    /// The monitor that is to the specified direction of the active one
    Direction(Direction),
    /// The monitor id
    Id(u8),
    /// The monitor name
    Name(&'a str),
    /// The current monitor
    Current,
    /// The workspace relative to the current workspace
    Relative(i32),
}

impl std::fmt::Display for MonitorIdentifier<'_> {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        let out = match self {
            MonitorIdentifier::Direction(dir) => dir.to_string(),
            MonitorIdentifier::Id(id) => id.to_string(),
            MonitorIdentifier::Name(name) => name.to_string(),
            MonitorIdentifier::Current => "current".to_string(),
            MonitorIdentifier::Relative(int) => format_relative(*int, ""),
        };
        write!(f, "{out}")
    }
}

/// This enum holds corners
#[allow(missing_docs)]
#[derive(Debug, Clone)]
pub enum Corner {
    TopRight = 0,
    TopLeft = 1,
    BottomRight = 2,
    BottomLeft = 3,
}

/// This enum holds options that are applied to the current workspace
#[derive(Debug, Clone, Display)]
pub enum WorkspaceOptions {
    /// Makes all windows pseudo tiled
    #[display(fmt = "allfloat")]
    AllPseudo,
    /// Makes all windows float
    #[display(fmt = "allpseudo")]
    AllFloat,
}

/// This enum is for identifying workspaces that also includes the special workspace
#[derive(Debug, Clone)]
pub enum WorkspaceIdentifierWithSpecial<'a> {
    /// The workspace Id
    Id(WorkspaceId),
    /// The workspace relative to the current workspace
    Relative(i32),
    /// The workspace on the monitor relative to the current workspace
    RelativeMonitor(i32),
    /// The workspace on the monitor relative to the current workspace, including empty workspaces
    RelativeMonitorIncludingEmpty(i32),
    /// The open workspace relative to the current workspace
    RelativeOpen(i32),
    /// The previous Workspace
    Previous,
    /// The first available empty workspace
    Empty,
    /// The name of the workspace
    Name(&'a str),
    /// The special workspace
    Special(Option<&'a str>),
}

impl std::fmt::Display for WorkspaceIdentifierWithSpecial<'_> {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        use WorkspaceIdentifierWithSpecial::*;
        let out = match self {
            Id(id) => format!("{id}"),
            Name(name) => format!("name:{name}"),
            Relative(int) => format_relative(*int, ""),
            RelativeMonitor(int) => format_relative(*int, "m"),
            RelativeMonitorIncludingEmpty(int) => format_relative(*int, "r"),
            RelativeOpen(int) => format_relative(*int, "e"),
            Previous => "previous".to_string(),
            Empty => "empty".to_string(),
            Special(opt) => match opt {
                Some(name) => format!("special:{name}"),
                None => "special".to_string(),
            },
        };

        write!(f, "{out}")
    }
}

/// This enum is for identifying workspaces
#[derive(Debug, Clone)]
pub enum WorkspaceIdentifier<'a> {
    /// The workspace Id
    Id(WorkspaceId),
    /// The workspace relative to the current workspace
    Relative(i32),
    /// The workspace on the monitor relative to the current workspace
    RelativeMonitor(i32),
    /// The workspace on the monitor relative to the current workspace, including empty workspaces
    RelativeMonitorIncludingEmpty(i32),
    /// The open workspace relative to the current workspace
    RelativeOpen(i32),
    /// The previous Workspace
    Previous,
    /// The first available empty workspace
    Empty,
    /// The name of the workspace
    Name(&'a str),
}

impl std::fmt::Display for WorkspaceIdentifier<'_> {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        use WorkspaceIdentifier::*;
        let out = match self {
            Id(id) => format!("{id}"),
            Name(name) => format!("name:{name}"),
            Relative(int) => format_relative(*int, ""),
            RelativeMonitor(int) => format_relative(*int, "m"),
            RelativeMonitorIncludingEmpty(int) => format_relative(*int, "r"),
            RelativeOpen(int) => format_relative(*int, "e"),
            Previous => "previous".to_string(),
            Empty => "empty".to_string(),
        };

        write!(f, "{out}")
    }
}

/// This enum is the params to MoveWindow dispatcher
#[derive(Debug, Clone)]
pub enum WindowMove<'a> {
    /// Moves the window to a specified monitor
    Monitor(MonitorIdentifier<'a>),
    /// Moves the window in a specified direction
    Direction(Direction),
}

/// This enum holds every dispatcher
#[derive(Debug, Clone)]
pub enum DispatchType<'a> {
    /// This lets you use dispatchers not supported by hyprland-rs yet, please make issues before
    /// using
    Custom(
        /// Name of event
        &'a str,
        /// Args
        &'a str,
    ),
    /// This dispatcher changes the current cursor
    SetCursor(
        /// The cursor theme
        &'a str,
        /// The size
        u16,
    ),
    /// This dispatcher executes a program
    Exec(&'a str),
    /// This dispatcher passes a keybind to a window when called in a
    /// keybind, its used for global keybinds. And should **ONLY** be used with keybinds
    Pass(WindowIdentifier<'a>),
    /// Executes a Global Shortcut using the GlobalShortcuts portal.
    Global(&'a str),
    /// This dispatcher kills the active window/client
    KillActiveWindow,
    /// This dispatcher closes the specified window
    CloseWindow(WindowIdentifier<'a>),
    /// This dispatcher changes the current workspace
    Workspace(WorkspaceIdentifierWithSpecial<'a>),
    /// This dispatcher moves a window (focused if not specified) to a workspace
    MoveToWorkspace(
        WorkspaceIdentifierWithSpecial<'a>,
        Option<WindowIdentifier<'a>>,
    ),
    /// This dispatcher moves a window (focused if not specified) to a workspace, without switching to that
    /// workspace
    MoveToWorkspaceSilent(
        WorkspaceIdentifierWithSpecial<'a>,
        Option<WindowIdentifier<'a>>,
    ),
    /// This dispatcher moves the focused window to a specified workspace, and
    /// changes the active workspace aswell
    #[deprecated(since = "0.3.13", note = "use MoveToWorkspace(work, None) instead")]
    MoveFocusedWindowToWorkspace(WorkspaceIdentifier<'a>),
    /// This dispatcher moves the focused window to a specified workspace, and
    /// does not change workspaces
    #[deprecated(
        since = "0.3.13",
        note = "use MoveToWorkspaceSilent(work, None) instead"
    )]
    MoveFocusedWindowToWorkspaceSilent(WorkspaceIdentifier<'a>),
    /// This dispatcher floats a window (current if not specified)
    ToggleFloating(Option<WindowIdentifier<'a>>),
    /// This dispatcher toggles the current window fullscreen state
    ToggleFullscreen(FullscreenType),
    /// This dispatcher toggles the focused window’s internal
    /// fullscreen state without altering the geometry
    ToggleFakeFullscreen,
    /// This dispatcher sets the DPMS status for all monitors
    ToggleDPMS(bool, Option<&'a str>),
    /// This dispatcher toggles pseudo tiling for the current window
    TogglePseudo,
    /// This dispatcher pins the active window to all workspaces
    TogglePin,
    /// This dispatcher moves the window focus in a specified direction
    MoveFocus(Direction),
    /// This dispatcher moves the current window to a monitor or in a specified direction
    MoveWindow(WindowMove<'a>),
    /// This dispatcher centers the active window
    CenterWindow,
    /// This dispatcher resizes the active window using a [`Position`][Position] enum
    ResizeActive(Position),
    /// This dispatcher moves the active window using a [`Position`][Position] enum
    MoveActive(Position),
    /// This dispatcher resizes the specified window using a [`Position`][Position] enum
    ResizeWindowPixel(Position, WindowIdentifier<'a>),
    /// This dispatcher moves the specified window using a [`Position`][Position] enum
    MoveWindowPixel(Position, WindowIdentifier<'a>),
    /// This dispatcher cycles windows using a specified direction
    CycleWindow(CycleDirection),
    /// This dispatcher swaps windows using a specified direction
    SwapWindow(CycleDirection),
    /// This dispatcher focuses a specified window
    FocusWindow(WindowIdentifier<'a>),
    /// This dispatcher focuses a specified monitor
    FocusMonitor(MonitorIdentifier<'a>),
    /// This dispatcher changed the split ratio
    ChangeSplitRatio(f32),
    /// This dispatcher toggle opacity for the current window/client
    ToggleOpaque,
    /// This dispatcher moves the cursor to a specified corner of a window
    MoveCursorToCorner(Corner),
    /// This dispatcher moves the cursor to a specified position
    /// (x, y) where x starts from left to right, and y starts from top to bottom
    MoveCursor(i64, i64),
    /// This dispatcher applied a option to all windows in a workspace
    WorkspaceOption(WorkspaceOptions),
    /// This dispatcher renames a workspace
    RenameWorkspace(WorkspaceId, Option<&'a str>),
    /// This exits Hyprland **(DANGEROUS)**
    Exit,
    /// This dispatcher forces the renderer to reload
    ForceRendererReload,
    /// This dispatcher moves the current workspace to a specified monitor
    MoveCurrentWorkspaceToMonitor(MonitorIdentifier<'a>),
    /// This dispatcher moves a specified workspace to a specified monitor
    MoveWorkspaceToMonitor(WorkspaceIdentifier<'a>, MonitorIdentifier<'a>),
    /// This dispatcher swaps the active workspaces of two monitors
    SwapActiveWorkspaces(MonitorIdentifier<'a>, MonitorIdentifier<'a>),
    /// This dispatcher brings the active window to the top of the stack
    BringActiveToTop,
    /// This toggles the special workspace (AKA scratchpad)
    ToggleSpecialWorkspace(Option<String>),
    /// This dispatcher jump to urgent or the last window
    FocusUrgentOrLast,
    /// Switch focus from current to previously focused window
    FocusCurrentOrLast,

    // LAYOUT DISPATCHERS
    // DWINDLE
    /// Toggles the split (top/side) of the current window. `preserve_split` must be enabled for toggling to work.
    ToggleSplit,

    // MASTER
    /// Swaps the current window with master.
    /// If the current window is the master,
    /// swaps it with the first child.
    SwapWithMaster(SwapWithMasterParam),
    /// Focuses the master window.
    FocusMaster(FocusMasterParam),
    /// Adds a master to the master side. That will be the active window,
    /// if it’s not a master, or the first non-master window.
    AddMaster,
    /// Removes a master from the master side. That will be the
    /// active window, if it’s a master, or the last master window.
    RemoveMaster,
    /// Sets the orientation for the current workspace to left
    /// (master area left, slave windows to the right, vertically stacked)
    OrientationLeft,
    /// Sets the orientation for the current workspace to right
    /// (master area right, slave windows to the left, vertically stacked)
    OrientationRight,
    /// Sets the orientation for the current workspace to top
    /// (master area top, slave windows to the bottom, horizontally stacked)
    OrientationTop,
    /// Sets the orientation for the current workspace to bottom
    /// (master area bottom, slave windows to the top, horizontally stacked)
    OrientationBottom,
    /// Sets the orientation for the current workspace to center
    /// (master area center, slave windows alternate to the left and right, vertically stacked)
    OrientationCenter,
    /// Cycle to the next orientation for the current workspace (clockwise)
    OrientationNext,
    /// Cycle to the previous orientation for the current workspace (counter-clockwise)
    OrientationPrev,

    // Group Dispatchers
    /// Toggles the current active window into a group
    ToggleGroup,
    /// Switches to the next window in a group.
    ChangeGroupActive(WindowSwitchDirection),
    /// Locks the groups
    LockGroups(LockType),
    /// Moves the active window into a group in a specified direction
    MoveIntoGroup(Direction),
    /// Moves the active window out of a group.
    MoveOutOfGroup,
}

/// Enum used with [DispatchType::LockGroups], to determine how to lock/unlock
#[derive(Debug, Clone, Copy, Display, PartialEq, Eq, PartialOrd, Ord)]
pub enum LockType {
    /// Lock Group
    #[display(fmt = "lock")]
    Lock,
    /// Unlock Group
    #[display(fmt = "unlock")]
    Unlock,
    /// Toggle lock state of Group
    #[display(fmt = "toggle")]
    ToggleLock,
}

/// Param for [SwapWithMaster] dispatcher
#[derive(Debug, Clone, Display)]
pub enum SwapWithMasterParam {
    /// New focus is the new master window
    #[display(fmt = "master")]
    Master,
    /// New focus is the new child
    #[display(fmt = "child")]
    Child,
    /// Keep the focus of the previously focused window
    #[display(fmt = "auto")]
    Auto,
}

/// Param for [FocusMaster] dispatcher
#[derive(Debug, Clone, Display)]
pub enum FocusMasterParam {
    /// Focus stays at master, (even if it was selected before)
    #[display(fmt = "master")]
    Master,
    /// If the current window is the master, focuses the first child
    #[display(fmt = "auto")]
    Auto,
}

fn format_relative<T: Ord + std::fmt::Display + num_traits::Signed>(
    int: T,
    extra: &'_ str,
) -> String {
    if int.is_positive() {
        format!("{extra}+{int}")
    } else if int.is_negative() {
        format!("{extra}-{int}", int = int.abs())
    } else {
        "+0".to_string()
    }
}

pub(crate) fn gen_dispatch_str(cmd: DispatchType, dispatch: bool) -> crate::Result<CommandContent> {
    use DispatchType::*;
    let sep = if dispatch { " " } else { "," };
    let string_to_pass = match &cmd {
        Custom(name, args) => format!("{name}{sep}{args}"),
        Exec(sh) => format!("exec{sep}{sh}"),
        Pass(win) => format!("pass{sep}{win}"),
        Global(name) => format!("global{sep}{name}"),
        KillActiveWindow => "killactive".to_string(),
        CloseWindow(win) => format!("closewindow{sep}{win}"),
        Workspace(work) => format!("workspace{sep}{work}"),
        MoveToWorkspace(work, Some(win)) => format!("movetoworkspace{sep}{work},{win}"),
        MoveToWorkspace(work, None) => format!("movetoworkspace{sep}{work}"),
        MoveToWorkspaceSilent(work, Some(win)) => format!("movetoworkspacesilent{sep}{work},{win}"),
        MoveToWorkspaceSilent(work, None) => format!("movetoworkspacesilent{sep}{work}"),
        MoveFocusedWindowToWorkspace(work) => format!("movetoworkspace{sep}{work}"),
        MoveFocusedWindowToWorkspaceSilent(work) => format!("movetoworkspacesilent{sep}{work}"),
        ToggleFloating(Some(v)) => format!("togglefloating{sep}{v}"),
        ToggleFloating(None) => "togglefloating".to_string(),
        ToggleFullscreen(ftype) => format!("fullscreen{sep}{ftype}"),
        ToggleFakeFullscreen => "fakefullscreen".to_string(),
        ToggleDPMS(stat, mon) => {
            format!(
                "dpms{sep}{} {}",
                if *stat { "on" } else { "off" },
                mon.unwrap_or_default()
            )
        }
        TogglePseudo => "pseudo".to_string(),
        TogglePin => "pin".to_string(),
        MoveFocus(dir) => format!("movefocus{sep}{dir}",),
        MoveWindow(ident) => format!(
            "movewindow{sep}{}",
            match ident {
                WindowMove::Direction(dir) => dir.to_string(),
                WindowMove::Monitor(mon) => format!("mon:{mon}"),
            }
        ),
        CenterWindow => "centerwindow".to_string(),
        ResizeActive(pos) => format!("resizeactive{sep}{pos}"),
        MoveActive(pos) => format!("moveactive {pos}"),
        ResizeWindowPixel(pos, win) => format!("resizewindowpixel{sep}{pos},{win}"),
        MoveWindowPixel(pos, win) => format!("movewindowpixel{sep}{pos},{win}"),
        CycleWindow(dir) => format!("cyclenext{sep}{dir}"),
        SwapWindow(dir) => format!("swapnext{sep}{dir}"),
        FocusWindow(win) => format!("focuswindow{sep}{win}"),
        FocusMonitor(mon) => format!("focusmonitor{sep}{mon}"),
        ChangeSplitRatio(ratio) => format!("splitratio {ratio}"),
        ToggleOpaque => "toggleopaque".to_string(),
        MoveCursorToCorner(corner) => format!("movecursortocorner{sep}{}", corner.clone() as u8),
        MoveCursor(x, y) => format!("movecursor{sep}{x} {y}"),
        WorkspaceOption(opt) => format!("workspaceopt{sep}{opt}"),
        Exit => "exit".to_string(),
        ForceRendererReload => "forcerendererreload".to_string(),
        MoveCurrentWorkspaceToMonitor(mon) => format!("movecurrentworkspacetomonitor{sep}{mon}"),
        MoveWorkspaceToMonitor(work, mon) => format!("moveworkspacetomonitor{sep}{work} {mon}"),
        ToggleSpecialWorkspace(Some(name)) => format!("togglespecialworkspace {name}"),
        ToggleSpecialWorkspace(None) => "togglespecialworkspace".to_string(),
        RenameWorkspace(id, name) => {
            format!(
                "renameworkspace{sep}{id} {}",
                name.unwrap_or(&id.to_string())
            )
        }
        SwapActiveWorkspaces(mon, mon2) => format!("swapactiveworkspaces{sep}{mon} {mon2}",),
        BringActiveToTop => "bringactivetotop".to_string(),
        SetCursor(theme, size) => format!("{theme} {}", *size),
        FocusUrgentOrLast => "focusurgentorlast".to_string(),
        FocusCurrentOrLast => "focuscurrentorlast".to_string(),
        ToggleSplit => "togglesplit".to_string(),
        SwapWithMaster(param) => format!("swapwithmaster{sep}{param}"),
        FocusMaster(param) => format!("focusmaster{sep}{param}"),
        AddMaster => "addmaster".to_string(),
        RemoveMaster => "removemaster".to_string(),
        OrientationLeft => "orientationleft".to_string(),
        OrientationRight => "orientationright".to_string(),
        OrientationTop => "orientationtop".to_string(),
        OrientationBottom => "orientationbottom".to_string(),
        OrientationCenter => "orientationcenter".to_string(),
        OrientationNext => "orientationnext".to_string(),
        OrientationPrev => "orientationprev".to_string(),
        ToggleGroup => "togglegroup".to_string(),
        ChangeGroupActive(dir) => format!("changegroupactive{sep}{dir}"),
        LockGroups(how) => format!("lockgroups{sep}{how}"),
        MoveIntoGroup(dir) => format!("moveintogroup{sep}{dir}"),
        MoveOutOfGroup => "moveoutofgroup".to_string(),
    };

    if let SetCursor(_, _) = cmd {
        Ok(command!(JSON, "setcursor {string_to_pass}"))
    } else if dispatch {
        Ok(command!(JSON, "dispatch {string_to_pass}"))
    } else {
        Ok(command!(Empty, "{string_to_pass}"))
    }
}

/// The struct that provides all dispatching methods
pub struct Dispatch;

impl Dispatch {
    /// This function calls a specified dispatcher (blocking)
    ///
    /// ```rust
    /// # use hyprland::shared::HResult;
    /// # fn main() -> HResult<()> {
    /// use hyprland::dispatch::{DispatchType,Dispatch};
    /// // This is an example of just one dispatcher, there are many more!
    /// Dispatch::call(DispatchType::Exec("kitty"))
    /// # }
    /// ```
    pub fn call(dispatch_type: DispatchType) -> crate::Result<()> {
        let socket_path = get_socket_path(SocketType::Command);
        let output = write_to_socket_sync(socket_path, gen_dispatch_str(dispatch_type, true)?);

        match output {
            Ok(msg) => match msg.as_str() {
                "ok" => Ok(()),
                msg => Err(HyprError::NotOkDispatch(msg.to_string())),
            },
            Err(error) => Err(error),
        }
    }

    /// This function calls a specified dispatcher (async)
    ///
    /// ```rust
    /// # use hyprland::shared::HResult;
    /// # async fn function() -> HResult<()> {
    /// use hyprland::dispatch::{DispatchType,Dispatch};
    /// // This is an example of just one dispatcher, there are many more!
    /// Dispatch::call_async(DispatchType::Exec("kitty")).await?;
    /// # Ok(())
    /// # }
    /// ```
    pub async fn call_async(dispatch_type: DispatchType<'_>) -> crate::Result<()> {
        let socket_path = get_socket_path(SocketType::Command);
        let output = write_to_socket(socket_path, gen_dispatch_str(dispatch_type, true)?).await;

        match output {
            Ok(msg) => match msg.as_str() {
                "ok" => Ok(()),
                msg => Err(HyprError::NotOkDispatch(msg.to_string())),
            },
            Err(error) => Err(error),
        }
    }
}

/// Macro abstraction over [Dispatch::call]
#[macro_export]
macro_rules! dispatch {
    ($dis:ident, $( $arg:expr ), *) => {
        Dispatch::call(DispatchType::$dis($($arg), *))
    };
    (async; $dis:ident, $( $arg:expr ), *) => {
        Dispatch::call_async(DispatchType::$dis($($arg), *))
    };
}