From 7675b3869f403a61e69c12b5e8cdf9d64adc889f Mon Sep 17 00:00:00 2001 From: "github-actions[bot]" Date: Wed, 1 May 2024 00:31:17 +0000 Subject: [PATCH] chore: change batteries --- font-patcher | 117 ++++++++++++++++++++++----------- src/glyphs/original-source.otf | Bin 160668 -> 163320 bytes 2 files changed, 79 insertions(+), 38 deletions(-) diff --git a/font-patcher b/font-patcher index c2535a1..cd8dbba 100755 --- a/font-patcher +++ b/font-patcher @@ -6,7 +6,7 @@ from __future__ import absolute_import, print_function, unicode_literals # Change the script version when you edit this script: -script_version = "4.13.1" +script_version = "4.14.2" version = "3.2.1" projectName = "Nerd Fonts" @@ -320,10 +320,10 @@ def create_filename(fonts): class font_patcher: - def __init__(self, args): + def __init__(self, args, conf): self.args = args # class 'argparse.Namespace' self.sym_font_args = [] - self.config = None # class 'configparser.ConfigParser' + self.config = conf # class 'configparser.ConfigParser' self.sourceFont = None # class 'fontforge.font' self.patch_set = None # class 'list' self.font_dim = None # class 'dict' @@ -332,7 +332,6 @@ class font_patcher: self.symbolsonly = False # Are we generating the SymbolsOnly font? self.onlybitmaps = 0 self.essential = set() - self.config = configparser.ConfigParser(empty_lines_in_values=False, allow_no_value=True) self.xavgwidth = [] # list of ints def patch(self, font): @@ -340,6 +339,7 @@ class font_patcher: self.setup_version() self.assert_monospace() self.remove_ligatures() + self.manipulate_hints() self.get_essential_references() self.get_sourcefont_dimensions() self.setup_patch_set() @@ -772,21 +772,40 @@ class font_patcher: def remove_ligatures(self): # let's deal with ligatures (mostly for monospaced fonts) # Usually removes 'fi' ligs that end up being only one cell wide, and 'ldot' - if self.args.configfile and self.config.read(self.args.configfile): - if self.args.removeligatures: - logger.info("Removing ligatures from configfile `Subtables` section") - ligature_subtables = json.loads(self.config.get("Subtables", "ligatures")) - for subtable in ligature_subtables: - logger.debug("Removing subtable: %s", subtable) - try: - self.sourceFont.removeLookupSubtable(subtable) - logger.debug("Successfully removed subtable: %s", subtable) - except Exception: - logger.error("Failed to remove subtable: %s", subtable) - elif self.args.removeligatures: - logger.error("Unable to read configfile, unable to remove ligatures") + if self.args.removeligatures: + logger.info("Removing ligatures from configfile `Subtables` section") + if 'Subtables' not in self.config: + logger.warning("No ligature data (config file missing?)") + return + ligature_subtables = json.loads(self.config.get('Subtables', 'ligatures', fallback='[]')) + for subtable in ligature_subtables: + logger.debug("Removing subtable: %s", subtable) + try: + self.sourceFont.removeLookupSubtable(subtable) + logger.debug("Successfully removed subtable: %s", subtable) + except Exception: + logger.error("Failed to remove subtable: %s", subtable) + def manipulate_hints(self): + """ Redo the hinting on some problematic glyphs """ + if 'Hinting' not in self.config: + return + redo = json.loads(self.config.get('Hinting', 're_hint', fallback='[]')) + if not len(redo): + return + logger.debug("Working on {} rehinting rules (this may create a lot of fontforge warnings)".format(len(redo))) + count = 0 + for gname in self.sourceFont: + for regex in redo: + if re.fullmatch(regex, gname): + glyph = self.sourceFont[gname] + glyph.autoHint() + glyph.autoInstr() + count += 1 + break + logger.info("Rehinted {} glyphs".format(count)) + def assert_monospace(self): # Check if the sourcefont is monospaced width_mono, offending_char = is_monospaced(self.sourceFont) @@ -925,7 +944,7 @@ class font_patcher: 0xf0de: {'align': 'c', 'valign': '', 'stretch': 'pa', 'params': {}} } SYM_ATTR_HEAVYBRACKETS = { - 'default': {'align': 'c', 'valign': 'c', 'stretch': 'pa1!', 'params': {'ypadding': 0.3, 'careful': True}} + 'default': {'align': 'c', 'valign': 'c', 'stretch': '^pa1!', 'params': {'ypadding': 0.3, 'careful': True}} } SYM_ATTR_BOX = { 'default': {'align': 'c', 'valign': 'c', 'stretch': '^xy', 'params': {'overlap': 0.02, 'dont_copy': box_keep}}, @@ -1886,6 +1905,7 @@ def check_version_with_git(version): return False def setup_arguments(): + """ Parse the command line parameters and load the config file if needed """ parser = argparse.ArgumentParser( description=( 'Nerd Fonts Font Patcher: patches a given font with programming and development related glyphs\n\n' @@ -1935,7 +1955,7 @@ def setup_arguments(): expert_group = parser.add_argument_group('Expert Options') expert_group.add_argument('--boxdrawing', dest='forcebox', default=False, action='store_true', help='Force patching in (over existing) box drawing glyphs') - expert_group.add_argument('--configfile', dest='configfile', default=False, type=str, help='Specify a file path for JSON configuration file (see sample: src/config.sample.json)') + expert_group.add_argument('--configfile', dest='configfile', default=False, type=str, help='Specify a file path for configuration file (see sample: src/config.sample.cfg)') expert_group.add_argument('--custom', dest='custom', default=False, type=str, help='Specify a custom symbol font, all glyphs will be copied; absolute path suggested') expert_group.add_argument('--dry', dest='dry_run', default=False, action='store_true', help='Do neither patch nor store the font, to check naming') @@ -1946,7 +1966,7 @@ def setup_arguments(): expert_group.add_argument('--name', dest='force_name', default=None, type=str, help='Specify naming source (\'full\', \'postscript\', \'filename\', or concrete free name-string)') expert_group.add_argument('--postprocess', dest='postprocess', default=False, type=str, help='Specify a Script for Post Processing') progressbars_group_parser = expert_group.add_mutually_exclusive_group(required=False) - expert_group.add_argument('--removeligs', '--removeligatures', dest='removeligatures', default=False, action='store_true', help='Removes ligatures specificed in JSON configuration file (needs --configfile)') + expert_group.add_argument('--removeligs', '--removeligatures', dest='removeligatures', default=False, action='store_true', help='Removes ligatures specificed in configuration file (needs --configfile)') expert_group.add_argument('--xavgcharwidth', dest='xavgwidth', default=None, type=int, nargs='?', help='Adjust xAvgCharWidth (optional: concrete value)', const=True) # --xavgcharwidth for compatibility with old applications like notepad and non-latin fonts # Possible values with examples: @@ -1960,6 +1980,23 @@ def setup_arguments(): expert_group.set_defaults(progressbars=True) args = parser.parse_args() + setup_global_logger(args) + + # if we have a config file: fetch commandline arguments from there and process again with all arguments + config = configparser.ConfigParser(empty_lines_in_values=False, allow_no_value=True) + if args.configfile: + if not os.path.isfile(args.configfile): + logger.critical("Configfile does not exist: %s", args.configfile) + sys.exit(1) + if not os.access(args.configfile, os.R_OK): + logger.critical("Can not open configfile for reading: %s", args.configfile) + sys.exit(1) + config.read(args.configfile) + extraflags = config.get("Config", "commandline", fallback='') + if len(extraflags): + logger.info("Adding config commandline options: %s", extraflags) + extraflags += ' ' + args.font # Need to re-add the mandatory argument + args = parser.parse_args(extraflags.split(), args) if args.makegroups > 0 and not FontnameParserOK: logger.critical("FontnameParser module missing (bin/scripts/name_parser/Fontname*), specify --makegroups 0") @@ -2042,25 +2079,11 @@ def setup_arguments(): logger.critical("--xavgcharwidth takes only numbers up to 16384") sys.exit(2) - return args + return (args, config) -def main(): +def setup_global_logger(args): + """ Set up the logger and take options into account """ global logger - logger = logging.getLogger("start") # Use start logger until we can set up something sane - s_handler = logging.StreamHandler(stream=sys.stdout) - s_handler.setFormatter(logging.Formatter('%(levelname)s: %(message)s')) - logger.addHandler(s_handler) - - global version - git_version = check_version_with_git(version) - allversions = "Patcher v{} ({}) (ff {})".format( - git_version if git_version else version, script_version, fontforge.version()) - print("{} {}".format(projectName, allversions)) - if git_version: - version = git_version - check_fontforge_min_version() - args = setup_arguments() - logger = logging.getLogger(os.path.basename(args.font)) logger.setLevel(logging.DEBUG) log_to_file = (args.debugmode & 1 == 1) @@ -2080,9 +2103,27 @@ def main(): logger.addHandler(c_handler) if (args.debugmode & 1 == 1) and not log_to_file: logger.info("Can not write logfile, disabling") + +def main(): + global logger + logger = logging.getLogger("start") # Use start logger until we can set up something sane + s_handler = logging.StreamHandler(stream=sys.stdout) + s_handler.setFormatter(logging.Formatter('%(levelname)s: %(message)s')) + logger.addHandler(s_handler) + + global version + git_version = check_version_with_git(version) + global allversions + allversions = "Patcher v{} ({}) (ff {})".format( + git_version if git_version else version, script_version, fontforge.version()) + print("{} {}".format(projectName, allversions)) + if git_version: + version = git_version + check_fontforge_min_version() + (args, conf) = setup_arguments() logger.debug("Naming mode %d", args.makegroups) - patcher = font_patcher(args) + patcher = font_patcher(args, conf) sourceFonts = [] all_fonts = fontforge.fontsInFile(args.font) diff --git a/src/glyphs/original-source.otf b/src/glyphs/original-source.otf index 2838fa9a0838c9b67263396681a7781f0a203bc6..ad4fc801cdccd3fd04915521b7a89c9796c2e985 100644 GIT binary patch delta 4806 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 KvAS#q-~V5gGb}X# delta 2151 zcmYjP3sh9s6+P#^|3osP!8KG-5VZ;AGl*IlH5oL)1sb4*q_NhB0TKyc1r4A$Pppb! zn<%K&5gx90Ltl^v~Xd{0;No7C4QBj zF$*(t^M2~>YXP>{0)Rys3-YqzL>yVrMUR}hAS0!5$Lu8X5&;BDc2-U%AHp-Jcz6^CdMM~mU&OfgoR zBfcYMh)c!aird9~Vzqcmye2k@?c!6(LmDoPlO{+JQjGML^p2D%Et86+EmDPaQ2Ii; zAYGHbmmbR~d&m~qUk;V0$b1XVSG0DMkUBqU zNltE7#{74)(vwpb&(F-xNG)|Km10gxZfZ@XTEY5R{Bv8dpS2G4Oa9KQ_5@4(67aIy$a{T|K)!39sa z@H$*sV;0hwJ0u##it!Gu&=~<^X6J3HSVx=^wu2cy%l{{;>aBIYr?Um7`PLy$8h3m zv<<>3Mfmb=wA(OZJx26kt^UCc?xyrWnkU_m-A>&C*h zsMllBLtGPpYx=MxA2%GrGEdw-4|mA8`!rVgVMRRdFUI|k&{5Tb2mgSz|G*=c@iSli zYY5h5;}sKLGvoEG_|FUYZ7|;Y0Gq$SmeF{3B0kuLZ5jBe4IiJ!CzG-79zM-y7|z6( zn7oP&I>bEIGmj2tHZgNE8~hy`-opIWv2pj<&knP|4i4gH>;+~E6>Nl;x;+Cu&ToD#rgf~cFsG~2s-=-Tt}WUx3!u=d}+B_6{M~b^e(^tCoP;mlz0yKm5+Xh64^t zxQ+nle@}9{1tZd#rVo^mMQf^7-6aYKDVi!e{0zCnPdC<7>}KXhC+E)9z#*iZG-Eit zvW!?~I%!fA_3y8C)w=8S5|x8vLW^DIFshEiQZ(tK>f9zRN7c~~$X#GKQBH#a2UD5B z5($irfX%88FzQ2To7L?A2d@{O%`=i@kuVTl(MilyX6KM!<)Em$=Za2!z>YSP=AIZk z$E^`Wo9!y~a2L4;Q%(PxenY@7K^ZXJ2Td{Ey{7Z%OmosH6xfZkrnX}h(wwWQqq$Kx z4t6NDp%)3puQ$p|)S9$uC4UKjK?j!?T?$_v+(0>^UGcr~UG$~?w+4*=V@5)%iD{dW3eKcvZhuiOL9In@x@Da{P_)Y#qs z)@~7f=TPv?5MAP+&7+X(qLYJV6N!Chy@Wm-e)2$fa9~+vm;z|DR8IE?N9Pee;N|4J zG7&iTh1wnH}=T4}jXu!q*wVHDi$a#BsF2hpMVlx*`S zhd;LWYrOR%qvq;Ko%5ibCQ?6KM9F52_R4#FslA#