use std::fmt; use crossfont::Size as FontSize; use serde::de::{self, Visitor}; use serde::{Deserialize, Deserializer}; use alacritty_config_derive::{ConfigDeserialize, SerdeReplace}; use crate::config::ui_config::Delta; /// Font config. /// /// Defaults are provided at the level of this struct per platform, but not per /// field in this struct. It might be nice in the future to have defaults for /// each value independently. Alternatively, maybe erroring when the user /// doesn't provide complete config is Ok. #[derive(ConfigDeserialize, Debug, Clone, PartialEq, Eq)] pub struct Font { /// Extra spacing per character. pub offset: Delta, /// Glyph offset within character cell. pub glyph_offset: Delta, #[config(removed = "set the AppleFontSmoothing user default instead")] pub use_thin_strokes: bool, /// Normal font face. normal: FontDescription, /// Bold font face. bold: SecondaryFontDescription, /// Italic font face. italic: SecondaryFontDescription, /// Bold italic font face. bold_italic: SecondaryFontDescription, /// Font size in points. size: Size, /// Whether to use the built-in font for box drawing characters. pub builtin_box_drawing: bool, } impl Font { /// Get a font clone with a size modification. pub fn with_size(self, size: FontSize) -> Font { Font { size: Size(size), ..self } } #[inline] pub fn size(&self) -> FontSize { self.size.0 } /// Get normal font description. pub fn normal(&self) -> &FontDescription { &self.normal } /// Get bold font description. pub fn bold(&self) -> FontDescription { self.bold.desc(&self.normal) } /// Get italic font description. pub fn italic(&self) -> FontDescription { self.italic.desc(&self.normal) } /// Get bold italic font description. pub fn bold_italic(&self) -> FontDescription { self.bold_italic.desc(&self.normal) } } impl Default for Font { fn default() -> Font { Self { builtin_box_drawing: true, glyph_offset: Default::default(), use_thin_strokes: Default::default(), bold_italic: Default::default(), italic: Default::default(), offset: Default::default(), normal: Default::default(), bold: Default::default(), size: Default::default(), } } } /// Description of the normal font. #[derive(ConfigDeserialize, Debug, Clone, PartialEq, Eq)] pub struct FontDescription { pub family: String, pub style: Option, } impl Default for FontDescription { fn default() -> FontDescription { FontDescription { #[cfg(not(any(target_os = "macos", windows)))] family: "monospace".into(), #[cfg(target_os = "macos")] family: "Menlo".into(), #[cfg(windows)] family: "Consolas".into(), style: None, } } } /// Description of the italic and bold font. #[derive(ConfigDeserialize, Debug, Default, Clone, PartialEq, Eq)] pub struct SecondaryFontDescription { family: Option, style: Option, } impl SecondaryFontDescription { pub fn desc(&self, fallback: &FontDescription) -> FontDescription { FontDescription { family: self.family.clone().unwrap_or_else(|| fallback.family.clone()), style: self.style.clone(), } } } #[derive(SerdeReplace, Debug, Clone, PartialEq, Eq)] struct Size(FontSize); impl Default for Size { fn default() -> Self { Self(FontSize::new(11.25)) } } impl<'de> Deserialize<'de> for Size { fn deserialize(deserializer: D) -> Result where D: Deserializer<'de>, { struct NumVisitor; impl<'v> Visitor<'v> for NumVisitor { type Value = Size; fn expecting(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { f.write_str("f64 or i64") } fn visit_f64(self, value: f64) -> Result { Ok(Size(FontSize::new(value as f32))) } fn visit_i64(self, value: i64) -> Result { Ok(Size(FontSize::new(value as f32))) } } deserializer.deserialize_any(NumVisitor) } }