From fc77ba17939cc4409a9592750eb94e4068e6189a Mon Sep 17 00:00:00 2001 From: arrowtype Date: Sat, 16 May 2020 20:25:58 -0400 Subject: [PATCH] formatting code --- .vscode/settings.json | 25 +- .../Recursive_Code/README.md | 7 +- .../make-release/instantiate-code-fonts.py | 568 +++++++++--------- 3 files changed, 318 insertions(+), 282 deletions(-) diff --git a/.vscode/settings.json b/.vscode/settings.json index 47ae993288..30dd0ed6c2 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -1,10 +1,19 @@ { - "python.pythonPath": "/Users/stephennixon/type-repos/recursive/venv/bin/python", - "git.ignoreLimitWarning": true, - "[markdown]": { - "editor.formatOnSave": false, - "editor.wordWrap": "on", - "editor.renderWhitespace": "all", - "editor.acceptSuggestionOnEnter": "on" - } + "python.pythonPath": "/Users/stephennixon/type-repos/recursive/venv/bin/python", + "git.ignoreLimitWarning": true, + "[markdown]": { + "editor.formatOnSave": false, + "editor.wordWrap": "on", + "editor.renderWhitespace": "all", + "editor.acceptSuggestionOnEnter": "on" + }, + "python.linting.pylintEnabled": false, + "python.linting.flake8Enabled": true, + "python.linting.enabled": true, + "python.linting.flake8Args": ["--ignore=E203, E501, W503", "--max-line-length=100"], + "editor.formatOnSave": true, + "python.formatting.autopep8Args": ["--ignore W191"], + "python.formatting.blackArgs": ["--line-length=100"], + "python.formatting.provider": "yapf", + "python.formatting.yapfArgs": ["column_limit=100"] } diff --git a/fonts/Recursive-Beta_1.051/Recursive_Code/README.md b/fonts/Recursive-Beta_1.051/Recursive_Code/README.md index 1dd8670bc2..dc0464ea2e 100644 --- a/fonts/Recursive-Beta_1.051/Recursive_Code/README.md +++ b/fonts/Recursive-Beta_1.051/Recursive_Code/README.md @@ -1,28 +1,31 @@ # Rec Mono for Code Custom 4-style packages specifically made for code editors, each featuring: + - Regular, Italic, Bold, & Bold Italic static fonts - An abbreviated family name to enable italic themes on macOS - Reduced-slant italics for easier readability in code (normal Recursive Italics have slnt=-15, which is pretty intense) - All the same OpenType features that are available in Recursive generally, including `ss01`-`ss11` to customize letterforms to your preference. - ## Packages Download the zip in this folder for an easy way to download these fonts. Then, install the fonts then call them from your favorite code editor with their relevant family name, e.g. `Rec Mono Duotone`. **`Rec Mono Linear`** + - Everyday workhorse for code. Simplified shapes meant to help enhance focus in complex code. **`Rec Mono Casual`** + - A party in a font. Fun & wacky shapes, simplified enough for small sizes but curvy enough to have plenty of character. Best in casual coding & non-primary terminals. **`Rec Mono SemiCasual`** + - Sets the CASL axis at `0.5` for font that is serious but softened a little bit. This isn't the best choice for text at large sizes (like headlines on a website), but can be a really nice balance in code. **`Rec Mono Duotone`** -- A personal favorite – this uses Linear styles for upright text and Casual styles for italic text. In many themes that use italic styles, this will give most code a utilitarian look, but set comments and some keywords in a more-handwritten style. +- A personal favorite – this uses Linear styles for upright text and Casual styles for italic text. In many themes that use italic styles, this will give most code a utilitarian look, but set comments and some keywords in a more-handwritten style. ## Code Ligatures diff --git a/src/build-scripts/make-release/instantiate-code-fonts.py b/src/build-scripts/make-release/instantiate-code-fonts.py index 766c574559..012c37610f 100644 --- a/src/build-scripts/make-release/instantiate-code-fonts.py +++ b/src/build-scripts/make-release/instantiate-code-fonts.py @@ -1,23 +1,23 @@ """ - A script to generate Recursive fonts for code with: - - An abbreviated family name to avoid macOS style-linking bug - - Rec Mono - - A reduced italic slant (probably -10 degrees) - - The following static instances: - - Linear - - Linear Italic - - Linear Bold - - Linear Bold Italic - - Casual - - Casual Italic - - Casual Bold - - Casual Bold Italic - - USAGE: - - python /instantiate-code-fonts.py - - NOTE: assumes it will act on the Recursive variable font as of e84015de. + A script to generate Recursive fonts for code with: + - An abbreviated family name to avoid macOS style-linking bug + - Rec Mono + - A reduced italic slant (probably -10 degrees) + - The following static instances: + - Linear + - Linear Italic + - Linear Bold + - Linear Bold Italic + - Casual + - Casual Italic + - Casual Bold + - Casual Bold Italic + + USAGE: + + python /instantiate-code-fonts.py + + NOTE: assumes it will act on the Recursive variable font as of e84015de. """ import os @@ -27,181 +27,180 @@ from opentype_feature_freezer import cli as pyftfeatfreeze import subprocess import shutil -import glob import fire from dlig2calt import dlig2calt - # instances to split instanceValues = { - # Linear package - 'Linear': { - 'Linear': { - 'MONO': 1, - 'CASL': 0, - 'wght': 400, - 'slnt': 0, - 'CRSV': 0, - 'style': 'Regular' - }, - 'Linear Italic': { - 'MONO': 1, - 'CASL': 0, - 'wght': 400, - 'slnt': -10, - 'CRSV': 1, - 'style': 'Italic' - }, - 'Linear Bold': { - 'MONO': 1, - 'CASL': 0, - 'wght': 700, - 'slnt': 0, - 'CRSV': 0, - 'style': 'Bold' - }, - 'Linear Bold Italic': { - 'MONO': 1, - 'CASL': 0, - 'wght': 700, - 'slnt': -10, - 'CRSV': 1, - 'style': 'Bold Italic' - }, - }, - # Casual package - 'Casual': { - 'Casual': { - 'MONO': 1, - 'CASL': 1, - 'wght': 400, - 'slnt': 0, - 'CRSV': 0, - 'style': 'Regular' - }, - 'Casual Italic': { - 'MONO': 1, - 'CASL': 1, - 'wght': 400, - 'slnt': -10, - 'CRSV': 1, - 'style': 'Italic' - }, - 'Casual Bold': { - 'MONO': 1, - 'CASL': 1, - 'wght': 700, - 'slnt': 0, - 'CRSV': 0, - 'style': 'Bold' - }, - 'Casual Bold Italic': { - 'MONO': 1, - 'CASL': 1, - 'wght': 700, - 'slnt': -10, - 'CRSV': 1, - 'style': 'Bold Italic' - }, - }, - # SemiCasual package - 'SemiCasual': { - 'SemiCasual': { - 'MONO': 1, - 'CASL': 0.5, - 'wght': 400, - 'slnt': 0, - 'CRSV': 0, - 'style': 'Regular' - }, - 'SemiCasual Italic': { - 'MONO': 1, - 'CASL': 0.5, - 'wght': 400, - 'slnt': -10, - 'CRSV': 1, - 'style': 'Italic' - }, - 'SemiCasual Bold': { - 'MONO': 1, - 'CASL': 0.5, - 'wght': 700, - 'slnt': 0, - 'CRSV': 0, - 'style': 'Bold' - }, - 'SemiCasual Bold Italic': { - 'MONO': 1, - 'CASL': 0.5, - 'wght': 700, - 'slnt': -10, - 'CRSV': 1, - 'style': 'Bold Italic' - }, - }, - # Duotone package - 'Duotone': { - 'Duotone': { - 'MONO': 1, - 'CASL': 0, - 'wght': 400, - 'slnt': 0, - 'CRSV': 0, - 'style': 'Regular' - }, - 'Duotone Italic': { - 'MONO': 1, - 'CASL': 1, - 'wght': 400, - 'slnt': -10, - 'CRSV': 1, - 'style': 'Italic' - }, - 'Duotone Bold': { - 'MONO': 1, - 'CASL': 0, - 'wght': 700, - 'slnt': 0, - 'CRSV': 0, - 'style': 'Bold' - }, - 'Duotone Bold Italic': { - 'MONO': 1, - 'CASL': 1, - 'wght': 700, - 'slnt': -10, - 'CRSV': 1, - 'style': 'Bold Italic' - } - }, + # Linear package + "Linear": { + "Linear": { + "MONO": 1, + "CASL": 0, + "wght": 400, + "slnt": 0, + "CRSV": 0, + "style": "Regular", + }, + "Linear Italic": { + "MONO": 1, + "CASL": 0, + "wght": 400, + "slnt": -10, + "CRSV": 1, + "style": "Italic", + }, + "Linear Bold": { + "MONO": 1, + "CASL": 0, + "wght": 700, + "slnt": 0, + "CRSV": 0, + "style": "Bold", + }, + "Linear Bold Italic": { + "MONO": 1, + "CASL": 0, + "wght": 700, + "slnt": -10, + "CRSV": 1, + "style": "Bold Italic", + }, + }, + # Casual package + "Casual": { + "Casual": { + "MONO": 1, + "CASL": 1, + "wght": 400, + "slnt": 0, + "CRSV": 0, + "style": "Regular", + }, + "Casual Italic": { + "MONO": 1, + "CASL": 1, + "wght": 400, + "slnt": -10, + "CRSV": 1, + "style": "Italic", + }, + "Casual Bold": { + "MONO": 1, + "CASL": 1, + "wght": 700, + "slnt": 0, + "CRSV": 0, + "style": "Bold", + }, + "Casual Bold Italic": { + "MONO": 1, + "CASL": 1, + "wght": 700, + "slnt": -10, + "CRSV": 1, + "style": "Bold Italic", + }, + }, + # SemiCasual package + "SemiCasual": { + "SemiCasual": { + "MONO": 1, + "CASL": 0.5, + "wght": 400, + "slnt": 0, + "CRSV": 0, + "style": "Regular", + }, + "SemiCasual Italic": { + "MONO": 1, + "CASL": 0.5, + "wght": 400, + "slnt": -10, + "CRSV": 1, + "style": "Italic", + }, + "SemiCasual Bold": { + "MONO": 1, + "CASL": 0.5, + "wght": 700, + "slnt": 0, + "CRSV": 0, + "style": "Bold", + }, + "SemiCasual Bold Italic": { + "MONO": 1, + "CASL": 0.5, + "wght": 700, + "slnt": -10, + "CRSV": 1, + "style": "Bold Italic", + }, + }, + # Duotone package + "Duotone": { + "Duotone": { + "MONO": 1, + "CASL": 0, + "wght": 400, + "slnt": 0, + "CRSV": 0, + "style": "Regular", + }, + "Duotone Italic": { + "MONO": 1, + "CASL": 1, + "wght": 400, + "slnt": -10, + "CRSV": 1, + "style": "Italic", + }, + "Duotone Bold": { + "MONO": 1, + "CASL": 0, + "wght": 700, + "slnt": 0, + "CRSV": 0, + "style": "Bold", + }, + "Duotone Bold Italic": { + "MONO": 1, + "CASL": 1, + "wght": 700, + "slnt": -10, + "CRSV": 1, + "style": "Bold Italic", + }, + }, } - # GET / SET NAME HELPER FUNCTIONS + def getFontNameID(font, ID, platformID=3, platEncID=1): - name = str(font['name'].getName(ID, platformID, platEncID)) - return name + name = str(font["name"].getName(ID, platformID, platEncID)) + return name + def setFontNameID(font, ID, newName): - - print(f"\n\t• name {ID}:") - macIDs = {"platformID": 3, "platEncID": 1, "langID": 0x409} - winIDs = {"platformID": 1, "platEncID": 0, "langID": 0x0} - oldMacName = font['name'].getName(ID, *macIDs.values()) - oldWinName = font['name'].getName(ID, *winIDs.values()) + print(f"\n\t• name {ID}:") + macIDs = {"platformID": 3, "platEncID": 1, "langID": 0x409} + winIDs = {"platformID": 1, "platEncID": 0, "langID": 0x0} - if oldMacName != newName: - print(f"\n\t\t Mac name was '{oldMacName}'") - font['name'].setName(newName, ID, *macIDs.values()) - print(f"\n\t\t Mac name now '{newName}'") + oldMacName = font["name"].getName(ID, *macIDs.values()) + oldWinName = font["name"].getName(ID, *winIDs.values()) - if oldWinName != newName: - print(f"\n\t\t Win name was '{oldWinName}'") - font['name'].setName(newName, ID, *winIDs.values()) - print(f"\n\t\t Win name now '{newName}'") + if oldMacName != newName: + print(f"\n\t\t Mac name was '{oldMacName}'") + font["name"].setName(newName, ID, *macIDs.values()) + print(f"\n\t\t Mac name now '{newName}'") + + if oldWinName != newName: + print(f"\n\t\t Win name was '{oldWinName}'") + font["name"].setName(newName, ID, *winIDs.values()) + print(f"\n\t\t Win name now '{newName}'") # ---------------------------------------------- @@ -209,98 +208,123 @@ def setFontNameID(font, ID, newName): oldName = "Recursive" -def splitFont(fontPath, outputDirectory="fonts/rec_mono-for-code", newName="Rec Mono", ttc=False, zip=False): - - # access font as TTFont object - varfont = ttLib.TTFont(fontPath) - - fontFileName = os.path.basename(fontPath) - - for package in instanceValues: - outputSubDir = f"{outputDirectory}/{package}" - - for instance in instanceValues[package]: - - print(instance) - - instanceFont = instancer.instantiateVariableFont( - varfont, {\ - "wght": instanceValues[package][instance]['wght'], \ - "CASL": instanceValues[package][instance]['CASL'], \ - "MONO": instanceValues[package][instance]['MONO'], \ - "slnt": instanceValues[package][instance]['slnt'], \ - "CRSV": instanceValues[package][instance]['CRSV']} - ) - - # UPDATE NAME ID 6, postscript name - currentPsName = getFontNameID(instanceFont, 6) - newPsName = currentPsName.replace('Sans','').replace(oldName, newName.replace(' ','')).replace('LinearLight',instance.replace(' ','')) - setFontNameID(instanceFont, 6, newPsName) - - # UPDATE NAME ID 4, full font name - currentFullName = getFontNameID(instanceFont, 4) - newFullName = currentFullName.replace('Sans','').replace(oldName, newName).replace(' Linear Light',instance) - setFontNameID(instanceFont, 4, newFullName) - - # UPDATE NAME ID 3, unique font ID - currentUniqueName = getFontNameID(instanceFont, 3) - newUniqueName = currentUniqueName.replace('Sans','').replace(oldName, newName.replace(' ','')).replace('LinearLight',instance.replace(' ','')) - setFontNameID(instanceFont, 3, newUniqueName) - - # ADD name 2, style linking name - newStyleLinkingName = instanceValues[package][instance]['style'] - setFontNameID(instanceFont, 2, newStyleLinkingName) - setFontNameID(instanceFont, 17, newStyleLinkingName) - - # UPDATE NAME ID 1, unique font ID - currentFamName = getFontNameID(instanceFont, 1) - newFamName = currentFamName.replace(' Sans','').replace(oldName, newName).replace('Linear Light',instance.replace(" " + instanceValues[package][instance]['style'],'')) - setFontNameID(instanceFont, 1, newFamName) - setFontNameID(instanceFont, 16, newFamName) - - newFileName = fontFileName.replace(oldName,newName.replace(' ','')).replace('_VF_','-'+instance.replace(' ','')+'-') - - # make dir for new fonts - pathlib.Path(outputSubDir).mkdir(parents=True, exist_ok=True) - - # drop STAT table to allow RIBBI style naming & linking on Windows - del instanceFont["STAT"] - - outputPath = f"{outputSubDir}/{newFileName}" - - # save font - instanceFont.save(outputPath) - - # freeze in rvrn features with pyftfeatfreeze - pyftfeatfreeze.main(["--features=rvrn", outputPath, outputPath]) - - # swap dlig2calt to make code ligatures work in old code editor apps - dlig2calt(outputPath, inplace=True) - - - # ----------------------------------------------------------- - # make TTC (truetype collection) of fonts – doesn't current work on Mac very well :( - - if ttc: - # make list of fonts in subdir - fontPaths = [os.path.abspath(outputSubDir + "/" + x) for x in os.listdir(outputSubDir)] - - # form command - command = f"otf2otc {' '.join(fontPaths)} -o {outputDirectory}/RecMono-{package}.ttc" - print("▶", command, "\n") - - # run command in shell - makeTTF = subprocess.run(command.split(), check=True, text=True) - - # remove dir with individual fontpaths - shutil.rmtree(os.path.abspath(outputSubDir)) - - # Make zip of output, then put inside output directory - if zip: - shutil.make_archive(f"{outputDirectory}", 'zip', outputDirectory) - shutil.move(f"{outputDirectory}.zip",f"{outputDirectory}/{outputDirectory.split('/')[-1]}.zip") - - -if __name__ == '__main__': - fire.Fire(splitFont) \ No newline at end of file +def splitFont( + fontPath, + outputDirectory="fonts/rec_mono-for-code", + newName="Rec Mono", + ttc=False, + zip=False, +): + + # access font as TTFont object + varfont = ttLib.TTFont(fontPath) + + fontFileName = os.path.basename(fontPath) + + for package in instanceValues: + outputSubDir = f"{outputDirectory}/{package}" + + for instance in instanceValues[package]: + + print(instance) + + instanceFont = instancer.instantiateVariableFont( + varfont, + { + "wght": instanceValues[package][instance]["wght"], + "CASL": instanceValues[package][instance]["CASL"], + "MONO": instanceValues[package][instance]["MONO"], + "slnt": instanceValues[package][instance]["slnt"], + "CRSV": instanceValues[package][instance]["CRSV"], + }, + ) + + # UPDATE NAME ID 6, postscript name + currentPsName = getFontNameID(instanceFont, 6) + newPsName = (currentPsName.replace("Sans", "").replace( + oldName, + newName.replace(" ", "")).replace("LinearLight", + instance.replace(" ", ""))) + setFontNameID(instanceFont, 6, newPsName) + + # UPDATE NAME ID 4, full font name + currentFullName = getFontNameID(instanceFont, 4) + newFullName = (currentFullName.replace("Sans", "").replace( + oldName, newName).replace(" Linear Light", instance)) + setFontNameID(instanceFont, 4, newFullName) + + # UPDATE NAME ID 3, unique font ID + currentUniqueName = getFontNameID(instanceFont, 3) + newUniqueName = (currentUniqueName.replace("Sans", "").replace( + oldName, + newName.replace(" ", "")).replace("LinearLight", + instance.replace(" ", ""))) + setFontNameID(instanceFont, 3, newUniqueName) + + # ADD name 2, style linking name + newStyleLinkingName = instanceValues[package][instance]["style"] + setFontNameID(instanceFont, 2, newStyleLinkingName) + setFontNameID(instanceFont, 17, newStyleLinkingName) + + # UPDATE NAME ID 1, unique font ID + currentFamName = getFontNameID(instanceFont, 1) + newFamName = (currentFamName.replace(" Sans", "").replace(oldName, newName).replace( + "Linear Light", + instance.replace(" " + instanceValues[package][instance]["style"], ""), + )) + setFontNameID(instanceFont, 1, newFamName) + setFontNameID(instanceFont, 16, newFamName) + + newFileName = fontFileName.replace(oldName, newName.replace( + " ", "")).replace("_VF_", + "-" + instance.replace(" ", "") + "-") + + # make dir for new fonts + pathlib.Path(outputSubDir).mkdir(parents=True, exist_ok=True) + + # drop STAT table to allow RIBBI style naming & linking on Windows + del instanceFont["STAT"] + + outputPath = f"{outputSubDir}/{newFileName}" + + # save font + instanceFont.save(outputPath) + + # freeze in rvrn features with pyftfeatfreeze + pyftfeatfreeze.main(["--features=rvrn", outputPath, outputPath]) + + # swap dlig2calt to make code ligatures work in old code editor apps + dlig2calt(outputPath, inplace=True) + + # ----------------------------------------------------------- + # make TTC (truetype collection) of fonts – doesn't current work on Mac very well :( + + if ttc: + # make list of fonts in subdir + fontPaths = [ + os.path.abspath(outputSubDir + "/" + x) + for x in os.listdir(outputSubDir) + ] + + # form command + command = f"otf2otc {' '.join(fontPaths)} -o {outputDirectory}/RecMono-{package}.ttc" + print("▶", command, "\n") + + # run command in shell + subprocess.run(command.split(), check=True, text=True) + + # remove dir with individual fontpaths + shutil.rmtree(os.path.abspath(outputSubDir)) + + # Make zip of output, then put inside output directory + if zip: + shutil.make_archive(f"{outputDirectory}", "zip", outputDirectory) + shutil.move( + f"{outputDirectory}.zip", + f"{outputDirectory}/{outputDirectory.split('/')[-1]}.zip", + ) + + +if __name__ == "__main__": + fire.Fire(splitFont)