mirror of
https://github.com/daylinmorgan/monolisa-nerdfont-patch.git
synced 2024-12-22 06:50:44 -06:00
chore: change batteries
This commit is contained in:
parent
a4d4640f01
commit
d8c928efe8
3 changed files with 47 additions and 56 deletions
|
@ -7,8 +7,8 @@ from FontnameTools import FontnameTools
|
||||||
class FontnameParser:
|
class FontnameParser:
|
||||||
"""Parse a font name and generate all kinds of names"""
|
"""Parse a font name and generate all kinds of names"""
|
||||||
|
|
||||||
def __init__(self, filename, logger):
|
def __init__(self, fontname, logger):
|
||||||
"""Parse a font filename and store the results"""
|
"""Parse a fontname and store the results"""
|
||||||
self.parse_ok = False
|
self.parse_ok = False
|
||||||
self.use_short_families = (False, False, False) # ( camelcase name, short styles, aggressive )
|
self.use_short_families = (False, False, False) # ( camelcase name, short styles, aggressive )
|
||||||
self.keep_regular_in_family = None # None = auto, True, False
|
self.keep_regular_in_family = None # None = auto, True, False
|
||||||
|
@ -17,7 +17,7 @@ class FontnameParser:
|
||||||
self.ps_fontname_suff = ''
|
self.ps_fontname_suff = ''
|
||||||
self.short_family_suff = ''
|
self.short_family_suff = ''
|
||||||
self.name_subst = []
|
self.name_subst = []
|
||||||
[ self.parse_ok, self._basename, self.weight_token, self.style_token, self.other_token, self._rest ] = FontnameTools.parse_font_name(filename)
|
[ self.parse_ok, self._basename, self.weight_token, self.style_token, self.other_token, self._rest ] = FontnameTools.parse_font_name(fontname)
|
||||||
self.basename = self._basename
|
self.basename = self._basename
|
||||||
self.rest = self._rest
|
self.rest = self._rest
|
||||||
self.add_name_substitution_table(FontnameTools.SIL_TABLE)
|
self.add_name_substitution_table(FontnameTools.SIL_TABLE)
|
||||||
|
@ -252,6 +252,9 @@ class FontnameParser:
|
||||||
# Ignore Italic if we have Oblique
|
# Ignore Italic if we have Oblique
|
||||||
if 'Oblique' in self.weight_token:
|
if 'Oblique' in self.weight_token:
|
||||||
b |= OBLIQUE
|
b |= OBLIQUE
|
||||||
|
if not self.rename_oblique:
|
||||||
|
# If we have no dedicated italic, than oblique = italic
|
||||||
|
b |= ITALIC
|
||||||
elif 'Italic' in self.style_token:
|
elif 'Italic' in self.style_token:
|
||||||
b |= ITALIC
|
b |= ITALIC
|
||||||
# Regular is just the basic weight
|
# Regular is just the basic weight
|
||||||
|
|
|
@ -5,7 +5,7 @@ import re
|
||||||
import sys
|
import sys
|
||||||
|
|
||||||
class FontnameTools:
|
class FontnameTools:
|
||||||
"""Deconstruct a font filename to get standardized name parts"""
|
"""Deconstruct a fontname to get standardized name parts"""
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def front_upper(word):
|
def front_upper(word):
|
||||||
|
@ -64,24 +64,11 @@ class FontnameTools:
|
||||||
known_names = {
|
known_names = {
|
||||||
# Source of the table is the current sourcefonts
|
# Source of the table is the current sourcefonts
|
||||||
# Left side needs to be lower case
|
# Left side needs to be lower case
|
||||||
'-': '',
|
|
||||||
'book': '',
|
'book': '',
|
||||||
'text': '',
|
|
||||||
'ce': 'CE',
|
'ce': 'CE',
|
||||||
#'semibold': 'Demi',
|
|
||||||
'ob': 'Oblique',
|
|
||||||
'it': 'Italic',
|
|
||||||
'i': 'Italic',
|
|
||||||
'b': 'Bold',
|
|
||||||
'normal': 'Regular',
|
'normal': 'Regular',
|
||||||
'c': 'Condensed',
|
|
||||||
'r': 'Regular',
|
|
||||||
'm': 'Medium',
|
|
||||||
'l': 'Light',
|
|
||||||
}
|
}
|
||||||
if style_name in known_names:
|
return known_names.get(style_name.lower(), style_name)
|
||||||
return known_names[style_name.lower()]
|
|
||||||
return style_name
|
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def find_in_dicts(key, dicts):
|
def find_in_dicts(key, dicts):
|
||||||
|
@ -146,7 +133,7 @@ class FontnameTools:
|
||||||
return (weights, styles)
|
return (weights, styles)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def get_name_token(name, tokens, allow_regex_token = False):
|
def get_name_token(name, tokens):
|
||||||
"""Try to find any case insensitive token from tokens in the name, return tuple with found token-list and rest"""
|
"""Try to find any case insensitive token from tokens in the name, return tuple with found token-list and rest"""
|
||||||
# The default mode (allow_regex_token = False) will try to find any verbatim string in the
|
# The default mode (allow_regex_token = False) will try to find any verbatim string in the
|
||||||
# tokens list (case insensitive matching) and give that tokens list item back with
|
# tokens list (case insensitive matching) and give that tokens list item back with
|
||||||
|
@ -160,7 +147,11 @@ class FontnameTools:
|
||||||
not_matched = ""
|
not_matched = ""
|
||||||
all_tokens = []
|
all_tokens = []
|
||||||
j = 1
|
j = 1
|
||||||
regex = re.compile('(.*?)(' + '|'.join(tokens) + ')(.*)', re.IGNORECASE)
|
token_regex = '|'.join(tokens)
|
||||||
|
# Allow a dash between CamelCase token word parts, i.e. Camel-Case
|
||||||
|
# This allows for styles like Extra-Bold
|
||||||
|
token_regex = re.sub(r'(?<=[a-z])(?=[A-Z])', '-?', token_regex)
|
||||||
|
regex = re.compile('(.*?)(' + token_regex + ')(.*)', re.IGNORECASE)
|
||||||
while j:
|
while j:
|
||||||
j = regex.match(name)
|
j = regex.match(name)
|
||||||
if not j:
|
if not j:
|
||||||
|
@ -169,6 +160,7 @@ class FontnameTools:
|
||||||
sys.exit('Malformed regex in FontnameTools.get_name_token()')
|
sys.exit('Malformed regex in FontnameTools.get_name_token()')
|
||||||
not_matched += ' ' + j.groups()[0] # Blanc prevents unwanted concatenation of unmatched substrings
|
not_matched += ' ' + j.groups()[0] # Blanc prevents unwanted concatenation of unmatched substrings
|
||||||
tok = j.groups()[1].lower()
|
tok = j.groups()[1].lower()
|
||||||
|
tok = tok.replace('-', '') # Remove dashes between CamelCase token words
|
||||||
if tok in lower_tokens:
|
if tok in lower_tokens:
|
||||||
tok = tokens[lower_tokens.index(tok)]
|
tok = tokens[lower_tokens.index(tok)]
|
||||||
tok = FontnameTools.unify_style_names(tok)
|
tok = FontnameTools.unify_style_names(tok)
|
||||||
|
@ -238,6 +230,7 @@ class FontnameTools:
|
||||||
'Medium': ('Md', 'Med'),
|
'Medium': ('Md', 'Med'),
|
||||||
'Nord': ('Nd', 'Nord'),
|
'Nord': ('Nd', 'Nord'),
|
||||||
'Book': ('Bk', 'Book'),
|
'Book': ('Bk', 'Book'),
|
||||||
|
'Text': ('Txt', 'Text'),
|
||||||
'Poster': ('Po', 'Poster'),
|
'Poster': ('Po', 'Poster'),
|
||||||
'Demi': ('Dm', 'Demi'), # Demi is sometimes used as a weight, sometimes as a modifier
|
'Demi': ('Dm', 'Demi'), # Demi is sometimes used as a weight, sometimes as a modifier
|
||||||
'Regular': ('Rg', 'Reg'),
|
'Regular': ('Rg', 'Reg'),
|
||||||
|
@ -306,8 +299,9 @@ class FontnameTools:
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def _parse_simple_font_name(name):
|
def _parse_simple_font_name(name):
|
||||||
"""Parse a filename that does not follow the 'FontFamilyName-FontStyle' pattern"""
|
"""Parse a fontname that does not follow the 'FontFamilyName-FontStyle' pattern"""
|
||||||
# No dash in name, maybe we have blanc separated filename?
|
# This is the usual case, because the font-patcher usually uses the fullname and
|
||||||
|
# not the PS name
|
||||||
if ' ' in name:
|
if ' ' in name:
|
||||||
return FontnameTools.parse_font_name(name.replace(' ', '-'))
|
return FontnameTools.parse_font_name(name.replace(' ', '-'))
|
||||||
# Do we have a number-name boundary?
|
# Do we have a number-name boundary?
|
||||||
|
@ -322,8 +316,15 @@ class FontnameTools:
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def parse_font_name(name):
|
def parse_font_name(name):
|
||||||
"""Expects a filename following the 'FontFamilyName-FontStyle' pattern and returns ... parts"""
|
"""Expects a fontname following the 'FontFamilyName-FontStyle' pattern and returns ... parts"""
|
||||||
name = re.sub(r'\bsemi-condensed\b', 'SemiCondensed', name, 1, re.IGNORECASE) # Just for "3270 Semi-Condensed" :-/
|
# This could parse filenames in the beginning but that was never used in production; code removed with this commit
|
||||||
|
for special in [
|
||||||
|
('ExtLt', 'ExtraLight'), # IBM-Plex
|
||||||
|
('Medm', 'Medium'), # IBM-Plex
|
||||||
|
('Semi-Condensed', 'SemiCondensed'), # 3270
|
||||||
|
('SmBld', 'SemiBold'), # IBM-Plex
|
||||||
|
]:
|
||||||
|
name = re.sub(r'\b' + special[0] + r'\b', special[1], name, 1, re.IGNORECASE)
|
||||||
name = re.sub('[_\s]+', ' ', name)
|
name = re.sub('[_\s]+', ' ', name)
|
||||||
matches = re.match(r'([^-]+)(?:-(.*))?', name)
|
matches = re.match(r'([^-]+)(?:-(.*))?', name)
|
||||||
familyname = FontnameTools.camel_casify(matches.group(1))
|
familyname = FontnameTools.camel_casify(matches.group(1))
|
||||||
|
@ -345,7 +346,6 @@ class FontnameTools:
|
||||||
# Some font specialities:
|
# Some font specialities:
|
||||||
other = [
|
other = [
|
||||||
'-', 'Book', 'For', 'Powerline',
|
'-', 'Book', 'For', 'Powerline',
|
||||||
'Text', # Plex
|
|
||||||
'IIx', # Profont IIx
|
'IIx', # Profont IIx
|
||||||
'LGC', # Inconsolata LGC
|
'LGC', # Inconsolata LGC
|
||||||
r'\bCE\b', # ProggycleanTT CE
|
r'\bCE\b', # ProggycleanTT CE
|
||||||
|
@ -353,19 +353,9 @@ class FontnameTools:
|
||||||
r'(?:uni-)?1[14]', # GohuFont uni
|
r'(?:uni-)?1[14]', # GohuFont uni
|
||||||
]
|
]
|
||||||
|
|
||||||
# Sometimes used abbreviations
|
|
||||||
weight_abbrevs = [ 'ob', 'c', 'm', 'l', ]
|
|
||||||
style_abbrevs = [ 'it', 'r', 'b', 'i', ]
|
|
||||||
|
|
||||||
( style, weight_token ) = FontnameTools.get_name_token(style, weights)
|
( style, weight_token ) = FontnameTools.get_name_token(style, weights)
|
||||||
( style, style_token ) = FontnameTools.get_name_token(style, styles)
|
( style, style_token ) = FontnameTools.get_name_token(style, styles)
|
||||||
( style, other_token ) = FontnameTools.get_name_token(style, other, True)
|
( style, other_token ) = FontnameTools.get_name_token(style, other)
|
||||||
if (len(style) < 4
|
|
||||||
and style.lower() != 'pro'): # Prevent 'r' of Pro to be detected as style_abbrev
|
|
||||||
( style, weight_token_abbrevs ) = FontnameTools.get_name_token(style, weight_abbrevs)
|
|
||||||
( style, style_token_abbrevs ) = FontnameTools.get_name_token(style, style_abbrevs)
|
|
||||||
weight_token += weight_token_abbrevs
|
|
||||||
style_token += style_token_abbrevs
|
|
||||||
while 'Regular' in style_token and len(style_token) > 1:
|
while 'Regular' in style_token and len(style_token) > 1:
|
||||||
# Correct situation where "Regular" and something else is given
|
# Correct situation where "Regular" and something else is given
|
||||||
style_token.remove('Regular')
|
style_token.remove('Regular')
|
||||||
|
|
38
font-patcher
38
font-patcher
|
@ -6,7 +6,7 @@
|
||||||
from __future__ import absolute_import, print_function, unicode_literals
|
from __future__ import absolute_import, print_function, unicode_literals
|
||||||
|
|
||||||
# Change the script version when you edit this script:
|
# Change the script version when you edit this script:
|
||||||
script_version = "4.3.1"
|
script_version = "4.3.4"
|
||||||
|
|
||||||
version = "3.0.1"
|
version = "3.0.1"
|
||||||
projectName = "Nerd Fonts"
|
projectName = "Nerd Fonts"
|
||||||
|
@ -250,11 +250,11 @@ def force_panose_monospaced(font):
|
||||||
def get_advance_width(font, extended, minimum):
|
def get_advance_width(font, extended, minimum):
|
||||||
""" Get the maximum/minimum advance width in the extended(?) range """
|
""" Get the maximum/minimum advance width in the extended(?) range """
|
||||||
width = 0
|
width = 0
|
||||||
if extended:
|
if not extended:
|
||||||
end = 0x17f
|
r = range(0x021, 0x07e)
|
||||||
else:
|
else:
|
||||||
end = 0x07e
|
r = range(0x07f, 0x17f)
|
||||||
for glyph in range(0x21, end):
|
for glyph in r:
|
||||||
if not glyph in font:
|
if not glyph in font:
|
||||||
continue
|
continue
|
||||||
if glyph in range(0x7F, 0xBF):
|
if glyph in range(0x7F, 0xBF):
|
||||||
|
@ -270,8 +270,8 @@ def get_advance_width(font, extended, minimum):
|
||||||
|
|
||||||
def report_advance_widths(font):
|
def report_advance_widths(font):
|
||||||
return "Advance widths (base/extended): {} - {} / {} - {}".format(
|
return "Advance widths (base/extended): {} - {} / {} - {}".format(
|
||||||
get_advance_width(font, True, True), get_advance_width(font, False, True),
|
get_advance_width(font, False, True), get_advance_width(font, False, False),
|
||||||
get_advance_width(font, False, False), get_advance_width(font, True, False))
|
get_advance_width(font, True, True), get_advance_width(font, True, False))
|
||||||
|
|
||||||
def get_btb_metrics(font):
|
def get_btb_metrics(font):
|
||||||
""" Get the baseline to baseline distance for all three metrics """
|
""" Get the baseline to baseline distance for all three metrics """
|
||||||
|
@ -765,16 +765,18 @@ class font_patcher:
|
||||||
if self.args.nonmono:
|
if self.args.nonmono:
|
||||||
return
|
return
|
||||||
panose_mono = check_panose_monospaced(self.sourceFont)
|
panose_mono = check_panose_monospaced(self.sourceFont)
|
||||||
|
logger.debug("Monospace check: %s; glyph-width-mono %s",
|
||||||
|
panose_check_to_text(panose_mono, self.sourceFont.os2_panose), repr(width_mono))
|
||||||
# The following is in fact "width_mono != panose_mono", but only if panose_mono is not 'unknown'
|
# The following is in fact "width_mono != panose_mono", but only if panose_mono is not 'unknown'
|
||||||
if (width_mono and panose_mono == 0) or (not width_mono and panose_mono == 1):
|
if (width_mono and panose_mono == 0) or (not width_mono and panose_mono == 1):
|
||||||
logger.warning("Monospaced check: Panose assumed to be wrong")
|
logger.warning("Monospaced check: Panose assumed to be wrong")
|
||||||
logger.warning(" %s and %s",
|
logger.warning("Monospaced check: %s and %s",
|
||||||
report_advance_widths(self.sourceFont),
|
report_advance_widths(self.sourceFont),
|
||||||
panose_check_to_text(panose_mono, self.sourceFont.os2_panose))
|
panose_check_to_text(panose_mono, self.sourceFont.os2_panose))
|
||||||
if self.args.single and not width_mono:
|
if self.args.single and not width_mono:
|
||||||
logger.warning("Sourcefont is not monospaced - forcing to monospace not advisable, results might be useless")
|
logger.warning("Sourcefont is not monospaced - forcing to monospace not advisable, "
|
||||||
if offending_char is not None:
|
"results might be useless%s",
|
||||||
logger.warning(" Offending char: %X", offending_char)
|
" - offending char: {:X}".format(offending_char) if offending_char is not None else "")
|
||||||
if self.args.single <= 1:
|
if self.args.single <= 1:
|
||||||
logger.critical("Font will not be patched! Give --mono (or -s, or --use-single-width-glyphs) twice to force patching")
|
logger.critical("Font will not be patched! Give --mono (or -s, or --use-single-width-glyphs) twice to force patching")
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
@ -920,6 +922,7 @@ class font_patcher:
|
||||||
# with the same scaling and shifting. The basis for it is a 'combined
|
# with the same scaling and shifting. The basis for it is a 'combined
|
||||||
# bounding box' of all glyphs in that group. All glyphs are handled as
|
# bounding box' of all glyphs in that group. All glyphs are handled as
|
||||||
# if they fill that combined bounding box.
|
# if they fill that combined bounding box.
|
||||||
|
# (- ScaleGroupsVert: Removed with this commit)
|
||||||
#
|
#
|
||||||
# The ScaleGlyph method: You set 'ScaleGlyph' to the unicode of the reference glyph.
|
# The ScaleGlyph method: You set 'ScaleGlyph' to the unicode of the reference glyph.
|
||||||
# Note that there can be only one per patch-set.
|
# Note that there can be only one per patch-set.
|
||||||
|
@ -955,14 +958,8 @@ class font_patcher:
|
||||||
range(0x2594, 0x259f + 1), # quards (Note: quard 2597 in Hack is wrong, scales like block!)
|
range(0x2594, 0x259f + 1), # quards (Note: quard 2597 in Hack is wrong, scales like block!)
|
||||||
]}
|
]}
|
||||||
CODI_SCALE_LIST = {'ScaleGroups': [
|
CODI_SCALE_LIST = {'ScaleGroups': [
|
||||||
range(0xea99, 0xeaa1 + 1), # arrows
|
|
||||||
range(0xeb6e, 0xeb71 + 1), # triangles
|
range(0xeb6e, 0xeb71 + 1), # triangles
|
||||||
range(0xeab4, 0xeab7 + 1), # chevrons
|
range(0xeab4, 0xeab7 + 1), # chevrons
|
||||||
[0xea71, *range(0xeaa6, 0xeaab + 1), 0xeabc, 0xeb18, 0xeb87, 0xeb88, 0xeb8a, 0xeb8c, 0xebb4], # cicles
|
|
||||||
[0xeacc, 0xeaba], # dash
|
|
||||||
[0xea75, 0xebe7], # lock pair
|
|
||||||
[0xeacf, 0xebe0], # debug-continue pair
|
|
||||||
[0xeb91, 0xeba8], # debug-alt pair
|
|
||||||
]}
|
]}
|
||||||
DEVI_SCALE_LIST = {'ScaleGlyph': 0xE60E, # Android logo
|
DEVI_SCALE_LIST = {'ScaleGlyph': 0xE60E, # Android logo
|
||||||
'GlyphsToScale': [
|
'GlyphsToScale': [
|
||||||
|
@ -1205,6 +1202,7 @@ class font_patcher:
|
||||||
0x132, 0x133, # IJ, ij (in Overpass Mono)
|
0x132, 0x133, # IJ, ij (in Overpass Mono)
|
||||||
0x022, 0x027, 0x060, # Single and double quotes in Inconsolata LGC
|
0x022, 0x027, 0x060, # Single and double quotes in Inconsolata LGC
|
||||||
0x0D0, 0x10F, 0x110, 0x111, 0x127, 0x13E, 0x140, 0x165, # Eth and others with stroke or caron in RobotoMono
|
0x0D0, 0x10F, 0x110, 0x111, 0x127, 0x13E, 0x140, 0x165, # Eth and others with stroke or caron in RobotoMono
|
||||||
|
0x149, # napostrophe in DaddyTimeMono
|
||||||
0x02D, # hyphen for Monofur
|
0x02D, # hyphen for Monofur
|
||||||
]:
|
]:
|
||||||
continue # ignore special characters like '1/4' etc and some specifics
|
continue # ignore special characters like '1/4' etc and some specifics
|
||||||
|
@ -1216,8 +1214,8 @@ class font_patcher:
|
||||||
if self.font_dim['width'] < self.sourceFont[glyph].width:
|
if self.font_dim['width'] < self.sourceFont[glyph].width:
|
||||||
self.font_dim['width'] = self.sourceFont[glyph].width
|
self.font_dim['width'] = self.sourceFont[glyph].width
|
||||||
if not warned1 and glyph > 0x7a: # NOT 'basic' glyph, which includes a-zA-Z
|
if not warned1 and glyph > 0x7a: # NOT 'basic' glyph, which includes a-zA-Z
|
||||||
logger.debug("Extended glyphs wider than basic glyphs, results might be useless\n %s",
|
logger.debug("Extended glyphs wider than basic glyphs, results might be useless")
|
||||||
report_advance_widths(self.sourceFont))
|
logger.debug("%s", report_advance_widths(self.sourceFont))
|
||||||
warned1 = True
|
warned1 = True
|
||||||
# print("New MAXWIDTH-A {:X} {} -> {} {}".format(glyph, self.sourceFont[glyph].width, self.font_dim['width'], xmax))
|
# print("New MAXWIDTH-A {:X} {} -> {} {}".format(glyph, self.sourceFont[glyph].width, self.font_dim['width'], xmax))
|
||||||
if xmax > self.font_dim['xmax']:
|
if xmax > self.font_dim['xmax']:
|
||||||
|
@ -1229,7 +1227,7 @@ class font_patcher:
|
||||||
if self.font_dim['width'] < self.font_dim['xmax']:
|
if self.font_dim['width'] < self.font_dim['xmax']:
|
||||||
logger.debug("Font has negative right side bearing in extended glyphs")
|
logger.debug("Font has negative right side bearing in extended glyphs")
|
||||||
self.font_dim['xmax'] = self.font_dim['width'] # In fact 'xmax' is never used
|
self.font_dim['xmax'] = self.font_dim['width'] # In fact 'xmax' is never used
|
||||||
# print("FINAL", self.font_dim)
|
logger.debug("Final font cell dimensions %d w x %d h", self.font_dim['width'], self.font_dim['height'])
|
||||||
|
|
||||||
self.xavgwidth.append(self.args.xavgwidth)
|
self.xavgwidth.append(self.args.xavgwidth)
|
||||||
if isinstance(self.xavgwidth[-1], int) and self.xavgwidth[-1] == 0:
|
if isinstance(self.xavgwidth[-1], int) and self.xavgwidth[-1] == 0:
|
||||||
|
|
Loading…
Reference in a new issue