Repository: alacritty/alacritty (language: rust)

Issue:
Powerline font cut off on 0.13
After updating to 0.13, powerline icons have started rendering incorrectly. On 0.12 it used to render as expected, but now it's cutting off the "points" of the powerline triangles. Here's a screenshot of what it looks like:

![new](https://pyazo.com/32da3ce6-8d78-469d-b2ff-d81b09ba7390.png)

And here's what it used to look like before (downgraded to 0.12 for the screenshot):

![old](https://pyazo.com/633569b7-0e7a-49f5-9eb0-8e8235c09353.png)

I use the IosevkaTerm font with NerdFont patches (https://www.nerdfonts.com/font-downloads)

Here's my config, after migrating to toml:

```toml
import = ["/home/pavle/.config/alacritty/gruvbox.toml"]

[font]
size = 8

[font.normal]
family = "IosevkaTerm NFP"
style = "Regular"

[font.offset]
x = 0
y = 0

[scrolling]
history = 40000

[window]
dynamic_title = true

[window.class]
general = "Alacritty"
instance = "Alacritty"
```

gruvbox.toml just defines some colors and I get the same behaviour with and without that file included.

### System

OS: Linux
Version: alacritty 0.13.0 (78fa4d6f)
Linux: X11, i3, no compositor

### Logs

Crashes: N/A
Font/Terminal size: `alacritty -vv`

```
[0.000004989s] [INFO ] [alacritty] Welcome to Alacritty
[0.000079378s] [INFO ] [alacritty] Version 0.13.0 (78fa4d6f)
[0.000091781s] [INFO ] [alacritty] Running on X11
[0.000748226s] [INFO ] [alacritty] Configuration files loaded from:
                                     "/home/pavle/.config/alacritty/alacritty.toml"
                                     "/home/pavle/.config/alacritty/gruvbox.toml"
[0.009097137s] [INFO ] [alacritty] Using GLX 1.4
[0.073722849s] [DEBUG] [alacritty] Picked GL Config:
                                     buffer_type: Some(Rgb { r_size: 8, g_size: 8, b_size: 8 })
                                     alpha_size: 8
                                     num_samples: 0
                                     hardware_accelerated: true
                                     supports_transparency: Some(true)
                                     config_api: Api(OPENGL | GLES1 | GLES2)
                                     srgb_capable: false
[0.084864511s] [INFO ] [alacritty] Window scale factor: 2.0833333333333335
[0.087529144s] [DEBUG] [alacritty] Loading "MonoFont" font
[0.103752469s] [DEBUG] [crossfont] Loaded Face Face { ft_face: Font Face: Regular, load_flags: TARGET_LIGHT, render_mode: "Lcd", lcd_filter: 1 }
[0.113076890s] [DEBUG] [crossfont] Loaded Face Face { ft_face: Font Face: Bold, load_flags: TARGET_LIGHT, render_mode: "Lcd", lcd_filter: 1 }
[0.120644422s] [DEBUG] [crossfont] Loaded Face Face { ft_face: Font Face: Italic, load_flags: TARGET_LIGHT, render_mode: "Lcd", lcd_filter: 1 }
[0.127604070s] [DEBUG] [crossfont] Loaded Face Face { ft_face: Font Face: Bold Italic, load_flags: TARGET_LIGHT, render_mode: "Lcd", lcd_filter: 1 }
[0.144804840s] [INFO ] [alacritty] Running on AMD Radeon Graphics (radeonsi, gfx1103_r1, LLVM 16.0.6, DRM 3.54, 6.6.8-arch1-1)
[0.144839404s] [INFO ] [alacritty] OpenGL version 4.6 (Core Profile) Mesa 23.3.1-arch1.1, shader_version 4.60
[0.144850114s] [INFO ] [alacritty] Using OpenGL 3.3 renderer
[0.154266316s] [DEBUG] [alacritty] Enabled debug logging for OpenGL
[0.154368277s] [DEBUG] [alacritty] Filling glyph cache with common glyphs
[0.191422396s] [INFO ] [alacritty] Cell size: 11 x 29
[0.191455027s] [INFO ] [alacritty] Padding: 0 x 0
[0.191463893s] [INFO ] [alacritty] Width: 800, Height: 600
[0.209875893s] [INFO ] [alacritty] PTY dimensions: 20 x 72
[0.214991469s] [INFO ] [alacritty] Initialisation complete
[0.221732670s] [DEBUG] [alacritty_terminal] New num_cols is 205 and num_lines is 48
[0.223415199s] [INFO ] [alacritty] Padding: 0 x 0
[0.223435497s] [INFO ] [alacritty] Width: 2256, Height: 1416
```

Keyboard and bindings: `alacritty --print-events`

```
[0.000004959s] [INFO ] [alacritty] Welcome to Alacritty
[0.000062587s] [INFO ] [alacritty] Version 0.13.0 (78fa4d6f)
[0.000072315s] [INFO ] [alacritty] Running on X11
[0.000711648s] [INFO ] [alacritty] Configuration files loaded from:
                                     "/home/pavle/.config/alacritty/alacritty.toml"
                                     "/home/pavle/.config/alacritty/gruvbox.toml"
[0.006861084s] [INFO ] [alacritty] winit event: NewEvents(Init)
[0.006887523s] [INFO ] [alacritty] winit event: Resumed
[0.009332947s] [INFO ] [alacritty] Using GLX 1.4
[0.077207692s] [INFO ] [alacritty] Window scale factor: 2.0833333333333335
[0.134859680s] [INFO ] [alacritty] Running on AMD Radeon Graphics (radeonsi, gfx1103_r1, LLVM 16.0.6, DRM 3.54, 6.6.8-arch1-1)
[0.134890698s] [INFO ] [alacritty] OpenGL version 4.6 (Core Profile) Mesa 23.3.1-arch1.1, shader_version 4.60
[0.134896399s] [INFO ] [alacritty] Using OpenGL 3.3 renderer
[0.180725694s] [INFO ] [alacritty] Cell size: 11 x 29
[0.180777861s] [INFO ] [alacritty] Padding: 0 x 0
[0.180786918s] [INFO ] [alacritty] Width: 800, Height: 600
[0.197625542s] [INFO ] [alacritty] PTY dimensions: 20 x 72
[0.204319724s] [INFO ] [alacritty] Initialisation complete
[0.204378714s] [INFO ] [alacritty] winit event: DeviceEvent { device_id: DeviceId(X(DeviceId(12))), event: Key(RawKeyEvent { physical_key: Code(Enter), state: Released }) }
[0.209233604s] [INFO ] [alacritty] winit event: WindowEvent { window_id: WindowId(WindowId(73400323)), event: Ime(Disabled) }
[0.209321719s] [INFO ] [alacritty] winit event: WindowEvent { window_id: WindowId(WindowId(73400323)), event: Ime(Enabled) }
[0.209681099s] [INFO ] [alacritty] winit event: WindowEvent { window_id: WindowId(WindowId(73400323)), event: Resized(PhysicalSize { width: 2256, height: 1416 }) }
[0.209704112s] [INFO ] [alacritty] winit event: WindowEvent { window_id: WindowId(WindowId(73400323)), event: Focused(false) }
[0.209720272s] [INFO ] [alacritty] winit event: WindowEvent { window_id: WindowId(WindowId(73400323)), event: Occluded(false) }
[0.209892424s] [INFO ] [alacritty] winit event: WindowEvent { window_id: WindowId(WindowId(73400323)), event: CursorEntered { device_id: DeviceId(X(DeviceId(2))) } }
[0.209909095s] [INFO ] [alacritty] winit event: WindowEvent { window_id: WindowId(WindowId(73400323)), event: CursorMoved { device_id: DeviceId(X(DeviceId(2))), position: PhysicalPosition { x: 736.0, y: 968.0 } } }
[0.209936686s] [INFO ] [alacritty] winit event: WindowEvent { window_id: WindowId(WindowId(73400323)), event: Moved(PhysicalPosition { x: 0, y: 59 }) }
[0.210007659s] [INFO ] [alacritty] winit event: WindowEvent { window_id: WindowId(WindowId(73400323)), event: Focused(true) }
[0.210017697s] [INFO ] [alacritty] winit event: WindowEvent { window_id: WindowId(WindowId(73400323)), event: CursorMoved { device_id: DeviceId(X(DeviceId(2))), position: PhysicalPosition { x: 736.0, y: 968.0 } } }
[0.210786011s] [INFO ] [alacritty] winit event: WindowEvent { window_id: WindowId(WindowId(73400323)), event: RedrawRequested }
[0.214663447s] [INFO ] [alacritty] Padding: 0 x 0
[0.214751281s] [INFO ] [alacritty] Width: 2256, Height: 1416
[0.236200459s] [INFO ] [alacritty] winit event: AboutToWait
[0.236334679s] [INFO ] [alacritty] winit event: NewEvents(WaitCancelled { start: Instant { tv_sec: 2055, tv_nsec: 436718989 }, requested_resume: Some(Instant { tv_sec: 2055, tv_nsec: 453279440 }) })
[0.236416342s] [INFO ] [alacritty] winit event: AboutToWait
[0.242346689s] [INFO ] [alacritty] winit event: NewEvents(WaitCancelled { start: Instant { tv_sec: 2055, tv_nsec: 436849352 }, requested_resume: Some(Instant { tv_sec: 2055, tv_nsec: 453279440 }) })
[0.242674921s] [INFO ] [alacritty] winit event: WindowEvent { window_id: WindowId(WindowId(73400323)), event: KeyboardInput { device_id: DeviceId(X(DeviceId(3))), event: KeyEvent { physical_key: Code(CapsLock), logical_key: Named(Control), text: None, location: Left, state: Pressed, repeat: false, platform_specific: KeyEventExtra { key_without_modifiers: Named(Control), text_with_all_modifiers: None } }, is_synthetic: false } }
[0.242735414s] [INFO ] [alacritty] winit event: WindowEvent { window_id: WindowId(WindowId(73400323)), event: ModifiersChanged(Modifiers { state: ModifiersState(CONTROL), pressed_mods: ModifiersKeys(0x0) }) }
[0.242788333s] [INFO ] [alacritty] winit event: AboutToWait
[0.252934056s] [INFO ] [alacritty] winit event: NewEvents(ResumeTimeReached { start: Instant { tv_sec: 2055, tv_nsec: 443241030 }, requested_resume: Instant { tv_sec: 2055, tv_nsec: 453279440 } })
[0.252988799s] [INFO ] [alacritty] winit event: AboutToWait
[0.253012282s] [INFO ] [alacritty] winit event: NewEvents(WaitCancelled { start: Instant { tv_sec: 2055, tv_nsec: 453427419 }, requested_resume: None })
[0.253027651s] [INFO ] [alacritty] winit event: UserEvent(Event { window_id: Some(WindowId(WindowId(73400323))), payload: Frame })
[0.253045144s] [INFO ] [alacritty] winit event: AboutToWait
[0.352253513s] [INFO ] [alacritty] winit event: NewEvents(WaitCancelled { start: Instant { tv_sec: 2055, tv_nsec: 453479937 }, requested_resume: None })
[0.352313645s] [INFO ] [alacritty] winit event: UserEvent(Event { window_id: Some(WindowId(WindowId(73400323))), payload: Terminal(Title(pavle@niccolum:~/.config/alacritty)) })
[0.352331759s] [INFO ] [alacritty] winit event: UserEvent(Event { window_id: Some(WindowId(WindowId(73400323))), payload: Terminal(Wakeup) })
[0.352349171s] [INFO ] [alacritty] winit event: WindowEvent { window_id: WindowId(WindowId(73400323)), event: RedrawRequested }
[0.357282287s] [INFO ] [alacritty] winit event: AboutToWait
[0.357359331s] [INFO ] [alacritty] winit event: NewEvents(WaitCancelled { start: Instant { tv_sec: 2055, tv_nsec: 557751645 }, requested_resume: None })
[0.357403584s] [INFO ] [alacritty] winit event: UserEvent(Event { window_id: Some(WindowId(WindowId(73400323))), payload: Frame })
[0.357422819s] [INFO ] [alacritty] winit event: AboutToWait
[0.398924769s] [INFO ] [alacritty] winit event: NewEvents(WaitCancelled { start: Instant { tv_sec: 2055, tv_nsec: 557857603 }, requested_resume: None })
[0.399017652s] [INFO ] [alacritty] winit event: UserEvent(Event { window_id: Some(WindowId(WindowId(73400323))), payload: Terminal(Wakeup) })
[0.399042379s] [INFO ] [alacritty] winit event: UserEvent(Event { window_id: Some(WindowId(WindowId(73400323))), payload: Terminal(Wakeup) })
[0.399059410s] [INFO ] [alacritty] winit event: WindowEvent { window_id: WindowId(WindowId(73400323)), event: RedrawRequested }
[0.401263964s] [INFO ] [alacritty] winit event: AboutToWait
[0.401314819s] [INFO ] [alacritty] winit event: NewEvents(WaitCancelled { start: Instant { tv_sec: 2055, tv_nsec: 601722562 }, requested_resume: None })
[0.401337091s] [INFO ] [alacritty] winit event: UserEvent(Event { window_id: Some(WindowId(WindowId(73400323))), payload: Frame })
[0.401351928s] [INFO ] [alacritty] winit event: AboutToWait
[0.434700943s] [INFO ] [alacritty] winit event: NewEvents(WaitCancelled { start: Instant { tv_sec: 2055, tv_nsec: 601789106 }, requested_resume: None })
[0.434828592s] [INFO ] [alacritty] winit event: WindowEvent { window_id: WindowId(WindowId(73400323)), event: KeyboardInput { device_id: DeviceId(X(DeviceId(3))), event: KeyEvent { physical_key: Code(KeyG), logical_key: Character("d"), text: Some("d"), location: Standard, state: Pressed, repeat: false, platform_specific: KeyEventExtra { key_without_modifiers: Character("d"), text_with_all_modifiers: Some("\u{4}") } }, is_synthetic: false } }
[0.434882262s] [INFO ] [alacritty] winit event: AboutToWait
[0.435315650s] [INFO ] [alacritty] winit event: NewEvents(WaitCancelled { start: Instant { tv_sec: 2055, tv_nsec: 635356228 }, requested_resume: None })
[0.435348672s] [INFO ] [alacritty] winit event: UserEvent(Event { window_id: Some(WindowId(WindowId(73400323))), payload: Terminal(Wakeup) })
[0.435368990s] [INFO ] [alacritty] winit event: WindowEvent { window_id: WindowId(WindowId(73400323)), event: RedrawRequested }
[0.437200468s] [INFO ] [alacritty] winit event: AboutToWait
[0.437243739s] [INFO ] [alacritty] winit event: NewEvents(WaitCancelled { start: Instant { tv_sec: 2055, tv_nsec: 637655870 }, requested_resume: None })
[0.437268815s] [INFO ] [alacritty] winit event: UserEvent(Event { window_id: Some(WindowId(WindowId(73400323))), payload: Frame })
[0.437280086s] [INFO ] [alacritty] winit event: AboutToWait
[0.464670962s] [INFO ] [alacritty] winit event: NewEvents(WaitCancelled { start: Instant { tv_sec: 2055, tv_nsec: 637711744 }, requested_resume: None })
[0.464714654s] [INFO ] [alacritty] winit event: UserEvent(Event { window_id: Some(WindowId(WindowId(73400323))), payload: Terminal(Exit) })
[0.471298070s] [INFO ] [alacritty] winit event: UserEvent(Event { window_id: Some(WindowId(WindowId(73400323))), payload: Terminal(Wakeup) })
[0.471327855s] [INFO ] [alacritty] winit event: AboutToWait
[0.471335900s] [INFO ] [alacritty] winit event: LoopExiting
[0.472613905s] [INFO ] [alacritty] Goodbye
```


Discussion / hints:
Yeah, narrow fonts will probably break like that because they can't create a `45` angle which was intended for powerline glyphs.
You can disable builtin box drawing or use `Extended` variant of iosevka for now.
@kchibisov What do you plan to change about this?
@chrisduerr we can try to draw with different angle when the cut is too much or we may opt-out of drawing powerline when the cut will be too big with the way we try to.

If you have suggestion let me know.
The built-in powerline seems broken, since it is offset from the top. So it's also not able to draw things correctly. Considering that, I'm not sure what we're doing is much worse.
>The built-in powerline seems broken, since it is offset from the top.

I don't quite get what you mean here, like that it draws from outside the cell by 1px? From what I can see in the font it's not like that, the angle is just different and that's about it (I've used that font and it's just different angle). We can also try to draw with different angle when we detect big cut.
> I don't quite get what you mean here, like that it draws from outside the cell by 1px?

It's one pixel farther from the top than from the bottom.
yeah, but it doesn't really matter as long as it's not massively cut? Like there's no definition that the angle should be exactly 45, like it still meets at the center of the cell (at least you can patch the font to start correctly within cell boundarios and it'll have the same 60 angle).

Fix patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 5c0f5ef36fd..16601355b18 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -15,6 +15,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
 - `chars = "\u000A"` action in bindings inserting `\n`
 - Alternate keys not sent for `Shift + <number>` when using kitty protocol
 - Alternative keys being swapped in kitty protocol implementation
+- Powerline glyphs being cut for narrow fonts
 
 ## 0.13.0
 
diff --git a/alacritty/src/renderer/text/builtin_font.rs b/alacritty/src/renderer/text/builtin_font.rs
index c3f843b6704..f59616d5a0d 100644
--- a/alacritty/src/renderer/text/builtin_font.rs
+++ b/alacritty/src/renderer/text/builtin_font.rs
@@ -32,7 +32,7 @@ pub fn builtin_glyph(
         '\u{2500}'..='\u{259f}' => box_drawing(character, metrics, offset),
         // Powerline symbols: '','','',''
         POWERLINE_TRIANGLE_LTR..=POWERLINE_ARROW_RTL => {
-            powerline_drawing(character, metrics, offset)
+            powerline_drawing(character, metrics, offset)?
         },
         _ => return None,
     };
@@ -503,7 +503,11 @@ fn box_drawing(character: char, metrics: &Metrics, offset: &Delta<i8>) -> Raster
     }
 }
 
