Skip to main content

quick_links_rofi/
link.rs

1use crate::config::Config;
2use crate::config::I3Switcher;
3use crate::config::WorkspaceSwitcher;
4use crate::input::Items;
5use anyhow::anyhow;
6use std::io::Write;
7use std::process::Command;
8use std::process::Output;
9use std::process::Stdio;
10
11pub trait ExecSwitcher {
12    fn exec(&self) -> Option<Result<Output, std::io::Error>>;
13}
14
15impl ExecSwitcher for WorkspaceSwitcher {
16    fn exec(&self) -> Option<Result<Output, std::io::Error>> {
17        if let Some(command) = &self.custom {
18            command.exec()
19        } else if let Some(i3_swicth) = &self.i3 {
20            i3_swicth.exec()
21        } else {
22            None
23        }
24    }
25}
26
27impl ExecSwitcher for String {
28    fn exec(&self) -> Option<Result<Output, std::io::Error>> {
29        let values: Vec<String> = self.split(" ").map(|s| s.to_string()).collect();
30        let comm = Command::new(values.first()?)
31            .args(values[1..].iter())
32            .output();
33        Some(comm)
34    }
35}
36
37impl ExecSwitcher for I3Switcher {
38    fn exec(&self) -> Option<Result<Output, std::io::Error>> {
39        Some(
40            Command::new("i3-msg")
41                .args([
42                    "workspace",
43                    "number",
44                    self.workspace_number.to_string().as_str(),
45                ])
46                .output(),
47        )
48    }
49}
50
51pub fn launch_rofi(items: &Items, config: &Config) -> anyhow::Result<Option<String>> {
52    let names = items.get_names();
53
54    let mut child = Command::new("rofi")
55        .args(["-dmenu", "-i", "-theme", config.theme.as_str()])
56        .stdin(Stdio::piped())
57        .stdout(Stdio::piped())
58        .spawn()?;
59
60    let mut stdin = child.stdin.take().ok_or(anyhow!("Cannot open stdin"))?;
61    std::thread::spawn(move || {
62        stdin
63            .write_all(names.as_bytes())
64            .expect("Failed to write to stdin");
65    });
66    let output = child.wait_with_output()?;
67
68    if output.status.success() {
69        let output_string = std::str::from_utf8(&output.stdout)?;
70        if output_string.trim().is_empty() {
71            Err(anyhow!("Empty selection"))
72        } else {
73            Ok(Some(String::from(output_string)))
74        }
75    } else {
76        Ok(None)
77    }
78}
79
80pub fn launch_link(s: &str, items: &Items, config: &Config) -> anyhow::Result<()> {
81    if let Some(switcher) = &config.workspace_switcher {
82        if let Some(output) = switcher.exec() {
83            if !output?.status.success() {
84                return Err(anyhow!("i3-msg failed"));
85            }
86        }
87    }
88
89    let link = items.get_link(s.trim()).ok_or(anyhow!("Invalid item"))?;
90    Command::new(config.browser_command_name.as_str())
91        .args([link])
92        .output()?;
93
94    Ok(())
95}