1"""Brings the icons and their name map over from a clone of 2wolfsouldev/jerrys-pixel-icons. 3 4 nix shell nixpkgs#librsvg -c python3 third-party/jerrys-pixel-icons/update.py <clone> 5 6Each upstream icon is an SVG holding one PNG; the PNG is taken out as it 7is. The few drawn as paths are rendered at the same size. The theme's map 8(names, extensions, folders) is written as packages/tree/src/icons_theme.rs. 9""" 10import base64, glob, json, os, re, subprocess, sys 11 12src = sys.argv[1] 13out = os.path.dirname(os.path.abspath(__file__)) 14root = os.path.join(out, "..", "..") 15commit = subprocess.run(["git", "-C", src, "log", "-1", "--format=%h %s"], capture_output=True, text=True, check=True).stdout.strip() 16 17have = set() 18for path in sorted(glob.glob(src + "/icons/*/*.svg")): 19 kind = "file" if "/files/" in path else "folder" 20 name = f"{kind}-{os.path.basename(path)[:-4]}" 21 held = re.search(r'href="data:image/png;base64,([^"]+)"', open(path).read()) 22 dest = os.path.join(out, name + ".png") 23 if held: 24 open(dest, "wb").write(base64.b64decode(held.group(1))) 25 else: 26 subprocess.run(["rsvg-convert", "-w", "256", "-h", "256", path, "-o", dest], check=True) 27 have.add(name)
The theme is JSON with comments and trailing commas.
35def icon(defined): 36 path = theme["iconDefinitions"][defined]["iconPath"] 37 return f"{'file' if '/files/' in path else 'folder'}-{os.path.basename(path)[:-4]}" 38 39 40def table(name, entries, doc): 41 rows = sorted((key, icon(value)) for key, value in entries.items() if "*" not in key and value in theme["iconDefinitions"]) 42 for _, value in rows: 43 assert value in have, value 44 body = "".join(f' ("{key}", "{value}"),\n' for key, value in rows) 45 return f"/// {doc}\npub const {name}: &[(&str, &str)] = &[\n{body}];\n" 46 47 48rust = f"""//! Which of Jerry's pixel icons a name gets: the icon theme's own map 49//! (`themes/icon-theme.json` of wolfsouldev/jerrys-pixel-icons, at 50//! {commit}), read into tables. Generated by 51//! third-party/jerrys-pixel-icons/update.py; do not edit by hand. Entries 52//! with a wildcard are left out. Each icon is a file of that name, `.png`, 53//! in third-party/jerrys-pixel-icons. 54 55{table("EXTENSIONS", theme["fileExtensions"], "A file, by what follows its last dot.")} 56{table("NAMES", theme["fileNames"], "A file, by its whole name.")} 57{table("FOLDERS", theme["folderNames"], "A folder, by its name. Its open icon is the same name with `-open`.")} 58/// A file with no icon of its own, and a folder with none. 59pub const FILE: &str = "{icon(theme["file"])}"; 60pub const FOLDER: &str = "{icon(theme["folder"])}"; 61""" 62open(os.path.join(root, "packages/tree/src/icons_theme.rs"), "w").write(rust) 63subprocess.run(["cp", src + "/LICENSE", os.path.join(out, "LICENSE")], check=True) 64print(len(have), "icons, from", commit)