1use std::string::ToString;
2
3use crate::errors::{QueryError, ReplyError};
4use crate::parser::utils::from_hex_to_id;
5use crate::selectors::{
6 DesktopSelector, MonitorSelector, NodeSelector, Selector,
7};
8use crate::socket::{self, BspcCommunication};
9use crate::tree::Tree;
10use crate::Id;
11
12fn query(
13 query_type: &str,
14 names_flag: bool,
15 selector: Option<&str>,
16 monitor_selector: Option<&str>,
17 desktop_selector: Option<&str>,
18 node_selector: Option<&str>,
19) -> Result<Vec<Id>, ReplyError> {
20 let mut conn = socket::connect()?;
21 let mut request = format!("query\x00--{query_type}\x00");
22
23 if names_flag {
24 if query_type == "nodes" {
25 return Err(ReplyError::QueryError(QueryError::InvalidRequest(
26 "You can't apply --names for nodes query request".to_string(),
27 )));
28 } else {
29 request = format!("{request}--names\x00");
30 }
31 }
32
33 if let Some(sel) = selector {
34 request = format!("{request}{sel}\x00");
35 }
36
37 if let Some(sel) = monitor_selector {
38 request = format!("{request}--monitor\x00{sel}\x00");
39 }
40
41 if let Some(sel) = desktop_selector {
42 request = format!("{request}--desktop\x00{sel}\x00");
43 }
44
45 if let Some(sel) = node_selector {
46 request = format!("{request}--node\x00{sel}\x00");
47 }
48
49 conn.send_message(&request)?;
50
51 let reply = conn.receive_message()?;
52
53 let mut ids = Vec::new();
54
55 for reply_id in reply.iter() {
56 let id = from_hex_to_id(reply_id)?;
57 ids.push(id);
58 }
59
60 Ok(ids)
61}
62
63pub fn query_nodes(
65 selector: Option<NodeSelector>,
66 monitor_selector: Option<MonitorSelector>,
67 desktop_selector: Option<DesktopSelector>,
68 node_selector: Option<NodeSelector>,
69) -> Result<Vec<Id>, ReplyError> {
70 query(
71 "nodes",
72 false,
73 extract(&selector)?,
74 extract(&monitor_selector)?,
75 extract(&desktop_selector)?,
76 extract(&node_selector)?,
77 )
78}
79
80pub fn query_desktops(
82 names_flag: bool,
83 selector: Option<DesktopSelector>,
84 monitor_selector: Option<MonitorSelector>,
85 desktop_selector: Option<DesktopSelector>,
86 node_selector: Option<NodeSelector>,
87) -> Result<Vec<Id>, ReplyError> {
88 query(
89 "desktops",
90 names_flag,
91 extract(&selector)?,
92 extract(&monitor_selector)?,
93 extract(&desktop_selector)?,
94 extract(&node_selector)?,
95 )
96}
97
98fn extract<S>(selector: &Option<S>) -> Result<Option<&str>, ReplyError>
99where
100 S: Selector,
101{
102 if let Some(sel) = selector {
103 if !sel.is_valid() {
104 return Err(ReplyError::InvalidSelector(format!(
105 "This {} selector is invalid: '{}'",
106 sel.kind(),
107 sel.extract(),
108 )));
109 }
110
111 return Ok(Some(sel.extract()));
112 }
113
114 Ok(None)
115}
116
117pub fn query_monitors(
119 names_flag: bool,
120 selector: Option<MonitorSelector>,
121 monitor_selector: Option<MonitorSelector>,
122 desktop_selector: Option<DesktopSelector>,
123 node_selector: Option<NodeSelector>,
124) -> Result<Vec<Id>, ReplyError> {
125 query(
126 "monitors",
127 names_flag,
128 extract(&selector)?,
129 extract(&monitor_selector)?,
130 extract(&desktop_selector)?,
131 extract(&node_selector)?,
132 )
133}
134
135pub fn query_tree(
142 monitor_selector: Option<MonitorSelector>,
143 desktop_selector: Option<DesktopSelector>,
144 node_selector: Option<NodeSelector>,
145) -> Result<Tree, ReplyError> {
146 let mut conn = socket::connect()?;
147 let mut request = "query\x00--tree\x00".to_string();
148
149 let monitor_selector = extract(&monitor_selector)?;
150 let desktop_selector = extract(&desktop_selector)?;
151 let node_selector = extract(&node_selector)?;
152
153 if let Some(sel) = monitor_selector {
154 request = format!("{request}--monitor\x00{sel}\x00");
155 }
156
157 if let Some(sel) = desktop_selector {
158 request = format!("{request}--desktop\x00{sel}\x00");
159 }
160
161 if let Some(sel) = node_selector {
162 request = format!("{request}--node\x00{sel}\x00");
163 }
164
165 conn.send_message(&request)?;
166
167 let reply = conn.receive_message()?;
168
169 if reply.len() > 1 {
170 panic!("{}", format!("Something is weird, reply has more than one element, this is debug log: {:#?}", reply));
172 }
173
174 let reply = &reply[0];
175
176 if node_selector.is_some() {
177 return Ok(Tree::Node(serde_json::from_str(reply)?));
178 }
179
180 if desktop_selector.is_some() {
181 return Ok(Tree::Desktop(serde_json::from_str(reply)?));
182 }
183
184 if monitor_selector.is_some() {
185 return Ok(Tree::Monitor(serde_json::from_str(reply)?));
186 }
187
188 Err(ReplyError::QueryError(QueryError::InvalidRequest(
189 "No options were given".to_string(),
190 )))
191
192 }
204
205#[cfg(test)]
206mod test {
207 use super::*;
208 use crate::events::*;
209 #[test]
223 fn test_fullscreen_node() {
224 let node_request = format!(".fullscreen.window");
225 let query_result =
226 query_nodes(None, None, None, Some(NodeSelector(&node_request)));
227
228 println!("{query_result:#?}");
229 }
230
231 #[test]
232 fn test_query_tree() {
233 let tree =
234 query_tree(Some(MonitorSelector("focused")), None, None).unwrap();
235
236 println!("{tree:#?}");
237 }
238}