gdritter repos dmesktop / 9baba44
Adding Rust-based port of dmesktop Getty Ritter 6 years ago
3 changed file(s) with 103 addition(s) and 0 deletion(s). Collapse all Expand all
1 target
1 [package]
2 name = "dmesktop"
3 version = "0.1.0"
4 authors = ["Getty Ritter <dmesktop@infinitenegativeutility.com>"]
5
6 [dependencies]
7 failure = "0.1.1"
8 xdg-desktop = { git = "https://git.gdritter.com/xdg-desktop/" }
1 #[macro_use] extern crate failure;
2 extern crate xdg_desktop;
3
4 use failure::Error;
5 use xdg_desktop::{DesktopEntry, EntryType};
6
7 use std::io::{Write};
8 use std::process::{self,exit,Command,Stdio};
9 use std::os::unix::process::CommandExt;
10
11 fn ensure_dmenu() -> Result<(), Error> {
12 let _ = Command::new("which")
13 .args(&["dmenu"])
14 .output()
15 .map_err(|_| format_err!("could not find `dmenu'"))?;
16 Ok(())
17 }
18
19 /// Given a list of strings, we provide them to dmenu and return back
20 /// the one which the user chose (or an empty string, if the user
21 /// chose nothing)
22 fn dmenu_choose<'a, I>(choices: I) -> Result<String, Error>
23 where I: Iterator<Item=&'a String>
24 {
25 let mut dmenu = Command::new("dmenu")
26 .args(&["-i", "-l", "10"])
27 .stdin(Stdio::piped())
28 .stdout(Stdio::piped())
29 .spawn()?;
30 {
31 let stdin = dmenu.stdin.as_mut().unwrap();
32 for c in choices.into_iter() {
33 stdin.write(c.as_bytes())?;
34 stdin.write(b"\n")?;
35 }
36 }
37
38 let output = dmenu.wait_with_output()?;
39 Ok(String::from_utf8(output.stdout)?.trim().to_owned())
40 }
41
42 fn is_not_metavar(s: &&str) -> bool {
43 !(s.starts_with("%") && s.len() == 2)
44 }
45
46 fn run_command(cmd: &Option<String>) -> Result<(), Error> {
47 println!("runnin");
48 if let &Some(ref cmd) = cmd {
49 let mut iter = cmd.split_whitespace();
50 process::Command::new(iter.next().unwrap())
51 .args(iter.filter(is_not_metavar))
52 .exec();
53 } else {
54 Err(format_err!("No command specified in file!"))?;
55 }
56 Ok(())
57 }
58
59 fn run() -> Result<(), Error> {
60 ensure_dmenu()?;
61 let mut entries = Vec::new();
62 for f in std::fs::read_dir("/usr/share/applications")? {
63 let f = f?;
64 if f.file_type()?.is_file() && f.path().extension().map_or(false, |e| e == "desktop") {
65 let mut f = std::fs::File::open(f.path())?;
66 match xdg_desktop::DesktopEntry::from_file(&mut f) {
67 Ok(e) => if e.is_application() {
68 entries.push(e);
69 },
70 _ => (),
71 }
72 }
73 }
74
75 let choice = dmenu_choose(entries.iter()
76 .map(|e| &e.info.name))?;
77 println!("Choice is {}", choice);
78
79 match entries.iter().find(|e| e.info.name == choice) {
80 Some(&DesktopEntry {
81 typ: EntryType::Application(ref app),
82 info: _,
83 }) => run_command(&app.exec)?,
84 _ => (),
85 }
86 Ok(())
87 }
88
89 fn main() {
90 if let Err(e) = run() {
91 eprintln!("Error running dmesktop: {}", e);
92 exit(99);
93 }
94 }