Skip to main content

tar_install/
desktop.rs

1use anyhow::{Context, Result};
2use std::fs;
3use std::path::Path;
4
5#[derive(Debug, Clone)]
6pub struct DesktopEntryInput<'a> {
7    pub name: &'a str,
8    pub generic_name: Option<&'a str>,
9    pub comment: Option<&'a str>,
10    pub exec_path: &'a Path,
11    pub icon_name: &'a str,
12    pub categories: &'a [String],
13    pub terminal: bool,
14}
15
16pub fn write_desktop_entry(path: &Path, input: &DesktopEntryInput<'_>) -> Result<()> {
17    if let Some(parent) = path.parent() {
18        fs::create_dir_all(parent).with_context(|| format!("failed to create desktop dir: {}", parent.display()))?;
19    }
20
21    let categories = if input.categories.is_empty() {
22        "Utility;".to_string()
23    } else {
24        let mut joined = input.categories.join(";");
25        if !joined.ends_with(';') { joined.push(';'); }
26        joined
27    };
28
29    let mut text = String::new();
30    text.push_str("[Desktop Entry]\n");
31    text.push_str("Type=Application\n");
32    text.push_str(&format!("Name={}\n", escape_value(input.name)));
33    if let Some(generic) = input.generic_name {
34        text.push_str(&format!("GenericName={}\n", escape_value(generic)));
35    }
36    if let Some(comment) = input.comment {
37        text.push_str(&format!("Comment={}\n", escape_value(comment)));
38    }
39    text.push_str(&format!("Exec={} %U\n", quote_exec(input.exec_path)));
40    text.push_str(&format!("Icon={}\n", escape_value(input.icon_name)));
41    text.push_str(&format!("Terminal={}\n", if input.terminal { "true" } else { "false" }));
42    text.push_str(&format!("Categories={}\n", categories));
43    text.push_str("StartupNotify=true\n");
44
45    fs::write(path, text).with_context(|| format!("failed to write desktop entry: {}", path.display()))?;
46    Ok(())
47}
48
49fn escape_value(value: &str) -> String {
50    value.replace('\\', "\\\\").replace('\n', "\\n")
51}
52
53fn quote_exec(path: &Path) -> String {
54    let s = path.to_string_lossy();
55    if s.contains(' ') {
56        format!("\"{}\"", s.replace('"', "\\\""))
57    } else {
58        s.to_string()
59    }
60}