sway_workspace_manager/
lib.rs

1use swayipc::{Connection, Event, EventType, WorkspaceChange};
2
3mod command;
4mod workspaces;
5
6pub use command::{Command, Position};
7pub use workspaces::{OrderedWorkspaces, Workspaces};
8
9fn process_event(
10    connection: &mut Connection,
11    event: Result<Event, swayipc::Error>,
12) -> Result<(), swayipc::Error> {
13    if let Event::Workspace(event) = event? {
14        if event.change == WorkspaceChange::Empty {
15            Workspaces::get(connection)?.reorder(connection)?;
16        }
17    }
18
19    Ok(())
20}
21
22pub fn run(
23    connection: &mut Connection,
24    mut workspaces: OrderedWorkspaces,
25    command: Command,
26) -> Result<(), swayipc::Error> {
27    let num_workspaces = workspaces.names().len() - 1;
28
29    match command {
30        Command::Reorder { daemon: false } => (),
31        Command::Reorder { daemon: true } => {
32            // event loop
33            for event in Connection::new()?.subscribe([EventType::Workspace])? {
34                let result = process_event(connection, event);
35
36                if let Err(err) = result {
37                    eprintln!("{err}");
38                }
39            }
40        }
41
42        Command::Switch { target, carry } => {
43            let target_index = target.num_existing(workspaces.current_index(), num_workspaces)?;
44            let target_name = workspaces.name(target_index);
45
46            if carry {
47                // carrying out of an empty workspace silently fails
48                connection.run_command(format!(
49                    "move container to workspace \"{target_index}{target_name}\""
50                ))?;
51            }
52
53            connection.run_command(format!("workspace \"{target_index}{target_name}\""))?;
54
55            Workspaces::get(connection)?.reorder(connection)?;
56        }
57
58        Command::Create { target, carry } => {
59            let target_index = target.num_new(workspaces.current_index(), num_workspaces)?;
60
61            workspaces.insert(connection, target_index)?;
62
63            if carry {
64                // carrying out of an empty workspace silently fails
65                connection
66                    .run_command(format!("move container to workspace \"{target_index}\""))?;
67            }
68
69            connection.run_command(format!("workspace \"{target_index}\""))?;
70
71            Workspaces::get(connection)?.reorder(connection)?;
72        }
73
74        Command::Swap { target } => {
75            let current_index = workspaces.current_index();
76            let current_name = &workspaces.names()[current_index].as_ref().unwrap();
77
78            let target_index = target.num_existing(workspaces.current_index(), num_workspaces)?;
79            let target_name = &workspaces.names()[target_index].as_ref().unwrap();
80
81            connection.run_command(format!(
82                "rename workspace \"{target_index}{target_name}\" to a"
83            ))?;
84            connection.run_command(format!(
85                "rename workspace \"{current_index}{current_name}\" to \"{target_index}{current_name}\""
86            ))?;
87            connection.run_command(format!(
88                "rename workspace a to \"{current_index}{target_name}\""
89            ))?;
90        }
91
92        Command::Rename { new_name } => {
93            let current_index = workspaces.current_index();
94            let current_name = &workspaces.names()[current_index].as_ref().unwrap();
95
96            if !new_name.is_empty() {
97                connection.run_command(format!(
98                    "rename workspace \"{current_index}{current_name}\" to \"{current_index}:{new_name}\""
99                ))?;
100            } else {
101                connection.run_command(format!(
102                    "rename workspace \"{current_index}{current_name}\" to \"{current_index}\""
103                ))?;
104            }
105        }
106    }
107
108    Ok(())
109}