diff --git a/font-patcher b/font-patcher index 581eaee5987..90c8d494f08 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 = "3.6.1" +script_version = "3.6.3" version = "2.3.3" projectName = "Nerd Fonts" @@ -989,10 +989,10 @@ class font_patcher: {'Enabled': self.args.material, 'Name': "Material", 'Filename': "materialdesign/MaterialDesignIconsDesktop.ttf", 'Exact': True, 'SymStart': 0xF0001,'SymEnd': 0xF1AF0,'SrcStart': None, 'ScaleRules': MDI_SCALE_LIST, 'Attributes': SYM_ATTR_DEFAULT}, {'Enabled': self.args.weather, 'Name': "Weather Icons", 'Filename': "weather-icons/weathericons-regular-webfont.ttf", 'Exact': False, 'SymStart': 0xF000, 'SymEnd': 0xF0EB, 'SrcStart': 0xE300, 'ScaleRules': WEATH_SCALE_LIST, 'Attributes': SYM_ATTR_DEFAULT}, {'Enabled': self.args.fontlogos, 'Name': "Font Logos", 'Filename': "font-logos.ttf", 'Exact': True, 'SymStart': 0xF300, 'SymEnd': 0xF32F, 'SrcStart': None, 'ScaleRules': None, 'Attributes': SYM_ATTR_DEFAULT}, - {'Enabled': self.args.octicons, 'Name': "Octicons", 'Filename': "octicons.ttf", 'Exact': False, 'SymStart': 0xF000, 'SymEnd': 0xF105, 'SrcStart': 0xF400, 'ScaleRules': OCTI_SCALE_LIST, 'Attributes': SYM_ATTR_DEFAULT}, # Magnifying glass - {'Enabled': self.args.octicons, 'Name': "Octicons", 'Filename': "octicons.ttf", 'Exact': True, 'SymStart': 0x2665, 'SymEnd': 0x2665, 'SrcStart': None, 'ScaleRules': OCTI_SCALE_LIST, 'Attributes': SYM_ATTR_DEFAULT}, # Heart - {'Enabled': self.args.octicons, 'Name': "Octicons", 'Filename': "octicons.ttf", 'Exact': True, 'SymStart': 0X26A1, 'SymEnd': 0X26A1, 'SrcStart': None, 'ScaleRules': OCTI_SCALE_LIST, 'Attributes': SYM_ATTR_DEFAULT}, # Zap - {'Enabled': self.args.octicons, 'Name': "Octicons", 'Filename': "octicons.ttf", 'Exact': False, 'SymStart': 0xF27C, 'SymEnd': 0xF27C, 'SrcStart': 0xF4A9, 'ScaleRules': OCTI_SCALE_LIST, 'Attributes': SYM_ATTR_DEFAULT}, # Desktop + {'Enabled': self.args.octicons, 'Name': "Octicons", 'Filename': "octicons/octicons.ttf", 'Exact': False, 'SymStart': 0xF000, 'SymEnd': 0xF105, 'SrcStart': 0xF400, 'ScaleRules': OCTI_SCALE_LIST, 'Attributes': SYM_ATTR_DEFAULT}, # Magnifying glass + {'Enabled': self.args.octicons, 'Name': "Octicons", 'Filename': "octicons/octicons.ttf", 'Exact': True, 'SymStart': 0x2665, 'SymEnd': 0x2665, 'SrcStart': None, 'ScaleRules': OCTI_SCALE_LIST, 'Attributes': SYM_ATTR_DEFAULT}, # Heart + {'Enabled': self.args.octicons, 'Name': "Octicons", 'Filename': "octicons/octicons.ttf", 'Exact': True, 'SymStart': 0X26A1, 'SymEnd': 0X26A1, 'SrcStart': None, 'ScaleRules': OCTI_SCALE_LIST, 'Attributes': SYM_ATTR_DEFAULT}, # Zap + {'Enabled': self.args.octicons, 'Name': "Octicons", 'Filename': "octicons/octicons.ttf", 'Exact': False, 'SymStart': 0xF27C, 'SymEnd': 0xF27C, 'SrcStart': 0xF4A9, 'ScaleRules': OCTI_SCALE_LIST, 'Attributes': SYM_ATTR_DEFAULT}, # Desktop {'Enabled': self.args.codicons, 'Name': "Codicons", 'Filename': "codicons/codicon.ttf", 'Exact': True, 'SymStart': 0xEA60, 'SymEnd': 0xEBEB, 'SrcStart': None, 'ScaleRules': CODI_SCALE_LIST, 'Attributes': SYM_ATTR_DEFAULT}, {'Enabled': self.args.custom, 'Name': "Custom", 'Filename': self.args.custom, 'Exact': True, 'SymStart': 0x0000, 'SymEnd': 0x0000, 'SrcStart': None, 'ScaleRules': None, 'Attributes': CUSTOM_ATTR} ] diff --git a/src/glyphs/octicons/analyze_octicons b/src/glyphs/octicons/analyze_octicons new file mode 100755 index 00000000000..67d6728b0d4 --- /dev/null +++ b/src/glyphs/octicons/analyze_octicons @@ -0,0 +1,32 @@ +#!/usr/bin/env python3 +# coding=utf8 + +# This extracts the names and source and destination codepoints +# of the old octicons font file to keep their codepoints stable +# +# You do not need to redo it, the result is in the repo +# +# Usage: +# fontforge analyze_octicons > mapping + +import fontforge + +octi_orig = "octicons_old.ttf" +current_cp = 0xF400 + +print('# Examining {}'.format(octi_orig)) + +font = fontforge.open(octi_orig) +for glyph in font.glyphs('encoding'): + point = glyph.unicode + if point < 0: + continue + desti = glyph.unicode + if point < 0xF000: + desti = point + else: + desti = current_cp + current_cp += 1 + print("{:X} {:X} {}".format(point, desti, glyph.glyphname)) + +font.close() diff --git a/src/glyphs/octicons/generate b/src/glyphs/octicons/generate new file mode 100755 index 00000000000..c7ac2f8e99c --- /dev/null +++ b/src/glyphs/octicons/generate @@ -0,0 +1,180 @@ +#!/usr/bin/env python3 +# coding=utf8 + +import sys +import os +import re +import subprocess +import fontforge + +# Double-quotes required here, for version-bump.sh: +version = "2.3.3" + +archive = 'v18.2.0.tar.gz' + +vectorsdir = 'icons' +fontdir = '.' +fontfile = 'octicons.ttf' +glyphsetfile = 'i_oct.sh' +glyphsetsdir = '../../../bin/scripts/lib' + +subset = '-16' # use 16 px subset if possible +subset_other = '-24' # use 24 px subset otherwise + +def renamer(old_name): + """ Return new equivalent icon name """ + return { + 'trashcan' : 'trash', + 'cloud-download' : 'download', + 'cloud-upload' : 'upload', + 'clippy' : 'paste', + 'mail-read' : 'read', + 'primitive-dot' : 'dot-fill', + 'primitive-square' : 'square-fill', + 'settings' : 'sliders', + 'dashboard' : 'meter', + 'paintcan' : 'paintbrush', + }.get(old_name, old_name) + +def addIcon(codepoint, name, filename): + """ Add one outline file and rescale/move """ + dBB = [120, 0, 1000-120, 900] # just some nice sizes + filename = os.path.join(vectorsdir, filename) + glyph = font.createChar(codepoint, name) + glyph.importOutlines(filename) + glyph.manualHints = True + +def createGlyphInfo(icon_datasets, filepathname, into): + """ Write the glyphinfo file """ + with open(filepathname, 'w', encoding = 'utf8') as f: + f.write(u'#!/usr/bin/env bash\n') + f.write(intro) + f.write(u'# Script Version: (autogenerated)\n') + f.write(u'test -n "$__i_oct_loaded" && return || __i_oct_loaded=1\n') + for _, codepoint, name in icon_datasets: + codepoint = int(codepoint, 16) + f.write(u"i='{}' i_oct_{}=$i\n".format(chr(codepoint), name)) + f.write(u'unset i\n') + +print('\nReading mapping file') +old_mapping = [] +with open('mapping', 'r') as f: + for line in f.readlines(): + if line.startswith('#'): + continue + old_mapping.append(tuple(re.split(' +', line.strip()))) +print('Found {} entries'.format(len(old_mapping))) +old_mapping.sort(key=(lambda x: x[0])) + +print('Fetching octicons archive "{}"\n'.format(archive)) +if subprocess.call('curl -OL https://github.com/primer/octicons/archive/' + archive, shell=True): + sys.exit('Error fetching octicons archive') +print('\nUnpacking octicons archive') +if subprocess.call('rm -rf icons octicons-* && tar zxf *.gz && mv octicons-*/icons . && rm -rf octicons-*', shell=True): + sys.exit('Error unpacking archive') + +svgs = os.listdir(vectorsdir) +print('Found {} svgs'.format(len(svgs))) +names = { s[0:-len('-xx.svg')] for s in svgs if s.endswith(subset + '.svg') or s.endswith(subset_other + '.svg') } +print('Found {} icons after de-duplicating\n'.format(len(names))) + +num_found = 0 +num_missing = 0 +misslist = '' +renamelist = '' +freeslots = [] + +new_mapping = [] +for i, j, old_n in old_mapping: + if old_n in names: + names.remove(old_n) + new_mapping.append((i, j, old_n)) + num_found += 1 + continue + new_n = renamer(old_n) + if new_n in names: + renamelist += 'Renamed {} -> {}\n'.format(old_n, new_n) + names.remove(new_n) + new_mapping.append((i, j, new_n)) + num_found += 1 + continue + misslist += 'Missing {}\n'.format(old_n) + freeslots.append((i, j)) + num_missing += 1 + +print(renamelist) +print(misslist) +print('Found {} (of {}, missing {}) and new {}'.format(num_found, len(old_mapping), num_missing, len(names))) + +names = list(names) +names.sort() +for n in list(names): + if len(freeslots) == 0: + break + i, j = freeslots[0] + new_mapping.append((i, j, n)) + names.remove(n) + freeslots = freeslots[1:] + +print('Filled in missing, remaining new {}'.format(len(names))) + +i_max = 0 +j_max = 0 +for i, j, _ in new_mapping: + i = int(i, 16) + j = int(j, 16) + if i > i_max: + i_max = i + if j > j_max: + j_max = j + +for n in names: + i_max += 1 + j_max += 1 + new_mapping.append(('{:X}'.format(i_max), '{:X}'.format(j_max), n)) + +print('Appended remaining new, total new mapping {}'.format(len(new_mapping))) + +new_mapping.sort(key=(lambda x: x[0])) +with open('mapping', 'w') as f: + for i, j, n in new_mapping: + f.write('{} {} {}\n'.format(i, j, n)) + +font = fontforge.font() +font.fontname = 'OcticonsNerdFont-Regular' +font.fullname = 'Octicons Nerd Font Regular' +font.familyname = 'Octicons Nerd Font' +font.em = 2048 +font.encoding = 'UnicodeFull' + +# Add valid space glyph to avoid "unknown character" box on IE11 +glyph = font.createChar(32) +glyph.width = 200 + +font.sfntRevision = None # Auto-set (refreshed) by fontforge +font.version = version +font.copyright = 'Nerd Fonts' +font.appendSFNTName('English (US)', 'Version', version) +font.appendSFNTName('English (US)', 'Vendor URL', 'https://github.com/ryanoasis/nerd-fonts') +font.appendSFNTName('English (US)', 'Copyright', 'Nerd Fonts') + +for codepoint, _, name in new_mapping: + codepoint = int(codepoint, 16) + filename = name + subset + '.svg' + if filename not in svgs: + filename = name + subset_other + '.svg' + addIcon(codepoint, name, filename) + +num_icons = len(new_mapping) + +print('Generating {} with {} glyphs'.format(fontfile, num_icons)) +font.generate(os.path.join(fontdir, fontfile), flags=("no-FFTM-table",)) + +codepoints = [ int(p, 16) for _, p, _ in new_mapping ] +intro = u'# Octicons ({} icons)\n'.format(num_icons) +intro += u'# Codepoints: {:X}-{:X} with gaps\n'.format(min(codepoints), max(codepoints)) +intro += u'# Nerd Fonts Version: {}\n'.format(version) + +print('Generating GlyphInfo {}'.format(glyphsetfile)) +createGlyphInfo(new_mapping, os.path.join(glyphsetsdir, glyphsetfile), intro) +print('Finished') diff --git a/src/glyphs/octicons/mapping b/src/glyphs/octicons/mapping new file mode 100644 index 00000000000..a70dab0a99d --- /dev/null +++ b/src/glyphs/octicons/mapping @@ -0,0 +1,173 @@ +# Examining octicons_old.ttf +2665 2665 heart +26A1 26A1 zap +F000 F400 light-bulb +F001 F401 repo +F002 F402 repo-forked +F005 F403 repo-push +F006 F404 repo-pull +F007 F405 book +F008 F406 octoface +F009 F407 git-pull-request +F00A F408 mark-github +F00B F409 cloud-download +F00C F40A cloud-upload +F00D F40B keyboard +F00E F40C gist +F010 F40D file-code +F011 F40E file-text +F012 F40F file-media +F013 F410 file-zip +F014 F411 file-pdf +F015 F412 tag +F016 F413 file-directory +F017 F414 file-submodule +F018 F415 person +F019 F416 jersey +F01F F417 git-commit +F020 F418 git-branch +F023 F419 git-merge +F024 F41A mirror +F026 F41B issue-opened +F027 F41C issue-reopened +F028 F41D issue-closed +F02A F41E star +F02B F41F comment +F02C F420 question +F02D F421 alert +F02E F422 search +F02F F423 gear +F030 F424 radio-tower +F031 F425 tools +F032 F426 sign-out +F033 F427 rocket +F034 F428 rss +F035 F429 clippy +F036 F42A sign-in +F037 F42B organization +F038 F42C device-mobile +F039 F42D unfold +F03A F42E check +F03B F42F mail +F03C F430 mail-read +F03D F431 arrow-up +F03E F432 arrow-right +F03F F433 arrow-down +F040 F434 arrow-left +F041 F435 pin +F042 F436 gift +F043 F437 graph +F044 F438 triangle-left +F045 F439 credit-card +F046 F43A clock +F047 F43B ruby +F048 F43C broadcast +F049 F43D key +F04A F43E repo-force-push +F04C F43F repo-clone +F04D F440 diff +F04E F441 eye +F04F F442 comment-discussion +F051 F443 mail-reply +F052 F444 primitive-dot +F053 F445 primitive-square +F056 F446 device-camera +F057 F447 device-camera-video +F058 F448 pencil +F059 F449 info +F05A F44A triangle-right +F05B F44B triangle-down +F05C F44C link +F05D F44D plus +F05E F44E three-bars +F05F F44F code +F060 F450 location +F061 F451 list-unordered +F062 F452 list-ordered +F063 F453 quote +F064 F454 versions +F068 F455 calendar +F06A F456 lock +F06B F457 diff-added +F06C F458 diff-removed +F06D F459 diff-modified +F06E F45A diff-renamed +F070 F45B horizontal-rule +F071 F45C arrow-small-right +F075 F45D milestone +F076 F45E checklist +F077 F45F megaphone +F078 F460 chevron-right +F07B F461 bookmark +F07C F462 settings +F07D F463 dashboard +F07E F464 history +F07F F465 link-external +F080 F466 mute +F081 F467 x +F084 F468 circle-slash +F085 F469 pulse +F087 F46A sync +F088 F46B telescope +F08C F46C gist-secret +F08D F46D home +F08F F46E stop +F091 F46F bug +F092 F470 logo-github +F094 F471 file-binary +F096 F472 database +F097 F473 server +F099 F474 diff-ignored +F09A F475 ellipsis +F09C F476 no-newline +F09D F477 hubot +F09F F478 arrow-small-up +F0A0 F479 arrow-small-down +F0A1 F47A arrow-small-left +F0A2 F47B chevron-up +F0A3 F47C chevron-down +F0A4 F47D chevron-left +F0AA F47E triangle-up +F0AC F47F git-compare +F0AD F480 logo-gist +F0B0 F481 file-symlink-file +F0B1 F482 file-symlink-directory +F0B2 F483 squirrel +F0B6 F484 globe +F0BA F485 unmute +F0BE F486 mention +F0C4 F487 package +F0C5 F488 browser +F0C8 F489 terminal +F0C9 F48A markdown +F0CA F48B dash +F0CC F48C fold +F0CF F48D inbox +F0D0 F48E trashcan +F0D1 F48F paintcan +F0D2 F490 flame +F0D3 F491 briefcase +F0D4 F492 plug +F0D6 F493 circuit-board +F0D7 F494 mortar-board +F0D8 F495 law +F0DA F496 thumbsup +F0DB F497 thumbsdown +F0DC F498 desktop-download +F0DD F499 beaker +F0DE F49A bell +F0E0 F49B watch +F0E1 F49C shield +F0E2 F49D bold +F0E3 F49E text-size +F0E4 F49F italic +F0E5 F4A0 tasklist +F0E6 F4A1 verified +F0E7 F4A2 smiley +F0E8 F4A3 unverified +F101 F4A4 ellipses +F102 F4A5 file +F103 F4A6 grabber +F104 F4A7 plus-small +F105 F4A8 reply +F27C F4A9 device-desktop diff --git a/src/glyphs/octicons.ttf b/src/glyphs/octicons/octicons.ttf similarity index 100% rename from src/glyphs/octicons.ttf rename to src/glyphs/octicons/octicons.ttf