Skip to main content

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