Skip to content

bug: Multi-codepoint emojis fail silently in theme.yml glyph fieldΒ #1654

@dcadenas

Description

@dcadenas

Bug Description

Emojis with Unicode variation selectors (like πŸ–ΌοΈ and πŸ–₯️) cause the entire theme.yml file to be silently ignored due to deserialization failure.

Reproduction Steps

  1. Create ~/.config/eza/theme.yml with:
filenames:
  data: {icon: {glyph: πŸ’Ύ}}        # Works - single codepoint
  Pictures: {icon: {glyph: πŸ–ΌοΈ}}    # Fails - has variation selector
  Desktop: {icon: {glyph: πŸ–₯️}}     # Fails - has variation selector
  1. Run eza -l --icons

Expected Behavior

All custom icons should display, including emojis with variation selectors.

Actual Behavior

  • The data icon (πŸ’Ύ) displays correctly
  • Theme parsing fails silently when it encounters πŸ–ΌοΈ or πŸ–₯️
  • All subsequent icons in theme.yml are ignored
  • User receives no error message

Root Cause

The glyph field in IconStyle and IconStyleOverride structs is defined as Option<char>:

src/theme/ui_styles.rs:18

pub struct IconStyle {
    pub glyph: Option<char>,  // ❌ Can only hold single Unicode scalar
    pub style: Option<Style>,
}

src/options/config.rs:210

pub struct IconStyleOverride {
    pub glyph: Option<char>,  // ❌ Same issue
    pub style: Option<StyleOverride>,
}

Rust's char type represents a single Unicode scalar value. However, many emojis consist of multiple codepoints:

Emoji Description Codepoints Status
πŸ–ΌοΈ Picture frame U+1F5BC + U+FE0F ❌ Fails
πŸ–₯️ Desktop computer U+1F5A5 + U+FE0F ❌ Fails
πŸ‘¨β€πŸ’» Man technologist U+1F468 + U+200D + U+1F4BB ❌ Fails
πŸ‡ΊπŸ‡Έ US flag U+1F1FA + U+1F1F8 ❌ Fails
πŸ’Ύ Floppy disk U+1F4BE βœ… Works

The second codepoint (U+FE0F) is a variation selector - an invisible modifier that tells the system to render the character as a colorful emoji.

Silent Failure

src/options/config.rs:617-621

pub fn to_theme(&self) -> Option<UiStyles> {
    let ui_styles_override: Option<UiStylesOverride> = {
        let file = std::fs::File::open(&self.location).ok()?;
        serde_norway::from_reader(&file).ok()  // ❌ .ok() swallows errors!
    };
    FromOverride::from(ui_styles_override, Some(UiStyles::default()))
}

The .ok() converts deserialization errors into None, causing the entire theme.yml to be ignored with no warning.

Affected Emojis

This affects:

  • βœ… Emojis with variation selectors (U+FE0F): πŸ–ΌοΈ πŸ–₯️ ⌚️ ☎️
  • βœ… ZWJ (Zero Width Joiner) sequences: πŸ‘¨β€πŸ’» πŸ‘©β€πŸŽ¨ πŸ‘¨β€πŸ‘©β€πŸ‘§β€πŸ‘¦
  • βœ… Flag emojis (regional indicators): πŸ‡ΊπŸ‡Έ πŸ‡¬πŸ‡§ πŸ‡―πŸ‡΅
  • βœ… Skin tone modifiers: πŸ‘‹πŸ» πŸ‘‹πŸΏ
  • βœ… Any other multi-codepoint emoji

Environment

  • eza version: v0.23.4
  • OS: Linux (affects all platforms)
  • Shell: Any
  • Terminal: Any

Proposed Solution

  1. Change glyph field from Option<char> to Option<String> to support grapheme clusters
  2. Add proper error handling to report deserialization failures instead of silently ignoring them

This would enable full emoji support while maintaining backward compatibility with existing single-character icons.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions