-
Notifications
You must be signed in to change notification settings - Fork 61
Fonts
I am no expert on font rendering and some of the details below are likely oversimplified. If you find anything to be inaccurate or misleading please let me know!
The goal is to provide a quick reference to all neovim users, though more likely newer ones, to solve issues related to missing or bad looking icons in terminals. This is an early version and will be updated based on feedback.
If you just want a way to unblock yourself and already know all you want to about font rendering then focus on the Troubleshooting section. Otherwise I encourage you to checkout some of the other sections as well.
In order to use the tables below you need to know 3 pieces of information:
- What problem you are facing with icons. Possible values are:
- Missing �: Icons are either clearly wrong or missing and being shown as a �.
- Too Small: Icons are rendered smaller than you want and are hard to see.
- Too Large: Icons are rendered larger than you want and look squished.
- The terminal emulator you are using for neovim. Currently we have info for:
- The type of Font you are using. Possible values are:
- Nerd Normal: This is if you're using a standard Nerd Font, meaning the name ends with "Nerd Font". For example "JetBrainsMono Nerd Font".
- Nerd Mono: Similar to above, but the monospaced symbol variant, meaning the name ends with "Nerd Font Mono". For example "JetBrainsMono Nerd Font Mono", notice the second "Mono", that is the important part.
- Base: This is the case if you're not not using any kind of Nerd Font, true if no other option is. Probably the case if you have not configured a font.
If your specific problem is not covered by these please reach out!
Once you have all that you can get to the solution. Use the table associated with your problem. Examples:
- Too Small + WezTerm + Base = ✅ Wez Glyphs Grow
- Too Large + kitty + Nerd Mono = ✅ Font -> Base
Terminal / Font | Base | Nerd Normal | Nerd Mono |
---|---|---|---|
WezTerm | ❓ Always Find | ❓ Always Find | ❓ Always Find |
kitty | ❓ Always Find | ❓ Always Find | ❓ Always Find |
Alacritty | ✅ Font -> Any Nerd | ✅ Font -> New Nerd | ✅ Font -> New Nerd |
Legend:
- ✅ = Potential Fix
- ❌ = No Fix
- ❓ = Impossible
Terminal / Font | Base | Nerd Normal | Nerd Mono |
---|---|---|---|
WezTerm | ✅ Wez Glyphs Grow | ✅ Font -> Base | ✅ Font -> Base |
kitty | ✅ Symbol Map Normal | ✅ Font -> Base | ✅ Font -> Base |
Alacritty | ❓ Never Find | ❌ Size Limit | ✅ Font -> Nerd Normal |
Legend:
- ✅ = Potential Fix
- ❌ = No Fix
- ❓ = Impossible
Terminal / Font | Base | Nerd Normal | Nerd Mono |
---|---|---|---|
WezTerm | ✅ Wez Glyphs Shrink | ✅ Font -> Base | ✅ Font -> Base |
kitty | ✅ Symbol Map Mono | ✅ Font -> Base | ✅ Font -> Base |
Alacritty | ❓ Never Find | ✅ Font -> Nerd Mono | ❌ Size Limit |
Legend:
- ✅ = Potential Fix
- ❌ = No Fix
- ❓ = Impossible
There are 2 levers we can pull to grow or shrink icons.
The first lever is through allow_square_glyphs_to_overflow_width.
To grow icons you'll need to allow them to overflow their cells:
config.allow_square_glyphs_to_overflow_width = 'WhenFollowedBySpace'
- This is the default value so this is more of a sanity check that you did not disable this, but you can also set it explicitly if you like.
To shrink icons you'll need to prevent them from overflowing their cells:
config.allow_square_glyphs_to_overflow_width = 'Never'
At this point you can update the config, save, and check the size of the icons to see if you're happy with it. If you are then nothing else is needed.
Otherwise use the second lever through font_with_fallback scale.
In the example below you can replace the <scale>
placeholder with a value > 1
(like 1.10) to grow icons or a value < 1 (like 0.90) to shrink icons.
config.font = wezterm.font_with_fallback({
{ family = '<your_current_font>' },
{ family = 'Symbols Nerd Font Mono', scale = <scale> },
})
Set the font for the symbol_map
described here
to either a Normal Nerd Font or a Mono Nerd Font as specified.
Change terminal emulator font to any Base font. This means not a Nerd Font so does not contain the string "Nerd Font", even Comic Sans works. You can install a new font if you like but that is not necessary. The goal is to have the terminal emulator resolve icons for you using font fallback rather than using the icons that are part of the preferred Nerd Font.
Change terminal emulator font to any Nerd Font. Follow these steps which fill install multiple variants of your chosen Nerd Font. When picking a variant choose any of them.
Change terminal emulator font to a new Nerd Font. Follow these steps but make sure the font you install is different from the one you are currently using. This is to make it likely that the new font will cover icons the previous one did not. When picking a variant choose any of them.
Change terminal emulator font to a Normal Nerd Font. Follow these steps which fill install multiple variants of your chosen Nerd Font. When picking a variant make sure to select the font that ends with "Nerd Font".
Change terminal emulator font to a Mono Nerd Font. Follow these steps which fill install multiple variants of your chosen Nerd Font. When picking a variant make sure to select the font that ends with "Nerd Font Mono".
Some terminal emulators, particularly newer ones, have the ability to search through more than just your default font. If a particular icon is missing it will trigger font fallback which will search through system fonts as well as fonts that come bundled with the terminal emulator by the author. This should prevent any icons from being missing, so if you encounter this let me know!
If a terminal emulator does not support font fallback and you are not using a Nerd Font of some sort it is unexpected any symbol renders in any way other than �, so if you encounter this let me know!
When Nerd Fonts are created from their Base Fonts the authors create multiple variants. We've talked about these before as Nerd and Nerd Mono. The difference between these is that the Nerd variant has double width icons which some terminal emulators can take advantage of when space allows. Nerd Mono on the other hand has single width icons which makes the entire font (base + icons) monospaced.
As a result if you're already using the Normal variant you cannot get bigger icons. Similarly if you're using the Mono variant you cannot get smaller icons. If you find this to not be the case and their is a way around this let me know!
- I have found that for the
SymbolsNerdFont
this is the opposite and the Mono variant is larger than the Normal variant, but this seems like an exception?
- Download a Nerd Font: A popular one is
JetBrainsMono Nerd Font
but any of them should work, pick the one you like. You can do this using: - Install the Font: This depends on your OS and could involve moving a file to a
specific directory, running some command, or is already handled by your package
manager like with
homebrew
. You just need the font to be visible, Google / LLM should help here. - Use the Font: Set the font as your terminal emulator's font. How depends on the
terminal emulator and could be under a settings panel or done through a configuration
file. A search for " font config" should get you there.
- After installing the font you'll have multiple variants available, such as
JetBrainsMono Nerd Font
andJetBrainsMono Nerd Font Mono
. Make sure to use the correct one if specified, otherwise the former is usually a safe choice.
- After installing the font you'll have multiple variants available, such as
This section covers some of the high level details about why we use icons and why they don't always work out of the box.
So you've downloaded neovim and picked up a few plugins, nice! Then you open up your new file tree from neo-tree.nvim or take a look at your status line from lualine.nvim or an awesome markdown renderer :) and you notice the dreaded �, what's going on?
Well, like many people, up until now, you've only ever needed your terminal to display letters, numbers, and the basic symbols you find on your keyboard. So your font, which likely only implements these basic characters was never a problem. Now you want to display complex glyphs / icons, leading to this problem. When your font doesn't implement a particular icon, your terminal emulator (WezTerm, kitty, Alacritty, iTerm2, etc.) doesn't know what to do, so as a last resort will show you the �. At this point might have some questions, it's a good time to browse the FAQs to see if they're covered before moving on.
How text is rendered by your terminal emulator depends on the 2 things you would expect, the font and the terminal emulator itself. What text can be rendered depends on these same 2 things.
The burden of who needs to provide all the necessary icons results in 2 distinct approaches. If the font does the heavy lifting we end up with "Patched Nerd Fonts" and if the terminal emulator does we end up with font fallback. I'll briefly touch on the former and explain why it may still be your only viable option first.
Patched Nerd Fonts are generated by taking some existing Base Font, like
JetBrains Mono
, and filling all the "gaps" with a set of common icons. This creates
a new font with a name like JetBrainsMono Nerd Font
which is managed and distributed
completely separately from the Base Font. These also will typically come with different
variants of the same font like a version with monospaced icons (by default icons
are double width) named JetBrainsMono Nerd Font Mono
.
By offloading this effort to the font the terminal emulator can avoid any complexity in handling missing icons. Instead either the configured font has the icon and we use it or we fallback to a default and move on. This also avoid any merging and mangling of multiple fonts, glorious simplicity.
You may come across information saying you should not use these fonts and they're "bad practice" or "harmful". These are opinions with some legitimate reasons behind them. I would not go so far but if you are able to avoid using them then that will likely lead to a more consistent experience for you. However sometimes you just can't, and if there is no alternative, like a mandatory terminal emulator you need to use for work that doesn't implement font fallback then Patched Nerd Fonts are really your only option, and they're not even a bad one.
Now for the more complex alternative of terminal emulators that build out font fallback and as a result avoid the need for users to use Patched Nerd Fonts. Below is a table of those that implement the feature:
Terminal | Font Fallback |
---|---|
WezTerm | ✅ |
kitty | ✅ |
Alacritty | ❌ |
The way this works at a high level is fairly simple to understand. Sure, your main font may not have some icon, but maybe some other font on your system does. Better yet even if no font on your system does there's nothing stopping us from bundling fonts directly into the terminal emulator as a fallback in case all else fails. Now the complexity of joining glyphs from separate fonts and making it look cohesive is not trivial, but once the work is done you end up with an incredibly robust font rendering experience. Many such terminal emulators will bundle a "symbols only" font which is just the icons from nerd fonts without the standard letters / numbers, those are provided by your preferred font. This means you don't need wait for a Patched version of your favorite font to be created. Instead you can use any font you want, yes, including Comic Sans, and any missing symbols get filled in by the terminal emulator on the fly, awesome!
How the fallback works will depend on the terminal emulator's implementation. If you are using a supported terminal emulator then in theory you should never see a � ever. It is highly recommended to avoid Patched Nerd Fonts when using these terminal emulators since the fallback only kicks in if your font is missing an icon. This will typically result in a more configurable and cohesive experience, especially if the terminal emulator gives you control of how the fallback works.
This is a very niche problem that most fonts don't need to solve. These missing icons are most likely what are referred to as Nerd Font Icons, and there are over 10,000 of them.
The idea of every font shipping with implementations for all these icons is crazy if you think about it. Who out there using Comic Sans in Word is trying to inline the GitHub logo as text? If font authors went through the trouble of making unique icons it would be an insane amount of work for a small portion of users. If they shared the same icons and kept the font part unique all fonts would get much bigger. Maybe not much of a problem now but still wasteful and extra effort.
GUI applications do not come with the same set of limitations as a terminal. They can render an image no problem. Terminals on the other hand are a fixed size grid where we can paint some pixels in each cell. We've essentially taken some UTF-8 encodings and mapped them to icons using the power fonts.
Well maybe not directly, but some plugin you're using did. Somewhere in the code for the plugin you'll find the UTF-8 encoded character that represents the icon your font is missing.
You're technically correct, we do it for the aesthetic :P I'll add that icons, when used effectively, can give you a lot of information at a glance. With file trees for instance they will tell you what's a folder and the type of each file, once you know what you're looking at. It's likely a bit of both and it's totally reasonable to want things to look nice in an environment you spend hours a day in.
The purist may disagree, and the purist is free to use something else or write it themselves.
No, this is not possible in any terminal emulator that I am aware of. I'm not really sure where the fundamental limitation is. Terminals have been grids since their inception, but in theory this is not mandatory. Though I do not believe there are any ANSI sequences that exist that would allow text size information to be communicated to the terminal emulator. Maybe one day ANSI sequences will be added, terminals will be updated, and neovim will add support, or maybe there's more challenges involved, or maybe it's just not that important. In either case for now this doesn't exist.