hyprshell_config_lib/
explain.rs

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