The Font Naming System is responsible for renaming source fonts during the patching process to comply with licensing requirements, add Nerd Fonts branding, differentiate between variants, and ensure cross-platform compatibility. This page documents the architecture and implementation of the font renaming pipeline.
For information about the overall patching process, see Font Patching System. For command-line options related to naming, see Patching Options.
When Nerd Fonts patches a font, it must rename the font to:
The naming system consists of three main components working together:
Architecture: Font Naming Pipeline
Sources: font-patcher530-786 bin/scripts/name_parser/FontnameParser.py1-384 bin/scripts/name_parser/FontnameTools.py1-453 </old_str> <new_str> Architecture: Font Naming Pipeline
Sources: font-patcher530-786 bin/scripts/name_parser/FontnameParser.py1-384 bin/scripts/name_parser/FontnameTools.py1-453
The FontnameParser class (bin/scripts/name_parser/FontnameParser.py7-384) is the core component that parses font names and generates all required SFNT name table entries.
Key responsibilities:
add_name_substitution_table()macstyle, fsSelection)Main methods:
| Method | SFNT ID | Description |
|---|---|---|
family() | 1 | Family name (RIBBI-constrained) |
subfamily() | 2 | SubFamily (Regular/Bold/Italic/Bold Italic only) |
fullname() | 4 | Full human-readable name |
psname() | 6 | PostScript name (no spaces) |
preferred_family() | 16 | Typographic/WWS family |
preferred_styles() | 17 | Typographic/WWS subfamily |
rename_font(font) | all | Applies all generated names to a FontForge font object |
macstyle(style) | — | Sets bold/italic bits in font.macstyle |
fs_selection(fs) | — | Sets flags in font.os2_stylemap |
The FontnameTools class (bin/scripts/name_parser/FontnameTools.py7-453) provides utility functions and data structures for name manipulation.
Key features:
SIL_TABLE — Regex-based Reserved Font Name substitutions (bin/scripts/name_parser/FontnameTools.py188-227)parse_font_name(name) — Splits a font name string into (basename, weight_token, style_token, other_token, rest) (bin/scripts/name_parser/FontnameTools.py394-453)shorten_style_name() / short_styles() — Length compliance helperspostscript_char_filter() — Strips characters invalid in PostScript namesweight_string_to_number() / weight_to_string() — Weight value conversionsThe setup_font_names() function (font-patcher539-786) orchestrates the renaming process within the main patcher script. It is preceded by setup_name_backup() (font-patcher530-536) which stores the original font names so the font can be renamed multiple times (once per output variant).
Workflow:
font.persistentMono/Propo) and icon set abbreviationsreservedFontNameReplacements dictFontnameParser-based naming (makegroups > 0) or legacy string manipulationfont.comment and font.fontlog with project infoSources: font-patcher530-786 bin/scripts/name_parser/FontnameParser.py7-384 bin/scripts/name_parser/FontnameTools.py7-453
A complete font name is composed of several token types that are parsed and recombined:
Token Flow: parse_font_name() → Name Generation Methods
The token dictionaries are defined as class attributes in FontnameTools:
| Token Type | Dictionary/List | Examples | Source |
|---|---|---|---|
| Weights (no modifier) | known_weights1 | Medium, Nord, Book, Demi, Regular | bin/scripts/name_parser/FontnameTools.py240-251 |
| Weights (with modifier) | known_weights2 | Black, Bold, Heavy, Thin, Light | bin/scripts/name_parser/FontnameTools.py252-259 |
| Styles (RIBBI set) | known_styles | Bold, Italic, Regular, Normal | bin/scripts/name_parser/FontnameTools.py260-262 |
| Widths | known_widths | Compressed, Extended, Condensed, Narrow | bin/scripts/name_parser/FontnameTools.py263-269 |
| Slopes | known_slopes | Inclined, Oblique, Italic, Upright, Kursiv | bin/scripts/name_parser/FontnameTools.py270-277 |
| Modifiers | known_modifiers | Demi, Ultra, Semi, Extra | bin/scripts/name_parser/FontnameTools.py278-283 |
Sources: bin/scripts/name_parser/FontnameTools.py138-175 bin/scripts/name_parser/FontnameTools.py240-295 bin/scripts/name_parser/FontnameTools.py394-453
Many source fonts are licensed under the SIL Open Font License with Reserved Font Names. Modified versions cannot use the original name. Nerd Fonts handles this through the SIL_TABLE:
The SIL_TABLE is defined in FontnameTools.py188-227 and contains 27 regex patterns with replacement strings. Key examples:
| Original Pattern | Replacement | Reason |
|---|---|---|
(s)ource | \1auce | Source Code Pro → Sauce Code Pro |
(c)ascadia( ?)(c)ode | \1askaydia\2\3ove | Cascadia Code → Caskaydia Cove |
(h)ermit | \1urmit | Hermit → Hurmit |
IBM[- ]?plex | Blex | IBM Plex → Blex |
(f)ira | \1ura | Fira Mono → Fura Mono |
The font_patcher.setup_font_names() function also applies additional name cleanup using replace_font_name() on three separate dictionaries (font-patcher688-763):
reservedFontNameReplacements — OFL/RFN-driven substitutions (30+ entries), e.g. 'source' → 'sauce', 'Hermit' → 'Hurmit'additionalFontNameReplacements — removes 'for Powerline' / 'ForPowerline' stringsadditionalFontNameReplacements2 — removes remaining 'Powerline' tokensThese replacements run in the legacy naming path. When FontnameParser is active (makegroups > 0), RFN handling is done instead via SIL_TABLE in add_name_substitution_table().
Sources: bin/scripts/name_parser/FontnameTools.py188-227 font-patcher688-763
OpenType fonts store names in the SFNT name table with specific name IDs. Nerd Fonts must populate these correctly for proper font behavior:
| ID | Name | Purpose | Max Length | Example |
|---|---|---|---|---|
| 1 | Family | Classic family for RIBBI grouping | 31 chars | Fura Code Nerd Font |
| 2 | SubFamily | Style within RIBBI (Regular/Bold/Italic/Bold Italic) | 31 chars | Bold Italic |
| 3 | UniqueID | Unique identifier | - | Fura Code Nerd Font Bold Italic 3.4.0 |
| 4 | Full name | Complete human-readable name | 63 chars | Fura Code Nerd Font Bold Italic |
| 6 | PostScript name | No spaces, for PS printers | 63 chars | FuraCodeNerdFont-BoldItalic |
| 16 | Typographic Family | Extended family (WWS) | 31 chars | Fura Code Nerd Font |
| 17 | Typographic Subfamily | Extended styles | 31 chars | SemiBold Italic |
Name IDs 1 and 2 must follow the "RIBBI" (Regular, Bold, Italic, Bold Italic) constraint for maximum compatibility with older applications. Any weights other than Bold must be moved to ID 1:
The logic for this is in FontnameParser.family() and FontnameParser.subfamily() methods (bin/scripts/name_parser/FontnameParser.py216-242).
Sources: bin/scripts/name_parser/FontnameParser.py122-214 bin/scripts/name_parser/FontnameParser.py323-384
The complete name generation flow when --makegroups > 0 is specified:
Control Flow: setup_name_backup() → setup_font_names() → rename_font()
Parser source name selection (font-patcher597-623):
font.fullname when it equals the PostScript name or for known fonts (e.g. Meslo)--name full|postscript|filename|<literal> overrides via self.args.force_nameSuffix construction (font-patcher546-595):
additionalFontNameSuffix carries the verbose " Nerd Font Mono" / " Nerd Font Propo" stringps_suffix carries the short PS form: "NF", "NFM", "NFP"--complete is not set, per-icon-set abbreviations are appended (e.g. " A" for Font Awesome)rename_font() internals (bin/scripts/name_parser/FontnameParser.py323-384):
Family, SubFamily, Fullname, PostScriptName, Preferred Family, Preferred Styles, UniqueID, and related entries from font.sfnt_namesfont.macstyle and font.os2_stylemapSources: font-patcher530-786 bin/scripts/name_parser/FontnameParser.py323-384 bin/scripts/name_parser/FontnameParser.py10-120
Font names have strict length limits. The system handles this through truncation:
Truncation strategy (FontnameParser.py27-44):
basename-styleOriginal: VeryLongFontFamilyNameThatExceedsLimit-BoldItalic (55 chars)
After: VeryLongFontFamilyNameThat-BoldItalic (37 chars)
└─────────────────────────┘
Truncated to fit 63 char limit
When enable_short_families() is used, the system has three modes:
| Mode | Aggressive | Effect |
|---|---|---|
| Mild | False | Use longer short forms (e.g., "Bold" not "Bd") |
| Moderate | False + prefix | Shorten weights but keep readable |
| Aggressive | True | Use shortest forms everywhere (e.g., "Bd", "It") |
The shortening tables are in FontnameTools.py240-283:
Sources: bin/scripts/name_parser/FontnameParser.py27-44 bin/scripts/name_parser/FontnameParser.py278-284 bin/scripts/name_parser/FontnameTools.py92-118
The font-patcher supports different naming modes via the --makegroups flag:
Implementation details:
Mode < 0 (font-patcher765-766): Skip renaming entirely — warns that RFN license compliance is the user's responsibility.
Mode 0 (font-patcher767-776): Legacy string-manipulation path; uses font.familyname, font.fullname, font.fontname directly plus appendSFNTName() calls.
Modes 1–6 (font-patcher597-784): Use FontnameParser with different enable_short_families() and inject_suffix() configurations:
| Mode | makegroups in [2,3,5,6] | makegroups in [3,6] | makegroups >= 4 |
|---|---|---|---|
| 1 | No short styles | No aggressive | Full: "Nerd Font Mono" |
| 2 | Short styles | No aggressive | Full: "Nerd Font Mono" |
| 3 | Short styles | Aggressive | Full: "Nerd Font Mono" |
| 4 | No short styles | No aggressive | Abbrev: "NFM" |
| 5 | Short styles | No aggressive | Abbrev: "NFM" |
| 6 | Short styles | Aggressive | Abbrev: "NFM" |
The short_family argument to inject_suffix() is "NF" / "NFM" / "NFP" when makegroups >= 4, and "Nerd Font" / "Nerd Font Mono" / "Nerd Font Propo" otherwise (font-patcher779-782).
Sources: font-patcher597-784 bin/scripts/name_parser/FontnameParser.py83-90
The naming system also updates font metadata flags to match the generated names:
| Bit | Meaning |
|---|---|
| 0 | Bold |
| 1 | Italic |
The system sets these bits based on parsed style tokens (FontnameParser.py258-276).
Sources: bin/scripts/name_parser/FontnameParser.py251-276 bin/scripts/name_parser/FontnameParser.py382-383
After FontForge generates the font, TableHEADWriter makes low-level adjustments that FontForge cannot:
The TableHEADWriter class (font-patcher56-187) provides binary-level access to font tables:
Key operations:
find_head_table(idx) / find_table(tablenames, idx) — locate tables in single or TTC fonts (font-patcher99-137)getshort() / getlong() / putshort() / putlong() — direct byte I/O (font-patcher56-82)HEAD table flags — clears ppem_to_int bit if it was not set in source (font-patcher502-504)lowestRecPPEM from source font (font-patcher505-507)xAvgCharWidth in OS/2 table (font-patcher488-499)reset_table_checksum() / reset_full_checksum() — recalculate after modifications (font-patcher167-173)This post-generation step is required because FontForge cannot fully control certain low-level binary fields when writing font files.
Sources: font-patcher56-187 font-patcher477-519
Here's a complete transformation example showing how "Fira Code Bold Italic" becomes "Fura Code Nerd Font Mono Bold Italic":
Original font properties:
font.fontname = "FiraCode-BoldItalic"
font.fullname = "Fira Code Bold Italic"
font.familyname = "Fira Code"
basename="FiraCode", weight_token=["Bold"], style_token=["Italic"]basename="FuraCode" (Fira → Fura)" Nerd Font Mono" variant| ID | Field | Value |
|---|---|---|
| 1 | Family | Fura Code Nerd Font Mono |
| 2 | SubFamily | Bold Italic |
| 3 | UniqueID | Fura Code Nerd Font Mono Bold Italic 3.4.0 |
| 4 | Full name | Fura Code Nerd Font Mono Bold Italic |
| 6 | PostScript | FuraCodeNerdFontMono-BoldItalic |
| 16 | Preferred Family | Fura Code Nerd Font Mono |
| 17 | Preferred Styles | Bold Italic |
Sources: font-patcher523-768 bin/scripts/name_parser/FontnameParser.py323-384
The naming system integrates into the overall patching workflow:
The name generation happens after glyph patching but before font file generation (font-patcher348-424).
Sources: font-patcher348-424 font-patcher425-512 font-patcher514-768
Symptoms: Font name exceeds 31 or 63 character limits; error logged with ====-< prefix.
Solution: _make_ps_name() automatically truncates by preserving the -style suffix and shortening the family portion (bin/scripts/name_parser/FontnameParser.py27-44). Use --makegroups 3 or higher to enable aggressive shortening.
Symptoms: Bold/Italic variants appear as separate families in application font pickers.
Cause: RIBBI constraint not followed in IDs 1/2 — non-Bold weights must appear in ID 1.
Solution: family() and subfamily() enforce RIBBI automatically (bin/scripts/name_parser/FontnameParser.py216-242). Ensure makegroups > 0 so FontnameParser handles grouping.
Symptoms: License non-compliance when distributing patched fonts using original font name.
Cause: Original font name used in modified version (OFL RFN clause).
Solution: Add a regex/replacement pair to SIL_TABLE in FontnameTools (bin/scripts/name_parser/FontnameTools.py188-227). Both the FontnameParser path and the legacy reservedFontNameReplacements dict (font-patcher688-734) should be updated.
Symptoms: Mono and Propo variants have different family names or won't co-install.
Solution: Ensure --makegroups value is consistent across all variants. The inject_suffix() call uses variant_abbrev (M/P/"") to differentiate while keeping the same base family (font-patcher779-782).
Sources: bin/scripts/name_parser/FontnameParser.py27-44 bin/scripts/name_parser/FontnameParser.py216-242 bin/scripts/name_parser/FontnameTools.py188-227
The naming system behavior can be controlled through:
Command-line flags:
--makegroups N - Set naming mode (see Patching Options)--name - Override source name for parsing--has-no-italic - Handle Oblique-only fontsCode-level configuration:
name_subst table in FontnameParserSIL_TABLE in FontnameToolsreservedFontNameReplacements in font-patcherSources: font-patcher578-612 bin/scripts/name_parser/FontnameTools.py188-227 font-patcher670-715
Refresh this wiki
This wiki was recently refreshed. Please wait 3 days to refresh again.