feat: resettable cache and icon retry after time
This commit is contained in:
parent
a28483f3d1
commit
09a76900a6
5 changed files with 63 additions and 17 deletions
|
|
@ -10,11 +10,10 @@ readme = "README.md"
|
|||
keywords = ["icons", "gui", "freedesktop"]
|
||||
|
||||
[dependencies]
|
||||
dirs = "5.0.1"
|
||||
thiserror = "1.0.56"
|
||||
once_cell = "1.19.0"
|
||||
xdg = "2.5.2"
|
||||
tracing = "0.1.41"
|
||||
dirs = "5.0"
|
||||
thiserror = "2.0"
|
||||
xdg = "2.5"
|
||||
tracing = "0.1.0"
|
||||
ini_core = "0.2.0"
|
||||
|
||||
[dev-dependencies]
|
||||
|
|
|
|||
25
src/cache.rs
25
src/cache.rs
|
|
@ -1,9 +1,10 @@
|
|||
use once_cell::sync::Lazy;
|
||||
use std::collections::BTreeMap;
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::sync::LazyLock;
|
||||
use std::sync::Mutex;
|
||||
use std::time::Instant;
|
||||
|
||||
pub(crate) static CACHE: Lazy<Cache> = Lazy::new(Cache::default);
|
||||
pub(crate) static CACHE: LazyLock<Cache> = LazyLock::new(Cache::default);
|
||||
type IconMap = BTreeMap<(String, u16, u16), CacheEntry>;
|
||||
type ThemeMap = BTreeMap<String, IconMap>;
|
||||
|
||||
|
|
@ -13,7 +14,7 @@ pub(crate) struct Cache(Mutex<ThemeMap>);
|
|||
#[derive(Debug, Clone, PartialEq)]
|
||||
pub enum CacheEntry {
|
||||
// We already looked for this and nothing was found, indicates we should not try to perform a lookup.
|
||||
NotFound,
|
||||
NotFound(Instant),
|
||||
// We have this entry.
|
||||
Found(PathBuf),
|
||||
// We don't know this entry yet, indicate we should perform a lookup.
|
||||
|
|
@ -21,6 +22,10 @@ pub enum CacheEntry {
|
|||
}
|
||||
|
||||
impl Cache {
|
||||
pub fn clear(&self) {
|
||||
self.0.lock().unwrap().clear();
|
||||
}
|
||||
|
||||
pub fn insert<P: AsRef<Path>>(
|
||||
&self,
|
||||
theme: &str,
|
||||
|
|
@ -33,7 +38,7 @@ impl Cache {
|
|||
let entry = icon_path
|
||||
.as_ref()
|
||||
.map(|path| CacheEntry::Found(path.as_ref().to_path_buf()))
|
||||
.unwrap_or(CacheEntry::NotFound);
|
||||
.unwrap_or(CacheEntry::NotFound(Instant::now()));
|
||||
|
||||
match theme_map.get_mut(theme) {
|
||||
Some(icon_map) => {
|
||||
|
|
@ -56,4 +61,16 @@ impl Cache {
|
|||
.and_then(|path| path.cloned())
|
||||
.unwrap_or(CacheEntry::Unknown)
|
||||
}
|
||||
|
||||
pub fn reset_none(&self) {
|
||||
let mut theme_map = self.0.lock().unwrap();
|
||||
|
||||
for (_theme_name, theme) in theme_map.iter_mut() {
|
||||
for (_icon_data, cached_icon) in theme.iter_mut() {
|
||||
if matches!(cached_icon, CacheEntry::NotFound(_)) {
|
||||
*cached_icon = CacheEntry::Unknown;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
29
src/lib.rs
29
src/lib.rs
|
|
@ -57,6 +57,7 @@ use crate::cache::{CacheEntry, CACHE};
|
|||
use crate::theme::{try_build_icon_path, THEMES};
|
||||
use std::io::BufRead;
|
||||
use std::path::PathBuf;
|
||||
use std::time::Instant;
|
||||
|
||||
mod cache;
|
||||
mod theme;
|
||||
|
|
@ -189,6 +190,7 @@ impl<'a> LookupBuilder<'a> {
|
|||
/// .with_size(48)
|
||||
/// .find();
|
||||
/// # }
|
||||
#[inline]
|
||||
pub fn with_size(mut self, size: u16) -> Self {
|
||||
self.size = size;
|
||||
self
|
||||
|
|
@ -205,6 +207,7 @@ impl<'a> LookupBuilder<'a> {
|
|||
/// .with_scale(2)
|
||||
/// .find();
|
||||
/// # }
|
||||
#[inline]
|
||||
pub fn with_scale(mut self, scale: u16) -> Self {
|
||||
self.scale = scale;
|
||||
self
|
||||
|
|
@ -220,6 +223,7 @@ impl<'a> LookupBuilder<'a> {
|
|||
/// .with_theme("Papirus")
|
||||
/// .find();
|
||||
/// # }
|
||||
#[inline]
|
||||
pub fn with_theme<'b: 'a>(mut self, theme: &'b str) -> Self {
|
||||
self.theme = theme;
|
||||
self
|
||||
|
|
@ -240,6 +244,7 @@ impl<'a> LookupBuilder<'a> {
|
|||
/// .with_cache()
|
||||
/// .find();
|
||||
/// # }
|
||||
#[inline]
|
||||
pub fn with_cache(mut self) -> Self {
|
||||
self.cache = true;
|
||||
self
|
||||
|
|
@ -258,6 +263,7 @@ impl<'a> LookupBuilder<'a> {
|
|||
/// .force_svg()
|
||||
/// .find();
|
||||
/// # }
|
||||
#[inline]
|
||||
pub fn force_svg(mut self) -> Self {
|
||||
self.force_svg = true;
|
||||
self
|
||||
|
|
@ -266,7 +272,12 @@ impl<'a> LookupBuilder<'a> {
|
|||
/// Execute the current lookup
|
||||
/// if no icon is found in the current theme fallback to
|
||||
/// `/usr/share/icons/hicolor` theme and then to `/usr/share/pixmaps`.
|
||||
#[inline]
|
||||
pub fn find(self) -> Option<PathBuf> {
|
||||
if self.name.is_empty() {
|
||||
return None;
|
||||
}
|
||||
|
||||
// Lookup for an icon in the given theme and fallback to 'hicolor' default theme
|
||||
self.lookup_in_theme()
|
||||
}
|
||||
|
|
@ -290,8 +301,12 @@ impl<'a> LookupBuilder<'a> {
|
|||
if self.cache {
|
||||
match self.cache_lookup(self.theme) {
|
||||
CacheEntry::Found(icon) => return Some(icon),
|
||||
CacheEntry::NotFound => return None,
|
||||
_ => ()
|
||||
CacheEntry::NotFound(last_check)
|
||||
if last_check.duration_since(Instant::now()).as_secs() < 5 =>
|
||||
{
|
||||
return None
|
||||
}
|
||||
_ => (),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -364,6 +379,16 @@ impl<'a> LookupBuilder<'a> {
|
|||
})
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn cache_clear(&mut self) {
|
||||
CACHE.clear();
|
||||
}
|
||||
|
||||
#[inline]
|
||||
pub fn cache_reset_none(&mut self) {
|
||||
CACHE.reset_none();
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn cache_lookup(&self, theme: &str) -> CacheEntry {
|
||||
CACHE.get(theme, self.size, self.scale, self.name)
|
||||
|
|
|
|||
|
|
@ -1,9 +1,9 @@
|
|||
use crate::theme::error::ThemeError;
|
||||
use crate::theme::paths::ThemePath;
|
||||
use once_cell::sync::Lazy;
|
||||
pub(crate) use paths::BASE_PATHS;
|
||||
use std::collections::BTreeMap;
|
||||
use std::path::{Path, PathBuf};
|
||||
use std::sync::LazyLock;
|
||||
|
||||
mod directories;
|
||||
pub mod error;
|
||||
|
|
@ -12,8 +12,9 @@ mod paths;
|
|||
|
||||
type Result<T> = std::result::Result<T, ThemeError>;
|
||||
|
||||
pub static THEMES: Lazy<BTreeMap<String, Vec<Theme>>> = Lazy::new(get_all_themes);
|
||||
pub static THEMES: LazyLock<BTreeMap<String, Vec<Theme>>> = LazyLock::new(get_all_themes);
|
||||
|
||||
#[inline]
|
||||
pub fn read_ini_theme(path: &Path) -> String {
|
||||
std::fs::read_to_string(path).unwrap_or_default()
|
||||
}
|
||||
|
|
@ -25,6 +26,7 @@ pub struct Theme {
|
|||
}
|
||||
|
||||
impl Theme {
|
||||
#[inline]
|
||||
pub fn try_get_icon(
|
||||
&self,
|
||||
name: &str,
|
||||
|
|
@ -32,11 +34,13 @@ impl Theme {
|
|||
scale: u16,
|
||||
force_svg: bool,
|
||||
) -> Option<PathBuf> {
|
||||
eprintln!("try_get_icon: {name}");
|
||||
let file = read_ini_theme(&self.index);
|
||||
self.try_get_icon_exact_size(file.as_str(), name, size, scale, force_svg)
|
||||
.or_else(|| self.try_get_icon_closest_size(file.as_str(), name, size, scale, force_svg))
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn try_get_icon_exact_size(
|
||||
&self,
|
||||
file: &str,
|
||||
|
|
@ -49,6 +53,7 @@ impl Theme {
|
|||
.find_map(|path| try_build_icon_path(name, path, force_svg))
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn match_size<'a>(
|
||||
&'a self,
|
||||
file: &'a str,
|
||||
|
|
@ -62,6 +67,7 @@ impl Theme {
|
|||
.map(|dir| self.path().join(dir))
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn try_get_icon_closest_size(
|
||||
&self,
|
||||
file: &str,
|
||||
|
|
|
|||
|
|
@ -1,13 +1,12 @@
|
|||
use std::path::PathBuf;
|
||||
|
||||
use dirs::home_dir;
|
||||
use once_cell::sync::Lazy;
|
||||
use std::path::PathBuf;
|
||||
use std::sync::LazyLock;
|
||||
use xdg::BaseDirectories;
|
||||
|
||||
use crate::theme;
|
||||
use crate::theme::error::ThemeError;
|
||||
|
||||
pub(crate) static BASE_PATHS: Lazy<Vec<PathBuf>> = Lazy::new(icon_theme_base_paths);
|
||||
pub(crate) static BASE_PATHS: LazyLock<Vec<PathBuf>> = LazyLock::new(icon_theme_base_paths);
|
||||
|
||||
/// Look in $HOME/.icons (for backwards compatibility), in $XDG_DATA_DIRS/icons, in $XDG_DATA_DIRS/pixmaps and in /usr/share/pixmaps (in that order).
|
||||
/// Paths that are not found are filtered out.
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue