Rely on a more robust entry parser | #9

This commit is contained in:
Gregory 2020-06-19 20:22:49 -04:00
parent 845aa5f213
commit fb98e4e2f5
No known key found for this signature in database
GPG key ID: 2E44FAEEDC94B1E2
8 changed files with 71 additions and 38 deletions

17
Cargo.lock generated
View file

@ -1,5 +1,11 @@
# This file is automatically @generated by Cargo. # This file is automatically @generated by Cargo.
# It is not intended for manual editing. # It is not intended for manual editing.
[[package]]
name = "anyhow"
version = "1.0.31"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "85bb70cc08ec97ca5450e6eba421deeea5f172c0fc61f78b5357b2a8e8be195f"
[[package]] [[package]]
name = "arrayref" name = "arrayref"
version = "0.3.6" version = "0.3.6"
@ -285,6 +291,16 @@ version = "0.1.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b"
[[package]]
name = "freedesktop_entry_parser"
version = "0.2.2"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0e71e40cde9e00afcb8c5f4e3339f72dae1fb0b30f299d54b690ceb6ce11f3e3"
dependencies = [
"anyhow",
"nom",
]
[[package]] [[package]]
name = "fuchsia-zircon" name = "fuchsia-zircon"
version = "0.3.3" version = "0.3.3"
@ -393,6 +409,7 @@ dependencies = [
"atty", "atty",
"clap", "clap",
"confy", "confy",
"freedesktop_entry_parser",
"itertools", "itertools",
"json", "json",
"mime", "mime",

View file

@ -24,6 +24,7 @@ atty = "0.2.14"
confy = "0.4.0" confy = "0.4.0"
serde = "1.0.111" serde = "1.0.111"
xdg-mime = "0.3.2" xdg-mime = "0.3.2"
freedesktop_entry_parser = "0.2.2"
[profile.release] [profile.release]
opt-level=3 opt-level=3

View file

@ -1,6 +1,5 @@
use crate::{Error, Result}; use crate::{Error, Result};
use mime::Mime; use mime::Mime;
use pest::Parser;
use std::{ use std::{
convert::TryFrom, convert::TryFrom,
ffi::OsString, ffi::OsString,
@ -9,8 +8,7 @@ use std::{
str::FromStr, str::FromStr,
}; };
#[derive(Debug, Clone, pest_derive::Parser, Default, PartialEq, Eq)] #[derive(Debug, Clone, Default, PartialEq, Eq)]
#[grammar = "common/ini.pest"]
pub struct DesktopEntry { pub struct DesktopEntry {
pub(crate) name: String, pub(crate) name: String,
pub(crate) exec: String, pub(crate) exec: String,
@ -77,39 +75,32 @@ impl DesktopEntry {
} }
fn parse_file(path: &Path) -> Option<DesktopEntry> { fn parse_file(path: &Path) -> Option<DesktopEntry> {
let raw = std::fs::read_to_string(&path).ok()?; let raw = std::fs::read(&path).ok()?;
let file = DesktopEntry::parse(Rule::file, &raw).ok()?.next()?; let parsed = freedesktop_entry_parser::parse_entry(&raw)
.filter_map(Result::ok)
.find(|s| s.title == b"Desktop Entry")?;
let mut entry = DesktopEntry::default(); let mut entry = DesktopEntry::default();
entry.file_name = path.file_name()?.to_owned(); entry.file_name = path.file_name()?.to_owned();
let mut section = ""; for attr in parsed.attrs {
match attr.name {
for line in file.into_inner() { b"Name" if entry.name == "" => {
match line.as_rule() { entry.name = String::from_utf8(attr.value.into()).ok()?;
Rule::section => section = line.into_inner().as_str(),
Rule::property if section == "Desktop Entry" => {
let mut inner = line.into_inner(); // { name ~ "=" ~ value }
match inner.next()?.as_str() {
"Name" if entry.name == "" => {
entry.name = inner.next()?.as_str().into()
}
"Exec" => entry.exec = inner.next()?.as_str().into(),
"MimeType" => {
let mut mimes = inner
.next()?
.as_str()
.split(";")
.filter_map(|m| Mime::from_str(m).ok())
.collect::<Vec<_>>();
mimes.pop();
entry.mimes = mimes;
}
"Terminal" => entry.term = inner.next()?.as_str() == "true",
_ => {}
}
} }
b"Exec" => {
entry.exec = String::from_utf8(attr.value.into()).ok()?
}
b"MimeType" => {
let mut mimes = String::from_utf8(attr.value.into())
.ok()?
.split(";")
.filter_map(|m| Mime::from_str(m).ok())
.collect::<Vec<_>>();
mimes.pop();
entry.mimes = mimes;
}
b"Terminal" => entry.term = attr.value == b"true",
_ => {} _ => {}
} }
} }
@ -127,3 +118,14 @@ impl TryFrom<PathBuf> for DesktopEntry {
parse_file(&path).ok_or(Error::BadEntry(path)) parse_file(&path).ok_or(Error::BadEntry(path))
} }
} }
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn complex_exec() {
let path = PathBuf::from("tests/cmus.desktop");
parse_file(&*path).unwrap();
}
}

View file

@ -84,8 +84,11 @@ mod tests {
#[test] #[test]
fn from_path() -> Result<()> { fn from_path() -> Result<()> {
assert_eq!(MimeType::try_from(".")?.0.essence_str(), "inode/directory"); assert_eq!(MimeType::try_from(".")?.0.essence_str(), "inode/directory");
assert_eq!(MimeType::try_from("./tests/cat")?.0.type_(), "text"); assert_eq!(MimeType::try_from("./tests/rust.vim")?.0, "text/plain");
assert_eq!(MimeType::try_from("./tests/rust.vim")?.0.type_(), "text"); assert_eq!(
MimeType::try_from("./tests/cat")?.0,
"application/x-shellscript"
);
Ok(()) Ok(())
} }

View file

@ -4,6 +4,6 @@ mod handler;
mod mime_types; mod mime_types;
pub use self::db::autocomplete as db_autocomplete; pub use self::db::autocomplete as db_autocomplete;
pub use desktop_entry::{DesktopEntry, Mode as ExecMode, Rule as EntryRule}; pub use desktop_entry::{DesktopEntry, Mode as ExecMode};
pub use handler::Handler; pub use handler::Handler;
pub use mime_types::{MimeOrExtension, MimeType}; pub use mime_types::{MimeOrExtension, MimeType};

View file

@ -1,7 +1,5 @@
#[derive(Debug, thiserror::Error)] #[derive(Debug, thiserror::Error)]
pub enum Error { pub enum Error {
#[error(transparent)]
ParseEntry(#[from] pest::error::Error<crate::common::EntryRule>),
#[error(transparent)] #[error(transparent)]
ParseApps(#[from] pest::error::Error<crate::apps::MimeappsRule>), ParseApps(#[from] pest::error::Error<crate::apps::MimeappsRule>),
#[error(transparent)] #[error(transparent)]

11
tests/cmus.desktop Normal file
View file

@ -0,0 +1,11 @@
[Desktop Entry]
Encoding=UTF-8
Version=1.0
Type=Application
Display=true
Exec=bash -c "(! pgrep cmus && tilix -e cmus && tilix -a session-add-down -e cava); sleep 0.1 && cmus-remote -q %f"
Terminal=false
Name=cmus-remote
Comment=Music player cmus-remote control
NoDisplay=true
Icon=cmus

View file

@ -1,2 +1,3 @@
#!/bin/sh highlight CocRustChainingHint ctermfg=0
bat "$@" hi link rustDerive SpecialComment
hi link rustDeriveTrait SpecialComment