-fn powerline_drawing(character: char, metrics: &Metrics, offset: &Delta<i8>) -> RasterizedGlyph {
+fn powerline_drawing(
+    character: char,
+    metrics: &Metrics,
+    offset: &Delta<i8>,
+) -> Option<RasterizedGlyph> {
     let height = (metrics.line_height as i32 + offset.y as i32) as usize;
     let width = (metrics.average_advance as i32 + offset.x as i32) as usize;
     let extra_thickness = calculate_stroke_size(width) as i32 - 1;
@@ -519,6 +523,12 @@ fn powerline_drawing(character: char, metrics: &Metrics, offset: &Delta<i8>) ->
     // x = (H - 2) / (2 * slope).
     let x_intersection = (height as i32 + 1) / 2 - 1;
 
+    // Don't use built-in font if we'd cut the tip too much, for example when the font is really
+    // narrow.
+    if x_intersection - width as i32 > 1 {
+        return None;
+    }
+
     let top_line = (0..x_intersection).map(|x| line_equation(slope, x, top_y));
     let bottom_line = (0..x_intersection).map(|x| line_equation(-slope, x, bottom_y));
 
@@ -555,7 +565,7 @@ fn powerline_drawing(character: char, metrics: &Metrics, offset: &Delta<i8>) ->
 
     let top = height as i32 + metrics.descent as i32;
     let buffer = BitmapBuffer::Rgb(canvas.into_raw());
-    RasterizedGlyph {
+    Some(RasterizedGlyph {
         character,
         top,
         left: 0,
@@ -563,7 +573,7 @@ fn powerline_drawing(character: char, metrics: &Metrics, offset: &Delta<i8>) ->
         width: width as i32,
         buffer,
         advance: (width as i32, height as i32),
-    }
+    })
 }
 
 #[repr(packed)]


Test patch: