diff --git a/src/lib.rs b/src/lib.rs index 85c1c23..a1fb5db 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -61,7 +61,5 @@ mod icon; mod search_dir; pub mod theme; -mod theme_graph; pub use search_dir::*; -pub use theme::*; diff --git a/src/search_dir.rs b/src/search_dir.rs index 5beeb68..4c161fd 100644 --- a/src/search_dir.rs +++ b/src/search_dir.rs @@ -1,24 +1,26 @@ use crate::icon::IconFile; +use crate::theme::{ThemeDescriptor, ThemeParseError}; use std::collections::HashMap; -use std::path::{Path, PathBuf}; +use std::ffi::{OsStr, OsString}; +use std::path::PathBuf; /// Icons and icon themes are looked for in a set of directories. /// /// By default, that is `$HOME/.icons`, `$XDG_DATA_DIRS/icons` and `/usr/share/pixmaps`. /// Applications may further add their own icon directories to this list, and users may extend or change the list. /// The default list may be obtained using the `Default` implementation on `SearchDirectories` or its `default` method. -/// +/// /// To add directories to the instance, use [SearchDirectories::append]. -/// +/// /// To construct a new `SearchDirectories` from a list, use the `From` implementation or construct it by hand. /// /// # Example -/// +/// /// ``` /// use icon::SearchDirectories; -/// +/// /// let dirs = SearchDirectories::default(); -/// let (files, themes) = dirs.search_icons_and_theme_folders(); +/// // TODO /// ``` #[derive(Debug, Clone)] pub struct SearchDirectories { @@ -31,12 +33,12 @@ impl SearchDirectories { } /// Add a list of directories to this `SearchDirectories` - /// + /// /// # Example - /// + /// /// ``` /// use icon::SearchDirectories; - /// + /// /// let dirs = SearchDirectories::default().append(["/home/root/.icons"]); /// ``` pub fn append(mut self, directories: I) -> Self @@ -46,17 +48,11 @@ impl SearchDirectories { { let mut extra_dirs = directories.into_iter().map(Into::into).collect(); self.dirs.append(&mut extra_dirs); - + extra_dirs.into() } - pub fn search_icons_and_theme_folders(&self) -> (Vec, HashMap>) { - fn theme_name_from_path(path: &Path) -> Option<&str> { - let theme_name = path.components().nth_back(1); // get the second-to-last component (which should be the theme name) - - theme_name?.as_os_str().to_str() - } - + pub fn find_icon_locations(&self) -> IconLocations { // "Each theme is stored as subdirectories of the base directories" let (files, dirs) = self @@ -79,17 +75,45 @@ impl SearchDirectories { // searching the base directories in order is used" // For each theme name, create a list of directories where it may be found: - let mut theme_folders: HashMap> = HashMap::new(); + let mut themes_directories: HashMap> = HashMap::new(); for (_, dir) in dirs { - let theme_name = dir.file_name().to_string_lossy().into_owned(); + let theme_name = dir.file_name(); - theme_folders + themes_directories .entry(theme_name) .or_default() .push(dir.path()); } - (files, theme_folders) + IconLocations { + standalone_icons: files, + themes_directories, + } + } +} + +#[derive(Debug)] +pub struct IconLocations { + pub standalone_icons: Vec, + pub themes_directories: HashMap>, +} + +impl IconLocations { + pub fn theme(&self, internal_name: S) -> std::io::Result> + where + S: AsRef, + { + let internal_name = internal_name.as_ref(); + + let theme = self + .themes_directories + .get(internal_name) + .ok_or_else(|| std::io::Error::other(ThemeParseError::NotAnIconTheme))?; + + ThemeDescriptor::new_from_folders( + internal_name.to_string_lossy().into_owned(), + theme.clone() + ) } } @@ -134,6 +158,7 @@ impl Default for SearchDirectories { #[cfg(test)] mod test { use crate::search_dir::SearchDirectories; + use crate::IconLocations; // these tests assume certain applications are installed on the system they are ran on. @@ -141,12 +166,27 @@ mod test { fn test_find_htop_icon_outside_icontheme() { let dirs = SearchDirectories::default(); - let (icons, _indexes) = dirs.search_icons_and_theme_folders(); + let IconLocations { + standalone_icons, + themes_directories, + } = dirs.find_icon_locations(); + + println!("{:?}", themes_directories); assert!( - icons + standalone_icons .iter() .any(|i| i.path.file_name().and_then(|s| s.to_str()) == Some("htop.png")) ) } + + #[test] + fn test_find_adwaita() { + let dirs = SearchDirectories::default(); + + let locations = dirs.find_icon_locations(); + let descriptor = locations.theme("Adwaita").unwrap(); + + assert_eq!(descriptor.index.name, "Adwaita"); + } } diff --git a/src/theme.rs b/src/theme.rs index 5201fa6..68e659d 100644 --- a/src/theme.rs +++ b/src/theme.rs @@ -9,7 +9,7 @@ pub type OwnedDirectoryIndex = DirectoryIndex<'static>; pub struct ThemeDescriptor<'a> { pub internal_name: String, - pub base_dirs: Vec>, + pub base_dirs: Vec, pub index_location: PathBuf, pub index: ThemeIndex<'a>, // additional groups? @@ -45,20 +45,19 @@ impl ThemeDescriptor<'_> { Ok(Self { internal_name, - base_dirs: folders.into_iter().map(Into::into).collect(), + base_dirs: folders, index_location, index, }) } + + pub fn into_owned(self) -> OwnedThemeDescriptor { + theme_into_owned(self) + } } fn theme_into_owned(theme: ThemeDescriptor) -> OwnedThemeDescriptor { - let base_dirs = theme - .base_dirs - .into_iter() - .map(Cow::into_owned) - .map(Into::into) - .collect(); + let base_dirs = theme.base_dirs; let index = theme.index.into_owned(); OwnedThemeDescriptor {