ltrait_source_desktop/
lib.rs

1//! # Example Usage
2//! ```rust
3//! # use ltrait::{color_eyre::Result, Launcher, filter::ClosureFilter};
4//! # use std::time::Duration;
5//! #
6//! # struct DummyUI;
7//! #
8//! # impl<'a> ltrait::UI<'a> for DummyUI {
9//! #     type Context = ();
10//! #
11//! #     async fn run<Cushion: 'a + Send>(
12//! #         &self,
13//! #         _: ltrait::launcher::batcher::Batcher<'a, Cushion, Self::Context>,
14//! #     ) -> Result<Option<Cushion>> {
15//! #         unimplemented!()
16//! #     }
17//! # }
18//! #
19//! # fn main() -> Result<()> {
20//! #
21//! use ltrait_source_desktop::{default_paths, DesktopEntry};
22//!
23//! let launcher = Launcher::default()
24//!     .set_ui(DummyUI, |c| unimplemented!())
25//!     .add_raw_source(
26//!         ltrait_source_desktop::new(default_paths())?,
27//!     )
28//!    .add_raw_filter(ClosureFilter::new(|d: &DesktopEntry, _| {
29//!        !d.entry.no_display() && d.entry.exec().is_some()
30//!    }));
31//! #
32//! # Ok(()) }
33//! ```
34
35use ltrait::{source::Source, tokio_stream};
36use std::path::PathBuf;
37
38pub use freedesktop_desktop_entry::default_paths;
39
40pub mod icon;
41
42#[derive(Debug, thiserror::Error)]
43pub enum DesktopError {
44    // Stringは名前
45    #[error("Failed to find icon of {0}")]
46    NoIcon(String),
47    #[error("Failed to open file: {0}")]
48    OpenFile(#[source] std::io::Error),
49    #[error("Failed to decode the image: {0}")]
50    ImageDecode(#[source] image::ImageError),
51}
52
53#[derive(Debug, Clone)]
54pub struct DesktopEntry {
55    pub entry: freedesktop_desktop_entry::DesktopEntry,
56}
57
58impl DesktopEntry {
59    pub fn icon(&self) -> Option<PathBuf> {
60        self.entry.icon().and_then(|n| icon::lookup(n).ok())
61    }
62}
63
64// 楽をするためにfreedesktop_desktop_entryを使っているからStreamではなく、性能を最大限に活かしきれていない
65pub fn new(paths: impl Iterator<Item = PathBuf>) -> Result<Source<DesktopEntry>, DesktopError> {
66    use freedesktop_desktop_entry::Iter;
67    let entries = Iter::new(paths)
68        .entries::<String>(None)
69        .map(|e| DesktopEntry { entry: e });
70
71    Ok(Box::pin(tokio_stream::iter(entries)))
72}