|
| 1 | +#!/usr/bin/env python3 |
| 2 | +# coding=utf8 |
| 3 | + |
| 4 | +# Create a new mapping file by combining the information from |
| 5 | +# the old mapping and checking which icons got dropped; are new; |
| 6 | +# or get a different svg file. |
| 7 | + |
| 8 | +# PREREQUISITES: |
| 9 | +# $ curl -OL https://github.com/devicons/devicon/archive/refs/tags/v2.16.0.tar.gz |
| 10 | +# $ tar zxf v2.16.0.tar.gz |
| 11 | +# $ mv devicon-*/icons . |
| 12 | +# $ cp -r vorillaz icons |
| 13 | + |
| 14 | +import re, os, sys |
| 15 | + |
| 16 | +vectorsdir = 'icons' |
| 17 | + |
| 18 | +def filename_from_name(filename): |
| 19 | + """ Some icons have a name that is not the svg filename """ |
| 20 | + # Returns '-' if the icon is to be removed |
| 21 | + # Giving a full pathname selects a certain svg variant |
| 22 | + return { |
| 23 | + 'awk': 'fixed/awk-plain.svg', # added as fixed icon |
| 24 | + 'bower': 'bower/bower-line.svg', |
| 25 | + 'c_lang': 'c', |
| 26 | + 'clojure': 'clojure/clojure-line.svg', |
| 27 | + 'composer': 'composer/composer-line.svg', |
| 28 | + 'css3_full': 'css3/css3-plain-wordmark.svg', |
| 29 | + 'djangorest': 'djangorest/djangorest-plain-wordmark.svg', |
| 30 | + 'dotnet': 'dot-net', |
| 31 | + 'ghost': 'ghost/ghost-original-wordmark.svg', |
| 32 | + 'github_full': 'github/github-original-wordmark.svg', |
| 33 | + 'go': 'go/go-line.svg', |
| 34 | + 'grunt': 'grunt/grunt-line.svg', |
| 35 | + 'ie': 'ie10', |
| 36 | + 'jenkins': 'jenkins/jenkins-line.svg', |
| 37 | + 'meteorfull': 'meteor/meteor-plain-wordmark.svg', |
| 38 | + 'nodejs': 'nodejs/nodejs-plain-wordmark.svg', |
| 39 | + 'nodejs_small': 'nodejs', |
| 40 | + 'windows': 'windows8', |
| 41 | + }.get(filename, filename) |
| 42 | + |
| 43 | +def get_aliases(names): |
| 44 | + """ For some icons we would like to have aliases """ |
| 45 | + # Returns a list with aliases, first element is main name and glyphname |
| 46 | + name = names[0] |
| 47 | + return { |
| 48 | + 'c': [ 'c_lang', 'c' ], |
| 49 | + 'github_badge': [ 'github', 'github_badge' ], |
| 50 | + 'javascript_badge': [ 'javascript', 'javascript_badge' ], |
| 51 | + 'krakenjs_badge': [ 'krakenjs', 'krakenjs_badge' ], |
| 52 | + 'symfony_badge': [ 'symfony', 'symfony_badge' ], |
| 53 | + 'unifiedmodelinglanguage': [ 'unifiedmodelinglanguage', 'uml' ], |
| 54 | + }.get(name, names) |
| 55 | + |
| 56 | +def file_with_ending(files, ending): |
| 57 | + """ Return the (first) file out of a list of files that has the desired ending """ |
| 58 | + # Returns False if no match at all |
| 59 | + matches = [ file for file in files if file.endswith(ending) ] |
| 60 | + if not matches: |
| 61 | + return False |
| 62 | + return matches[0] |
| 63 | + |
| 64 | +def suggest_new_filename(name): |
| 65 | + """ Return a specific svg filename for one icon, preferring some svg filename endings """ |
| 66 | + name = filename_from_name(name) |
| 67 | + subdir = os.path.join(vectorsdir, name) |
| 68 | + if not os.path.exists(subdir): |
| 69 | + return False |
| 70 | + if os.path.isfile(subdir): |
| 71 | + # For translation to direct filename hits |
| 72 | + return name |
| 73 | + svgs = os.listdir(subdir) |
| 74 | + filename = file_with_ending(svgs, 'plain.svg') |
| 75 | + if not filename: |
| 76 | + filename = file_with_ending(svgs, 'original.svg') |
| 77 | + if not filename: |
| 78 | + filename = file_with_ending(svgs, 'plain-wordmark.svg') |
| 79 | + if not filename: |
| 80 | + filename = file_with_ending(svgs, 'original-wordmark.svg') |
| 81 | + if not filename: |
| 82 | + return False |
| 83 | + return os.path.join(name, filename) |
| 84 | + |
| 85 | +remix_mapping = [] |
| 86 | +with open('mapping', 'r') as f: |
| 87 | + for line in f.readlines(): |
| 88 | + if line.startswith('#'): |
| 89 | + continue |
| 90 | + c1, c2, n, *f = re.split(' +', line.strip()) |
| 91 | + remix_mapping.append((int(c1, 16), int(c2, 16), n, *f)) |
| 92 | + |
| 93 | +new_names = os.listdir(vectorsdir) |
| 94 | +new_names.sort() |
| 95 | +new_names.remove('vorillaz') # If this fails one prerequisite step is missing |
| 96 | +if 'fixed' in new_names: |
| 97 | + # This can exist after a generate run |
| 98 | + new_names.remove('fixed') |
| 99 | + |
| 100 | +print('Found {} mapping entries and {} devicon directories'.format( |
| 101 | + len(remix_mapping), len(new_names))) |
| 102 | + |
| 103 | +notes1 = '' |
| 104 | +notes2 = '' |
| 105 | +mapping = [] |
| 106 | +for orig_point, dest_point, filename, *names in remix_mapping: |
| 107 | + if not os.path.isfile(os.path.join(vectorsdir, filename)): |
| 108 | + newfilename = suggest_new_filename(names[0]) |
| 109 | + if newfilename: |
| 110 | + notes1 += '# SVG change: code: {:04X} name: {}, old: {}, new: {}\n'.format( |
| 111 | + orig_point, names[0], filename, newfilename) |
| 112 | + filename = newfilename |
| 113 | + if filename: |
| 114 | + mapping.append((orig_point, dest_point, filename, *names)) |
| 115 | + dirname = os.path.dirname(filename) |
| 116 | + if dirname.endswith('fixed'): |
| 117 | + # Translate dirname for fixed icons |
| 118 | + dirname = names[0] |
| 119 | + if dirname in new_names: |
| 120 | + new_names.remove(dirname) |
| 121 | + continue |
| 122 | + |
| 123 | + notes2 += '# Icon dropped: code: {:04X} name: {}\n'.format( |
| 124 | + orig_point, names[0]) |
| 125 | + |
| 126 | +index = 0xE700 |
| 127 | +taken_codes = set([ e[1] for e in mapping ]) |
| 128 | +for iconname in new_names: |
| 129 | + filename = suggest_new_filename(iconname) |
| 130 | + if not filename: |
| 131 | + sys.exit('Can not find svg for "{}"'.format(iconname)) |
| 132 | + while index in taken_codes: |
| 133 | + index = index + 1 |
| 134 | + mapping.append((index - 0x0100, index, filename, iconname)) |
| 135 | + taken_codes.add(index) |
| 136 | + |
| 137 | +with open('mapping', 'w', encoding = 'utf8') as f: |
| 138 | + f.write('# Devicons mapping file\n') |
| 139 | + f.write('#\n') |
| 140 | + f.write('# DEV-code NF-code filename name [alias [...]]\n') |
| 141 | + f.write('#\n') |
| 142 | + |
| 143 | + mapping.sort(key=(lambda x: x[1])) |
| 144 | + unique_names = set() |
| 145 | + for orig_point, dest_point, filename, *names in mapping: |
| 146 | + aliases = get_aliases(names) |
| 147 | + for n in aliases: |
| 148 | + if n not in unique_names: |
| 149 | + unique_names.add(n) |
| 150 | + else: |
| 151 | + sys.exit('ERROR name duplicate found: {}'.format(n)) |
| 152 | + f.write('{:04X} {:04X} {} {}\n'.format(orig_point, dest_point, filename, ' '.join(aliases))) |
| 153 | + |
| 154 | +if notes1: |
| 155 | + print(notes1) |
| 156 | +if notes2: |
| 157 | + print(notes2) |
| 158 | + |
| 159 | +print('Generated new mapping with {} entries'.format(len(mapping))) |
0 commit comments