1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
//! Utility functions including wofi-selection.

use std::collections::HashMap;
use std::io::Write;
use std::process as proc;

pub fn get_swayr_socket_path() -> String {
    let wayland_display = std::env::var("WAYLAND_DISPLAY");
    format!(
        "/run/user/{}/swayr-{}.sock",
        users::get_current_uid(),
        match wayland_display {
            Ok(val) => val,
            Err(_e) => {
                eprintln!("Couldn't get WAYLAND_DISPLAY!");
                String::from("unknown")
            }
        }
    )
}

pub fn wofi_select<'a, 'b, TS>(
    prompt: &'a str,
    choices: &'b [TS],
) -> Option<&'b TS>
where
    TS: std::fmt::Display + Sized,
{
    let mut map: HashMap<String, &TS> = HashMap::new();
    let mut strs: Vec<String> = vec![];
    for c in choices {
        let s = format!("{}", c);
        strs.push(String::from(s.as_str()));
        map.insert(s, c);
    }

    let mut wofi = proc::Command::new("wofi")
        .arg("--show=dmenu")
        .arg("--allow-markup")
        .arg("--allow-images")
        .arg("--insensitive")
        .arg("--cache-file=/dev/null")
        .arg("--parse-search")
        .arg("--prompt")
        .arg(prompt)
        .stdin(proc::Stdio::piped())
        .stdout(proc::Stdio::piped())
        .spawn()
        .expect("Error running wofi!");

    {
        let stdin = wofi.stdin.as_mut().expect("Failed to open wofi stdin");
        let wofi_input = strs.join("\n");
        println!("Wofi input:\n{}", wofi_input);
        stdin
            .write_all(wofi_input.as_bytes())
            .expect("Failed to write to wofi stdin");
    }

    let output = wofi.wait_with_output().expect("Failed to read stdout");
    let choice = String::from_utf8_lossy(&output.stdout);
    let mut choice = String::from(choice);
    choice.pop(); // Remove trailing \n from choice.
    map.get(&choice).copied()
}

#[test]
#[ignore = "interactive test requiring user input"]
fn test_wofi_select() {
    let choices = vec!["a", "b", "c"];
    let choice = wofi_select("Choose wisely", &choices);
    assert!(choice.is_some());
    assert!(choices.contains(choice.unwrap()));
}