hyprshell_config_lib/
explain.rs1use crate::Config;
2use std::fmt::Write;
3use std::path::Path;
4
5const BOLD: &str = "\x1b[1m";
6const ITALIC: &str = "\x1b[3m";
7const BLUE: &str = "\x1b[34m";
8const GREEN: &str = "\x1b[32m";
9const RESET: &str = "\x1b[0m";
10
11#[must_use]
12pub fn explain(
13 config: &Config,
14 config_path: &Path,
15 enable_color: bool,
16 enable_header: bool,
17) -> String {
18 let (bold, italic, blue, green, reset) = if enable_color {
19 (BOLD, ITALIC, BLUE, GREEN, RESET)
20 } else {
21 ("", "", "", "", "")
22 };
23
24 let config_path_display = config_path.display();
25 let mut builder = if enable_header {
26 format!(
27 "{bold}{green}Config is valid{reset} ({config_path_display})\n{bold}Explanation{reset} ({blue}blue{reset} are keys, {bold}{blue}bold blue{reset} keys can be configured in config):{reset}\n",
28 )
29 } else {
30 String::new()
31 };
32
33 if let Some(windows) = &config.windows {
34 if let Some(overview) = &windows.overview {
35 let _ = builder.write_str(&format!(
36 "Use {bold}{blue}{}{reset} + {bold}{blue}{}{reset} to open the Overview. Use {blue}tab{reset} and {blue}grave{reset} / {blue}shift{reset} + {blue}tab{reset} to select a different window, press {blue}return{reset} to switch\n\
37 You can also use the {blue}arrow keys{reset} or {bold}{blue}{}{reset} + vim keys to navigate the workspaces. Use {blue}Esc{reset} to close the overview.\n",
38 overview.modifier,
39 overview.key,
40 overview.launcher.launch_modifier
41 ));
42 let _ = builder.write_str(&format!(
43 "After opening the Overview the {bold}Launcher{reset} is available:\n"
44 ));
45 let mut any_plugin = false;
46 if let Some(_applications) = overview.launcher.plugins.applications.as_ref() {
47 any_plugin = true;
48 let _ = builder.write_str(&format!("\t- Start typing to search through applications (sorted by how often they were opened). Press {blue}return{reset} to launch the first app, use {blue}Ctrl{reset} + {blue}1{reset}/{blue}2{reset}/{blue}3{reset}/... to open the second, third, etc.\n"));
49 }
50 if overview.launcher.plugins.terminal.is_some() {
51 any_plugin = true;
52 let _ = builder.write_str(&format!(
53 "\t- Press {blue}Ctrl{reset} + {blue}t{reset} to run the typed command in a terminal.\n"
54 ));
55 }
56 if overview.launcher.plugins.shell.is_some() {
57 any_plugin = true;
58 let _ = builder.write_str(&format!(
59 "\t- Press {blue}Ctrl{reset} + {blue}r{reset} to run the typed command in the background.\n",
60 ));
61 }
62 if let Some(engines) = &overview.launcher.plugins.websearch {
63 any_plugin = true;
64 let _ = builder.write_str(&format!("\t- Press {blue}Ctrl{reset} + {bold}{blue}<key>{reset} to search the typed text in any of the configured SearchEngines: {}.\n",
65 engines.engines.iter().map(|e| e.name.to_string()).collect::<Vec<_>>().join(", ")));
66 }
67 if overview.launcher.plugins.calc.is_some() {
68 any_plugin = true;
69 let _ = builder.write_str(
70 "\t- Typing a mathematical expression will calculate it and display the result in the launcher.\n",
71 );
72 }
73 if overview.launcher.plugins.path.is_some() {
74 any_plugin = true;
75 let _ = builder.write_str(
76 "\t- Paths (starting with ~ or /) can be open in default file-manager.\n",
77 );
78 }
79 if overview.launcher.plugins.actions.is_some() {
80 any_plugin = true;
81 let _ = builder.write_str(
82 "\t- Type Reboot/Shutdown/etc. to run corresponding commands. Type `actions` to see all available ones.\n",
83 );
84 }
85 if !any_plugin {
86 let _ = builder.write_str(&format!(
87 "{italic}\t<No plugins enabled in launcher>{reset}\n"
88 ));
89 }
90 } else {
91 let _ = builder.write_str(&format!("{italic}<Overview disabled>{reset}\n"));
92 }
93 builder.push('\n');
94
95 if let Some(switch) = &windows.switch {
96 let _ = builder.write_str(&format!(
97 "Press {bold}{blue}{}{reset} + {blue}tab{reset} and hold {bold}{blue}{}{reset} to view recently used applications. Press {blue}tab{reset} and {blue}grave{reset} / {blue}shift{reset} + {blue}tab{reset} to select a different window, release {bold}{blue}{}{reset} to close the window.\n",
98 switch.modifier,
99 switch.modifier,
100 switch.modifier,
101 ));
102 } else {
103 let _ = builder.write_str(&format!("{italic}<Switch mode disabled>{reset}\n"));
104 }
105 } else {
106 let _ = builder.write_str(&format!("{italic}<Windows disabled>{reset}\n"));
107 }
108
109 builder
110}
111
112#[cfg(test)]
113mod tests {
114 use super::*;
115 use crate::structs::*;
116 use std::path::PathBuf;
117
118 fn create_test_config() -> Config {
119 Config {
120 windows: Some(Windows {
121 overview: Some(Overview::default()),
122 switch: Some(Switch::default()),
123 ..Default::default()
124 }),
125 ..Default::default()
126 }
127 }
128
129 #[test_log::test]
130 #[test_log(default_log_filter = "trace")]
131 fn test_explain_with_overview() {
132 const CONFIG: &str = r"Config is valid (/test/config.ron)
133Explanation (blue are keys, bold blue keys can be configured in config):
134Use Super + super_l to open the Overview. Use tab and grave / shift + tab to select a different window, press return to switch
135You can also use the arrow keys or Ctrl + vim keys to navigate the workspaces. Use Esc to close the overview.
136After opening the Overview the Launcher is available:
137 - Start typing to search through applications (sorted by how often they were opened). Press return to launch the first app, use Ctrl + 1/2/3/... to open the second, third, etc.
138 - Press Ctrl + t to run the typed command in a terminal.
139 - Press Ctrl + <key> to search the typed text in any of the configured SearchEngines: Google, Wikipedia.
140 - Typing a mathematical expression will calculate it and display the result in the launcher.
141 - Paths (starting with ~ or /) can be open in default file-manager.
142 - Type Reboot/Shutdown/etc. to run corresponding commands. Type `actions` to see all available ones.
143
144Press Alt + tab and hold Alt to view recently used applications. Press tab and grave / shift + tab to select a different window, release Alt to close the window.
145";
146 let config = create_test_config();
147 let path = PathBuf::from("/test/config.ron");
148 let result = explain(&config, &path, false, true);
149 assert_eq!(result, CONFIG);
150 }
151
152 #[test_log::test]
153 #[test_log(default_log_filter = "trace")]
154 fn test_explain_without_overview() {
155 const CONFIG: &str = r"Config is valid (/test/config.ron)
156Explanation (blue are keys, bold blue keys can be configured in config):
157<Overview disabled>
158
159Press Alt + tab and hold Alt to view recently used applications. Press tab and grave / shift + tab to select a different window, release Alt to close the window.
160";
161 let mut config = create_test_config();
162 config
163 .windows
164 .as_mut()
165 .expect("config option missing")
166 .overview = None;
167 let path = PathBuf::from("/test/config.ron");
168 let result = explain(&config, &path, false, true);
169 assert_eq!(result, CONFIG);
170 }
171
172 #[test_log::test]
173 #[test_log(default_log_filter = "trace")]
174 fn test_explain_without_switch() {
175 const CONFIG: &str = r"Config is valid (/test/config.ron)
176Explanation (blue are keys, bold blue keys can be configured in config):
177Use Super + super_l to open the Overview. Use tab and grave / shift + tab to select a different window, press return to switch
178You can also use the arrow keys or Ctrl + vim keys to navigate the workspaces. Use Esc to close the overview.
179After opening the Overview the Launcher is available:
180 - Start typing to search through applications (sorted by how often they were opened). Press return to launch the first app, use Ctrl + 1/2/3/... to open the second, third, etc.
181 - Press Ctrl + t to run the typed command in a terminal.
182 - Press Ctrl + <key> to search the typed text in any of the configured SearchEngines: Google, Wikipedia.
183 - Typing a mathematical expression will calculate it and display the result in the launcher.
184 - Paths (starting with ~ or /) can be open in default file-manager.
185 - Type Reboot/Shutdown/etc. to run corresponding commands. Type `actions` to see all available ones.
186
187<Switch mode disabled>
188";
189 let mut config = create_test_config();
190 config
191 .windows
192 .as_mut()
193 .expect("config option missing")
194 .switch = None;
195 let path = PathBuf::from("/test/config.ron");
196 let result = explain(&config, &path, false, true);
197 assert_eq!(result, CONFIG);
198 }
199
200 #[test_log::test]
201 #[test_log(default_log_filter = "trace")]
202 fn test_explain_without_plugins() {
203 const CONFIG: &str = r"Use Super + super_l to open the Overview. Use tab and grave / shift + tab to select a different window, press return to switch
204You can also use the arrow keys or Ctrl + vim keys to navigate the workspaces. Use Esc to close the overview.
205After opening the Overview the Launcher is available:
206 <No plugins enabled in launcher>
207
208Press Alt + tab and hold Alt to view recently used applications. Press tab and grave / shift + tab to select a different window, release Alt to close the window.
209";
210 let mut config = create_test_config();
211 config
212 .windows
213 .as_mut()
214 .expect("config option missing")
215 .overview
216 .as_mut()
217 .expect("config option missing")
218 .launcher
219 .plugins = Plugins {
220 applications: None,
221 terminal: None,
222 shell: None,
223 websearch: None,
224 calc: None,
225 path: None,
226 actions: None,
227 };
228 let path = PathBuf::from("/test/config.ron");
229 let result = explain(&config, &path, false, false);
230 assert_eq!(result, CONFIG);
231 }
232}