Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
136 changes: 45 additions & 91 deletions src/mime_app.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ pub use mime_guess::Mime;
use rustc_hash::FxHashMap;
use std::{
cmp::Ordering,
env,
ffi::OsStr,
fs, io,
path::{Path, PathBuf},
Expand Down Expand Up @@ -280,107 +279,62 @@ impl MimeAppCache {
}
}

let desktops: Vec<String> = env::var("XDG_CURRENT_DESKTOP")
.unwrap_or_default()
.split(':')
.map(str::to_ascii_lowercase)
.collect();

// Load mimeapps.list files
// https://specifications.freedesktop.org/mime-apps-spec/mime-apps-spec-latest.html
//TODO: ensure correct lookup order
let mut mimeapps_paths = Vec::new();
let xdg_dirs = xdg::BaseDirectories::new();

mimeapps_paths.extend(xdg_dirs.find_data_files("applications/mimeapps.list"));

for desktop in desktops.iter().rev() {
mimeapps_paths
.extend(xdg_dirs.find_data_files(format!("applications/{desktop}-mimeapps.list")));
}

mimeapps_paths.extend(xdg_dirs.find_config_files("mimeapps.list"));

for desktop in desktops.iter().rev() {
mimeapps_paths.extend(xdg_dirs.find_config_files(format!("{desktop}-mimeapps.list")));
}
let mut list = cosmic_mime_apps::List::default();

//TODO: handle directory specific behavior
for path in mimeapps_paths {
let entry = match freedesktop_entry_parser::parse_entry(&path) {
Ok(ok) => ok,
Err(err) => {
log::warn!("failed to parse {}: {}", path.display(), err);
continue;
}
};
let paths = cosmic_mime_apps::list_paths();
list.load_from_paths(&paths);

for attr in entry
.section("Added Associations")
.attrs()
.chain(entry.section("Default Applications").attrs())
{
if let Ok(mime) = attr.name.parse::<Mime>() {
if let Some(filenames) = attr.value {
for filename in filenames.split_terminator(';') {
log::trace!("add {mime}={filename}");
let apps = self
.cache
.entry(mime.clone())
.or_insert_with(|| Vec::with_capacity(1));
if !apps.iter().any(|x| filename_eq(&x.path, filename)) {
if let Some(app) =
all_apps.iter().find(|&x| filename_eq(&x.path, filename))
{
apps.push(MimeApp::from(app));
} else {
log::info!(
"failed to add association for {mime:?}: application {filename:?} not found"
);
}
}
}
for (mime, filenames) in list
.added_associations
.iter()
.chain(list.default_apps.iter())
{
for filename in filenames {
log::trace!("add {mime}={filename}");
let apps = self
.cache
.entry(mime.clone())
.or_insert_with(|| Vec::with_capacity(1));
if !apps.iter().any(|x| filename_eq(&x.path, filename)) {
if let Some(app) = all_apps.iter().find(|&x| filename_eq(&x.path, filename)) {
apps.push(MimeApp::from(app));
} else {
log::info!(
"failed to add association for {mime:?}: application {filename:?} not found"
);
}
}
}
}

for attr in entry.section("Removed Associations").attrs() {
if let Ok(mime) = attr.name.parse::<Mime>() {
if let Some(filenames) = attr.value {
for filename in filenames.split_terminator(';') {
log::trace!("remove {mime}={filename}");
if let Some(apps) = self.cache.get_mut(&mime) {
apps.retain(|x| !filename_eq(&x.path, filename));
}
}
}
for (mime, filenames) in list.removed_associations.iter() {
for filename in filenames {
log::trace!("remove {mime}={filename}");
if let Some(apps) = self.cache.get_mut(&mime) {
apps.retain(|x| !filename_eq(&x.path, filename));
}
}
}

for attr in entry.section("Default Applications").attrs() {
if let Ok(mime) = attr.name.parse::<Mime>() {
if let Some(filenames) = attr.value {
for filename in filenames.split_terminator(';') {
log::trace!("default {mime}={filename}");
if let Some(apps) = self.cache.get_mut(&mime) {
let mut found = false;
for app in apps.iter_mut() {
if filename_eq(&app.path, filename) {
app.is_default = true;
found = true;
} else {
app.is_default = false;
}
}
if found {
break;
}
log::debug!(
"failed to set default for {mime:?}: application {filename:?} not found"
);
}
for (mime, filenames) in list.default_apps.iter() {
for filename in filenames {
log::trace!("default {mime}={filename}");
if let Some(apps) = self.cache.get_mut(&mime) {
let mut found = false;
for app in apps.iter_mut() {
if filename_eq(&app.path, filename) {
app.is_default = true;
found = true;
} else {
app.is_default = false;
}
}
if found {
break;
}
log::debug!(
"failed to set default for {mime:?}: application {filename:?} not found"
);
}
}
}
Expand Down
Loading