From d567ad4b3f965dc74580f7e5bdc835e8f4bdd36f Mon Sep 17 00:00:00 2001 From: Cosmic Horror Date: Mon, 29 May 2023 12:45:49 -0600 Subject: [PATCH] `ThemeDefaults` proof of concept --- src/dumps.rs | 79 ++++++++++++++++++++++++++++++++++++++- src/highlighting/theme.rs | 25 +++++++++++++ 2 files changed, 103 insertions(+), 1 deletion(-) diff --git a/src/dumps.rs b/src/dumps.rs index af71bac1..9a603f68 100644 --- a/src/dumps.rs +++ b/src/dumps.rs @@ -25,7 +25,7 @@ use std::io::{BufWriter, Write}; #[cfg(all(feature = "default-syntaxes"))] use crate::parsing::SyntaxSet; #[cfg(all(feature = "default-themes"))] -use crate::highlighting::ThemeSet; +use crate::highlighting::{Theme, ThemeDefaults, ThemeSet}; use std::path::Path; #[cfg(feature = "dump-create")] use flate2::write::ZlibEncoder; @@ -208,6 +208,64 @@ impl ThemeSet { } } +#[cfg(feature = "default-themes")] +impl Theme { + pub fn load_default(default: ThemeDefaults) -> Self { + use std::io; + + use bincode::{ + config::{DefaultOptions, Options}, + Deserializer, + }; + use serde::{ + de::{MapAccess, Visitor}, + Deserializer as _, + }; + + // Custom themedump visitor that only returns a single theme + #[derive(Clone, Copy)] + struct ThemedumpVisitor(ThemeDefaults); + + impl<'de> Visitor<'de> for ThemedumpVisitor { + type Value = Theme; + + fn expecting(&self, _formatter: &mut std::fmt::Formatter) -> std::fmt::Result { + unreachable!("has to deserialize right"); + } + + fn visit_map( + self, + mut map: A, + ) -> std::result::Result>::Error> + where + A: MapAccess<'de>, + { + let theme = loop { + let name: String = map.next_key()?.expect("`default` must be in dump"); + + if name == self.0.as_theme_name() { + break map.next_value()?; + } else { + let _: Theme = map.next_value()?; + } + }; + + Ok(theme) + } + } + + // Copied from the options used in `bincode::deserialize_from()` + let options = DefaultOptions::new() + .with_fixint_encoding() + .allow_trailing_bytes(); + let bytes = include_bytes!("../assets/default.themedump"); + let decoder = ZlibDecoder::new(io::Cursor::new(bytes)); + Deserializer::with_reader(decoder, options) + .deserialize_map(ThemedumpVisitor(default)) + .unwrap() + } +} + #[cfg(test)] mod tests { #[cfg(all(feature = "yaml-load", feature = "dump-create", feature = "dump-load", feature = "parsing"))] @@ -253,4 +311,23 @@ mod tests { let themes = ThemeSet::load_defaults(); assert!(themes.themes.len() > 4); } + + #[cfg(feature = "default-themes")] + #[test] + fn load_single_default_theme() { + use crate::highlighting::{Theme, ThemeDefaults}; + + for &default in &[ + ThemeDefaults::Base16OceanDark, + ThemeDefaults::Base16EightiesDark, + ThemeDefaults::Base16MochaDark, + ThemeDefaults::Base16OceanLight, + ThemeDefaults::InspiredGitHub, + ThemeDefaults::SolarizedDark, + ThemeDefaults::SolarizedLight, + ] { + // Ensure none of them panic + let _ = Theme::load_default(default); + } + } } diff --git a/src/highlighting/theme.rs b/src/highlighting/theme.rs index ebd449b4..069c4f49 100644 --- a/src/highlighting/theme.rs +++ b/src/highlighting/theme.rs @@ -131,3 +131,28 @@ impl Default for UnderlineOption { UnderlineOption::None } } + +#[derive(Clone, Copy)] +pub enum ThemeDefaults { + Base16OceanDark, + Base16EightiesDark, + Base16MochaDark, + Base16OceanLight, + InspiredGitHub, + SolarizedDark, + SolarizedLight, +} + +impl ThemeDefaults { + pub(crate) fn as_theme_name(self) -> &'static str { + match self { + Self::Base16OceanDark => "base16-ocean.dark", + Self::Base16EightiesDark => "base16-eighties.dark", + Self::Base16MochaDark => "base16-mocha.dark", + Self::Base16OceanLight => "base16-ocean.light", + Self::InspiredGitHub => "InspiredGitHub", + Self::SolarizedDark => "Solarized (dark)", + Self::SolarizedLight => "Solarized (light)", + } + } +}