diff --git a/docs/docs/config.md b/docs/docs/config.md index a64df02c07..30e2d8c0fa 100644 --- a/docs/docs/config.md +++ b/docs/docs/config.md @@ -294,7 +294,7 @@ Has no default values. Example values are shown below: ```toml fonts.symbol-map = [ // covers: '⊗','⊘','⊙' - { start = "2297", end = "2299", font-family = "Cascadia Code Nerd Font" } + { start = "2297", end = "2299", font-family = "Cascadia Code NF" } ] ``` @@ -305,7 +305,7 @@ In case you would like to map many codepoints: ```toml fonts.symbol-map = [ { start = "E0A0", end = "E0A3", font-family = "PowerlineSymbols" }, - { start = "E0C0", end = "E0C7", font-family = "PowerlineSymbols" }, + { start = "E0C0", end = "E0C7", font-family = "PowerlineSymbols" } ] ``` diff --git a/docs/docs/releases.md b/docs/docs/releases.md index fb203276a0..0486302654 100644 --- a/docs/docs/releases.md +++ b/docs/docs/releases.md @@ -7,8 +7,12 @@ language: 'en' ## 0.2.9 (unreleased) +- Support to symbol map configuration: `fonts.symbol-map`: +```toml +# covers: '⊗','⊘','⊙' +fonts.symbol-map = [{ start = "2297", end = "2299", font-family = "Cascadia Code NF" }] +``` - Add Switch to Next/Prev Split or Tab command by [@vlabo](https://github.com/vlabo). -- Support to symbol map configuration: `fonts.symbol-map`. - Fix issue whenever the first main font cannot be found. ## 0.2.8 diff --git a/frontends/rioterm/src/context/grid.rs b/frontends/rioterm/src/context/grid.rs index ebfa3f5a59..6a2974c488 100644 --- a/frontends/rioterm/src/context/grid.rs +++ b/frontends/rioterm/src/context/grid.rs @@ -152,7 +152,7 @@ impl ContextGrid { self.current += 1; } - return true; + true } #[inline] @@ -179,7 +179,7 @@ impl ContextGrid { } else { self.current -= 1; } - return true; + true } #[inline] diff --git a/rio-backend/src/config/defaults.rs b/rio-backend/src/config/defaults.rs index 4b3448e751..045fab3bfc 100644 --- a/rio-backend/src/config/defaults.rs +++ b/rio-backend/src/config/defaults.rs @@ -340,7 +340,14 @@ pub fn default_config_file_content() -> String { # [fonts] # hinting = false # -# Example: +# You can also map the specified Unicode codepoints to a particular font. +# [fonts] +# symbol-map = [ +# // covers: '⊗','⊘','⊙' +# { start = "2297", end = "2299", font-family = "Cascadia Code NF" } +# ] +# +# Simple example: # [fonts] # size = 18 # diff --git a/rio-backend/src/config/mod.rs b/rio-backend/src/config/mod.rs index b2ede2c8c2..234294ee5f 100644 --- a/rio-backend/src/config/mod.rs +++ b/rio-backend/src/config/mod.rs @@ -526,6 +526,7 @@ mod tests { use super::*; use colors::{hex_to_color_arr, hex_to_color_wgpu}; use std::io::Write; + use sugarloaf::font::fonts::parse_unicode; fn tmp_dir() -> PathBuf { std::env::temp_dir() @@ -1044,29 +1045,32 @@ mod tests { #[test] fn test_symbol_map() { - fn unsafe_parse_unicode(input: &str) -> char { - let unicode = u32::from_str_radix(input, 16).unwrap(); - char::from_u32(unicode).unwrap() - } - let result = create_temporary_config( "symbol-map", r#" fonts.symbol-map = [ - // covers: '⊗','⊘','⊙' - { start = "2297", end = "2299", font-family = "PowerlineSymbols" } + # covers: '⊗','⊘','⊙' + { start = "2297", end = "2299", font-family = "PowerlineSymbols" }, + { start = "E0C0", end = "E0C7", font-family = "Cascadia Code NF" }, ] "#, ); assert!(result.fonts.symbol_map.is_some()); let symbol_map = result.fonts.symbol_map.unwrap(); - assert_eq!(symbol_map.len(), 1); + assert_eq!(symbol_map.len(), 2); assert_eq!(symbol_map[0].font_family, "PowerlineSymbols"); - assert_eq!(symbol_map[0].start, "E0C0"); - assert_eq!(symbol_map[0].end, "E0C7"); + assert_eq!(symbol_map[0].start, "2297"); + assert_eq!(symbol_map[0].end, "2299"); + + assert_eq!(parse_unicode(&symbol_map[0].start), Some('\u{2297}')); + assert_eq!(parse_unicode(&symbol_map[0].end), Some('\u{2299}')); + + assert_eq!(symbol_map[1].font_family, "Cascadia Code NF"); + assert_eq!(symbol_map[1].start, "E0C0"); + assert_eq!(symbol_map[1].end, "E0C7"); - assert_eq!(unsafe_parse_unicode(&symbol_map[0].start), '\u{E0C0}'); - assert_eq!(unsafe_parse_unicode(&symbol_map[0].end), '\u{E0C7}'); + assert_eq!(parse_unicode(&symbol_map[1].start), Some('\u{E0C0}')); + assert_eq!(parse_unicode(&symbol_map[1].end), Some('\u{E0C7}')); } } diff --git a/sugarloaf/src/font/fonts.rs b/sugarloaf/src/font/fonts.rs index 1672646294..6560cc1f1b 100644 --- a/sugarloaf/src/font/fonts.rs +++ b/sugarloaf/src/font/fonts.rs @@ -141,6 +141,16 @@ pub struct SugarloafFonts { pub symbol_map: Option>, } +pub fn parse_unicode(input: &str) -> Option { + if let Ok(unicode) = u32::from_str_radix(input, 16) { + if let Some(result) = char::from_u32(unicode) { + return Some(result); + } + } + + None +} + impl Default for SugarloafFonts { fn default() -> SugarloafFonts { SugarloafFonts { diff --git a/sugarloaf/src/font/mod.rs b/sugarloaf/src/font/mod.rs index 55ad648834..a973b4c8ac 100644 --- a/sugarloaf/src/font/mod.rs +++ b/sugarloaf/src/font/mod.rs @@ -7,7 +7,7 @@ pub mod loader; pub const FONT_ID_REGULAR: usize = 0; use crate::font::constants::*; -use crate::font::fonts::{SugarloafFontStyle, SugarloafFontWidth}; +use crate::font::fonts::{parse_unicode, SugarloafFontStyle, SugarloafFontWidth}; use crate::font_introspector::text::cluster::Parser; use crate::font_introspector::text::cluster::Token; use crate::font_introspector::text::cluster::{CharCluster, Status}; @@ -21,6 +21,7 @@ use lru::LruCache; use parking_lot::FairMutex; use rustc_hash::FxHashMap; use std::num::NonZeroUsize; +use std::ops::Range; use std::path::PathBuf; use std::sync::Arc; @@ -34,8 +35,8 @@ pub fn lookup_for_font_match( ) -> Option<(usize, bool)> { let mut search_result = None; let mut font_synth = Synthesis::default(); - let fonts_len: usize = library.inner.len(); + let fonts_len: usize = library.inner.len(); for font_id in 0..fonts_len { let mut is_emoji = false; @@ -118,10 +119,16 @@ impl Default for FontLibrary { } } +pub struct SymbolMap { + pub font_index: usize, + pub range: Range, +} + pub struct FontLibraryData { pub ui: FontArc, // Standard is fallback for everything, it is also the inner number 0 pub inner: FxHashMap, + pub symbol_maps: Option>, pub stash: LruCache, pub hinting: bool, } @@ -133,6 +140,7 @@ impl Default for FontLibraryData { inner: FxHashMap::default(), stash: LruCache::new(NonZeroUsize::new(2).unwrap()), hinting: true, + symbol_maps: None, } } } @@ -160,6 +168,15 @@ impl FontLibraryData { return Some((0, false)); } + // First check symbol map before lookup_for_font_match + if let Some(symbol_maps) = &self.symbol_maps { + for symbol_map in symbol_maps { + if symbol_map.range.contains(&ch) { + return Some((symbol_map.font_index, false)); + } + } + } + let is_italic = fragment_style.font_attrs.style() == Style::Italic; let is_bold = fragment_style.font_attrs.weight() == Weight::BOLD; @@ -384,6 +401,62 @@ impl FontLibraryData { } } + // TODO: Currently, it will naively just extend fonts from symbol_map + // without even look if the font has been loaded before. + // Considering that we drop the font data that's inactive should be ok but + // it will cost a bit more time to initialize. + // + // Considering we receive via config + // [{ start = "2297", end = "2299", font-family = "Cascadia Code NF" }, + // { start = "2296", end = "2297", font-family = "Cascadia Code NF" }] + // + // Will become: + // [{ start = "2297", end = "2299", font_index = Some(1) }, + // { start = "2296", end = "2297", font_index = Some(1) }] + // + // TODO: We should have a new symbol map internally + // { range = '2296'..'2297', font_index = Some(1) }] + if let Some(symbol_map) = spec.symbol_map { + let mut symbol_maps = Vec::default(); + for extra_font_from_symbol_map in symbol_map { + match find_font( + &db, + SugarloafFont { + family: extra_font_from_symbol_map.font_family, + ..SugarloafFont::default() + }, + true, + true, + ) { + FindResult::Found(data) => { + if let Some(start) = + parse_unicode(&extra_font_from_symbol_map.start) + { + if let Some(end) = + parse_unicode(&extra_font_from_symbol_map.end) + { + self.insert(data); + + symbol_maps.push(SymbolMap { + range: start..end, + font_index: self.len() - 1, + }); + + continue; + } + } + + warn!("symbol-map: Failed to parse start and end values"); + } + FindResult::NotFound(spec) => { + fonts_not_fount.push(spec); + } + } + } + + self.symbol_maps = Some(symbol_maps); + } + fonts_not_fount }