use std::sync::Arc;
use std::time::Instant;
use gpui::{App, Global, ReadGlobal, SharedString};
use parking_lot::RwLock;
#[derive(Default)]
struct FontFamilyCacheState {
loaded_at: Option<Instant>,
font_families: Vec<SharedString>,
}
#[derive(Default)]
pub struct FontFamilyCache {
state: Arc<RwLock<FontFamilyCacheState>>,
}
#[derive(Default)]
struct GlobalFontFamilyCache(Arc<FontFamilyCache>);
impl Global for GlobalFontFamilyCache {}
impl FontFamilyCache {
pub fn init_global(cx: &mut App) {
cx.default_global::<GlobalFontFamilyCache>();
}
pub fn global(cx: &App) -> Arc<Self> {
GlobalFontFamilyCache::global(cx).0.clone()
}
pub fn list_font_families(&self, cx: &App) -> Vec<SharedString> {
if self.state.read().loaded_at.is_some() {
return self.state.read().font_families.clone();
}
let mut lock = self.state.write();
lock.font_families = cx
.text_system()
.all_font_names()
.into_iter()
.map(SharedString::from)
.collect();
lock.loaded_at = Some(Instant::now());
lock.font_families.clone()
}
pub fn try_list_font_families(&self) -> Option<Vec<SharedString>> {
self.state
.try_read()
.filter(|state| state.loaded_at.is_some())
.map(|state| state.font_families.clone())
}
pub async fn prefetch(&self, cx: &gpui::AsyncApp) {
if self
.state
.try_read()
.is_none_or(|state| state.loaded_at.is_some())
{
return;
}
let text_system = cx.update(|cx| App::text_system(cx).clone());
let state = self.state.clone();
cx.background_executor()
.spawn(async move {
let mut lock = state.write();
let all_font_names = text_system
.all_font_names()
.into_iter()
.map(SharedString::from)
.collect();
lock.font_families = all_font_names;
lock.loaded_at = Some(Instant::now());
})
.await;
}
}