-
-
Notifications
You must be signed in to change notification settings - Fork 1.3k
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Load themes lazily for improved startup time (#1969)
This is for #951. Syntax lazy-loading will come later and have a much bigger impact, but lazy-loading of themes does not have negligible impact.
- Loading branch information
Showing
5 changed files
with
134 additions
and
17 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Binary file not shown.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,104 @@ | ||
use super::*; | ||
|
||
use std::collections::BTreeMap; | ||
use std::convert::TryFrom; | ||
|
||
use serde::Deserialize; | ||
use serde::Serialize; | ||
|
||
use once_cell::unsync::OnceCell; | ||
|
||
use syntect::highlighting::{Theme, ThemeSet}; | ||
|
||
/// Same structure as a [`syntect::highlighting::ThemeSet`] but with themes | ||
/// stored in raw serialized form, and deserialized on demand. | ||
#[derive(Debug, Default, Serialize, Deserialize)] | ||
pub struct LazyThemeSet { | ||
/// This is a [`BTreeMap`] because that's what [`syntect::highlighting::ThemeSet`] uses | ||
themes: BTreeMap<String, LazyTheme>, | ||
} | ||
|
||
/// Stores raw serialized data for a theme with methods to lazily deserialize | ||
/// (load) the theme. | ||
#[derive(Debug, Serialize, Deserialize)] | ||
struct LazyTheme { | ||
serialized: Vec<u8>, | ||
|
||
#[serde(skip, default = "OnceCell::new")] | ||
deserialized: OnceCell<syntect::highlighting::Theme>, | ||
} | ||
|
||
impl LazyThemeSet { | ||
/// Lazily load the given theme | ||
pub fn get(&self, name: &str) -> Option<&Theme> { | ||
self.themes.get(name).and_then(|lazy_theme| { | ||
lazy_theme | ||
.deserialized | ||
.get_or_try_init(|| lazy_theme.deserialize()) | ||
.ok() | ||
}) | ||
} | ||
|
||
/// Returns the name of all themes. | ||
pub fn themes(&self) -> impl Iterator<Item = &str> { | ||
self.themes.keys().map(|name| name.as_ref()) | ||
} | ||
} | ||
|
||
impl LazyTheme { | ||
fn deserialize(&self) -> Result<Theme> { | ||
asset_from_contents( | ||
&self.serialized[..], | ||
"lazy-loaded theme", | ||
COMPRESS_LAZY_THEMES, | ||
) | ||
} | ||
} | ||
|
||
impl TryFrom<LazyThemeSet> for ThemeSet { | ||
type Error = Error; | ||
|
||
/// Since the user might want to add custom themes to bat, we need a way to | ||
/// convert from a `LazyThemeSet` to a regular [`ThemeSet`] so that more | ||
/// themes can be added. This function does that pretty straight-forward | ||
/// conversion. | ||
fn try_from(lazy_theme_set: LazyThemeSet) -> Result<Self> { | ||
let mut theme_set = ThemeSet::default(); | ||
|
||
for (name, lazy_theme) in lazy_theme_set.themes { | ||
theme_set.themes.insert(name, lazy_theme.deserialize()?); | ||
} | ||
|
||
Ok(theme_set) | ||
} | ||
} | ||
|
||
#[cfg(feature = "build-assets")] | ||
impl TryFrom<ThemeSet> for LazyThemeSet { | ||
type Error = Error; | ||
|
||
/// To collect themes, a [`ThemeSet`] is needed. Once all desired themes | ||
/// have been added, we need a way to convert that into [`LazyThemeSet`] so | ||
/// that themes can be lazy-loaded later. This function does that | ||
/// conversion. | ||
fn try_from(theme_set: ThemeSet) -> Result<Self> { | ||
let mut lazy_theme_set = LazyThemeSet::default(); | ||
|
||
for (name, theme) in theme_set.themes { | ||
// All we have to do is to serialize the theme | ||
let lazy_theme = LazyTheme { | ||
serialized: crate::assets::build_assets::asset_to_contents( | ||
&theme, | ||
&format!("theme {}", name), | ||
COMPRESS_LAZY_THEMES, | ||
)?, | ||
deserialized: OnceCell::new(), | ||
}; | ||
|
||
// Ok done, now we can add it | ||
lazy_theme_set.themes.insert(name, lazy_theme); | ||
} | ||
|
||
Ok(lazy_theme_set) | ||
} | ||
} |