I'm struggling to compile this file.
The whole project can be viewed here:
There are 2 points of error, but first I want to solve the get_app_browser_ini()
function.
If I remove the lifetime, it says on the return Some(entry);
:
error[E0515]: cannot return value referencing local variable `desktop_entry`
--> src/providers.rs:71:12
|
61 | let name: &str = desktop_entry.get("Name").unwrap().clone();
| ------------- `desktop_entry` is borrowed here
...
71 | return Some(entry);
| ^^^^^^^^^^^ returns a value referencing data owned by the current function
Even though I closed the name
, icon
and exec
string.
If I specify a static lifetime (the compiler suggested, so I don't fully understand it), I get the error:
error[E0597]: `desktop_entry` does not live long enough
--> src/providers.rs:61:22
|
48 | let desktop_entry = ini
| ------------- binding `desktop_entry` declared here
...
61 | let name: &str = desktop_entry.get("Name").unwrap().clone();
| ^^^^^^^^^^^^^ borrowed value does not live long enough
...
65 | let entry: BrowserEntry<'static> = BrowserEntry {
| --------------------- type annotation requires that `desktop_entry` is borrowed for `'static`
...
72 | }
| - `desktop_entry` dropped here while still borrowed
I don't know how to proceed or why the clone still maintains the ownership of from desktop_entry.
Here is the file providers.rs
use std::path::PathBuf;
use std::{fs, path::Path};
use ini::Ini;
const APP_DIR_SYSTEM: &str = "/usr/share/applications/";
const APP_DIR_USER: &str = "~/.local/share/applications/";
const DESKTOP_EXTENSION: &str = "desktop"; // Files that ends with .desktop
const WEB_BROWSER_CATEGORY: &str = "WebBrowser";
const USE_USER_APPS: bool = false;
#[derive(Debug)]
pub struct BrowserEntry<'a> {
name: &'a str,
icon: &'a str,
exec: Option<&'a str>,
}
pub const CLIPBOARD_ENTRY: BrowserEntry<'_> = BrowserEntry {
name: "Copy to clipboard",
icon: "edit-copy-symbolic",
exec: None,
};
fn get_app_desktop_paths(app_dir: &Path) -> Vec<PathBuf> {
assert!(app_dir.is_dir());
let mut desktop_entries: Vec<PathBuf> = Vec::new();
for entry_result in fs::read_dir(app_dir).unwrap() {
let entry: fs::DirEntry = entry_result.unwrap();
let path = entry.path();
if let Some(extension) = path.extension() {
if extension == DESKTOP_EXTENSION {
desktop_entries.push(path);
}
}
}
desktop_entries
}
fn get_app_browser_ini(path: &PathBuf) -> Option<BrowserEntry<'static>> {
// println!("FILE: {:?}", path);
let ini = Ini::load_from_file(path).expect("Error parsing desktop file");
let desktop_entry = ini
.section(Some("Desktop Entry"))
.expect("No desktop.entry")
.clone();
// println!("{:#?}", desktop_entry);
let _categories = desktop_entry.get("Categories").unwrap_or_default();
let categories: Vec<&str> = _categories.split(';').collect();
if categories.contains(&WEB_BROWSER_CATEGORY) {
let name: &str = desktop_entry.get("Name").unwrap().clone();
let icon: &str = desktop_entry.get("Icon").unwrap().clone();
let exec: &str = desktop_entry.get("Exec").unwrap().clone();
let entry: BrowserEntry = BrowserEntry {
name: name,
icon: icon,
exec: Some(exec),
};
return Some(entry);
}
None // Not a Web Browser
}
fn get_browser_desktop_list() -> Vec<BrowserEntry<'static>> {
let app_dir = Path::new(APP_DIR_SYSTEM);
let mut file_paths = get_app_desktop_paths(&app_dir);
if USE_USER_APPS {
let app_dir_user = Path::new(APP_DIR_USER);
let file_paths_user = get_app_desktop_paths(&app_dir_user);
file_paths.extend(file_paths_user);
}
let browsers: Vec<BrowserEntry> = file_paths
.iter()
.map(get_app_browser_ini)
.flatten()
.collect();
browsers
}
pub fn get_browsers_list() -> Vec<BrowserEntry<'static>> {
let mut browsers: Vec<BrowserEntry> = get_browser_desktop_list();
browsers.insert(0, CLIPBOARD_ENTRY);
browsers
}
pub fn main_dev() {
let browsers = get_browsers_list();
println!("BROWSERS:\n{:#?}", browsers);
}