Skip to content

Instantly share code, notes, and snippets.

@shaunduncan
Created April 17, 2024 21:02
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save shaunduncan/f8f869e93bfb79fb69d1500e809e7152 to your computer and use it in GitHub Desktop.
Save shaunduncan/f8f869e93bfb79fb69d1500e809e7152 to your computer and use it in GitHub Desktop.
alacritty patch to mimic the behavior of kitty's symbol_map for unicode codepoint substitution
alacritty/src/config/font.rs | 20 ++++++++++++++
alacritty/src/renderer/text/glyph_cache.rs | 42 ++++++++++++++++++++++++++----
2 files changed, 57 insertions(+), 5 deletions(-)
diff --git a/alacritty/src/config/font.rs b/alacritty/src/config/font.rs
index 061c0f42..b9630f84 100644
--- a/alacritty/src/config/font.rs
+++ b/alacritty/src/config/font.rs
@@ -42,6 +42,9 @@ pub struct Font {
/// Whether to use the built-in font for box drawing characters.
pub builtin_box_drawing: bool,
+
+ /// Unicode codepoint substitutions
+ pub codepoint_substitutions: Vec<CodepointSubstitution>,
}
impl Font {
@@ -88,6 +91,7 @@ impl Default for Font {
normal: Default::default(),
bold: Default::default(),
size: Default::default(),
+ codepoint_substitutions: Default::default(),
}
}
}
@@ -163,3 +167,19 @@ impl<'de> Deserialize<'de> for Size {
deserializer.deserialize_any(NumVisitor)
}
}
+
+/// Configuration for performing substitution for specific codepoints
+#[derive(ConfigDeserialize, Debug, Clone, PartialEq, Eq)]
+pub struct CodepointSubstitution {
+ pub font: String,
+ pub codepoints: Vec<String>,
+}
+
+impl Default for CodepointSubstitution {
+ fn default() -> Self {
+ Self {
+ font: Default::default(),
+ codepoints: Default::default(),
+ }
+ }
+}
diff --git a/alacritty/src/renderer/text/glyph_cache.rs b/alacritty/src/renderer/text/glyph_cache.rs
index 957cde1a..31d3301f 100644
--- a/alacritty/src/renderer/text/glyph_cache.rs
+++ b/alacritty/src/renderer/text/glyph_cache.rs
@@ -76,12 +76,35 @@ pub struct GlyphCache {
/// Whether to use the built-in font for box drawing characters.
builtin_box_drawing: bool,
+
+ // glyph replacements
+ codepoint_substitutions: HashMap<char, FontKey>,
}
impl GlyphCache {
pub fn new(mut rasterizer: Rasterizer, font: &Font) -> Result<GlyphCache, crossfont::Error> {
let (regular, bold, italic, bold_italic) = Self::compute_font_keys(font, &mut rasterizer)?;
+ let mut codepoint_substitutions = HashMap::new();
+
+ // setup the symbol override map
+ for map in font.codepoint_substitutions.iter() {
+ let size = font.size();
+ let description = &FontDescription{
+ family: map.font.clone(),
+ style: font.normal().style.clone(),
+ };
+
+ let fontdesc = Self::make_desc(description, Slant::Normal, Weight::Normal);
+ let mapped_font = Self::load_regular_font(&mut rasterizer, &fontdesc, size)?;
+
+ for codepoint in map.codepoints.iter() {
+ let codepoint_val = u32::from_str_radix(codepoint.replace("U+", "").as_str(), 16);
+ let codepoint_char = char::from_u32(codepoint_val.unwrap());
+ codepoint_substitutions.insert(codepoint_char.unwrap(), mapped_font);
+ }
+ }
+
// Need to load at least one glyph for the face before calling metrics.
// The glyph requested here ('m' at the time of writing) has no special
// meaning.
@@ -101,6 +124,7 @@ impl GlyphCache {
glyph_offset: font.glyph_offset,
metrics,
builtin_box_drawing: font.builtin_box_drawing,
+ codepoint_substitutions,
})
}
@@ -196,8 +220,16 @@ impl GlyphCache {
where
L: LoadGlyph,
{
+ let mut gk = glyph_key;
+
+ // does this need a substitution?
+ if self.codepoint_substitutions.contains_key(&gk.character) {
+ let alt = self.codepoint_substitutions.get(&gk.character).unwrap();
+ gk.font_key = *alt;
+ }
+
// Try to load glyph from cache.
- if let Some(glyph) = self.cache.get(&glyph_key) {
+ if let Some(glyph) = self.cache.get(&gk) {
return *glyph;
};
@@ -207,21 +239,21 @@ impl GlyphCache {
.builtin_box_drawing
.then(|| {
builtin_font::builtin_glyph(
- glyph_key.character,
+ gk.character,
&self.metrics,
&self.font_offset,
&self.glyph_offset,
)
})
.flatten()
- .map_or_else(|| self.rasterizer.get_glyph(glyph_key), Ok);
+ .map_or_else(|| self.rasterizer.get_glyph(gk), Ok);
let glyph = match rasterized {
Ok(rasterized) => self.load_glyph(loader, rasterized),
// Load fallback glyph.
Err(RasterizerError::MissingGlyph(rasterized)) if show_missing => {
// Use `\0` as "missing" glyph to cache it only once.
- let missing_key = GlyphKey { character: '\0', ..glyph_key };
+ let missing_key = GlyphKey { character: '\0', ..gk };
if let Some(glyph) = self.cache.get(&missing_key) {
*glyph
} else {
@@ -236,7 +268,7 @@ impl GlyphCache {
};
// Cache rasterized glyph.
- *self.cache.entry(glyph_key).or_insert(glyph)
+ *self.cache.entry(gk).or_insert(glyph)
}
/// Load glyph into the atlas.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment