123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266 |
- import { join, extname } from "path";
- import * as fs from "fs";
- import util from "node:util";
- import * as child_process from "node:child_process";
- const _exec = util.promisify(child_process.exec);
- const dark_colors = {
- "#fc7f7f": "#fc9c9c",
- "#8da5f3": "#a5b7f3",
- "#e0e0e0": "#e0e0e0",
- "#c38ef1": "#cea4f1",
- "#8eef97": "#a5efac",
- };
- const light_colors = {
- "#fc7f7f": "#ff5f5f",
- "#8da5f3": "#6d90ff",
- "#e0e0e0": "#4f4f4f",
- "#c38ef1": "#bb6dff",
- "#8eef97": "#29d739",
- };
- function replace_colors(colors: object, data: string) {
- for (const [from, to] of Object.entries(colors)) {
- data = data.replace(from, to);
- }
- return data;
- }
- const iconsPath = "editor/icons";
- const modulesPath = "modules";
- const outputPath = "resources/godot_icons";
- const godotPath = process.argv[2];
- async function exec(command) {
- const { stdout, stderr } = await _exec(command);
- return stdout;
- }
- const git = {
- diff: "git diff HEAD",
- check_branch: "git rev-parse --abbrev-ref HEAD",
- reset: "git reset --hard",
- stash_push: "git stash push",
- stash_pop: "git stash pop",
- checkout: "git checkout ",
- checkout_4: "git checkout master",
- checkout_3: "git checkout 3.x",
- };
- function to_title_case(str) {
- return str.replace(
- /\w\S*/g,
- function (txt) {
- return txt.charAt(0).toUpperCase() + txt.substr(1).toLowerCase();
- }
- );
- }
- function get_class_list(modules) {
- const classes: string[] = [
- "ArrowDown.svg",
- "ArrowLeft.svg",
- "ArrowRight.svg",
- "ArrowUp.svg",
- "GuiVisibilityHidden.svg",
- "GuiVisibilityVisible.svg",
- "GuiVisibilityXray.svg",
- "Edit.svg",
- "Help.svg",
- "HelpSearch.svg",
- "ImportCheck.svg",
- "ImportFail.svg",
- "Info.svg",
- "Play.svg",
- "PlayBackwards.svg",
- "PlayCustom.svg",
- "PlayRemote.svg",
- "PlayScene.svg",
- "PlayStart.svg",
- "Progress1.svg",
- "Progress2.svg",
- "Progress3.svg",
- "Progress4.svg",
- "Progress5.svg",
- "Progress6.svg",
- "Progress7.svg",
- "Progress8.svg",
- "Progress9.svg",
- "Reload.svg",
- "ReloadSmall.svg",
- "Script.svg",
- "ScriptCreate.svg",
- "ScriptRemove.svg",
- "Search.svg",
- "Signals.svg",
- "SignalsAndGroups.svg",
- "Slot.svg",
- "Stop.svg",
- "Lock.svg",
- "Unlock.svg",
- "Zoom.svg",
- "ZoomLess.svg",
- "ZoomMore.svg",
- "ZoomReset.svg",
- ];
- const files = ["scene/register_scene_types.cpp"];
- modules.forEach(mod => {
- files.push(join(mod, "register_types.cpp"));
- });
- const patterns = [
- /GDREGISTER_CLASS\((\w*)\)/,
- /register_class<(\w*)>/,
- ];
- files.forEach(fileName => {
- const file = fs.readFileSync(fileName, "utf8");
- file.split("\n").forEach(line => {
- patterns.forEach(pattern => {
- const match = line.match(pattern);
- if (match) {
- classes.push(match[1] + ".svg");
- }
- });
- });
- });
- return classes;
- }
- function discover_modules() {
- const modules: string[] = [];
- // a valid module is a subdir of modulesPath, and contains a subdir 'icons'
- fs.readdirSync(modulesPath, { withFileTypes: true }).forEach(mod => {
- if (mod.isDirectory()) {
- fs.readdirSync(join(modulesPath, mod.name), { withFileTypes: true }).forEach(child => {
- if (child.isDirectory() && child.name == "icons") {
- modules.push(join(modulesPath, mod.name));
- }
- });
- }
- });
- return modules;
- }
- interface IconData {
- name: string;
- contents: string;
- }
- function get_icons(): IconData[] {
- const modules = discover_modules();
- const classes = get_class_list(modules);
- const searchPaths = [iconsPath];
- modules.forEach(mod => {
- searchPaths.push(join(mod, "icons"));
- });
- const icons: IconData[] = [];
- searchPaths.forEach(searchPath => {
- fs.readdirSync(searchPath).forEach(file => {
- if (extname(file) === ".svg") {
- let name = file;
- if (name.startsWith("icon_")) {
- name = name.replace("icon_", "");
- let parts = name.split("_");
- parts = parts.map(to_title_case);
- name = parts.join("");
- }
- if (!classes.includes(name)) {
- return;
- }
- const f = {
- name: name,
- contents: fs.readFileSync(join(searchPath, file), "utf8")
- };
- icons.push(f);
- }
- });
- });
- return icons;
- }
- function ensure_paths() {
- const paths = [
- outputPath,
- join(outputPath, "light"),
- join(outputPath, "dark"),
- ];
- paths.forEach(path => {
- if (!fs.existsSync(path)) {
- fs.mkdirSync(path);
- }
- });
- }
- async function run() {
- if (godotPath == undefined) {
- console.log("Please provide the absolute path to your godot repo");
- return;
- }
- const original_cwd = process.cwd();
- process.chdir(godotPath);
- const diff = (await exec(git.diff)).trim();
- if (diff) {
- console.log("There appear to be uncommitted changes in your godot repo");
- console.log("Revert or stash these changes and try again");
- return;
- }
- const branch = (await exec(git.check_branch)).trim();
- console.log("Gathering Godot 3 icons...");
- await exec(git.checkout_3);
- const g3 = get_icons();
- console.log("Gathering Godot 4 icons...");
- await exec(git.checkout_4);
- const g4 = get_icons();
- await exec(git.checkout + branch);
- process.chdir(original_cwd);
- console.log(`Found ${g3.length + g4.length} icons...`);
- const light_icons: Map<string, string> = new Map();
- const dark_icons: Map<string, string> = new Map();
- console.log("Generating themed icons...");
- g3.forEach(file => {
- light_icons[file.name] = replace_colors(light_colors, file.contents);
- });
- g4.forEach(file => {
- light_icons[file.name] = replace_colors(light_colors, file.contents);
- });
- g3.forEach(file => {
- dark_icons[file.name] = replace_colors(dark_colors, file.contents);
- });
- g4.forEach(file => {
- dark_icons[file.name] = replace_colors(dark_colors, file.contents);
- });
- console.log("Ensuring output directory...");
- ensure_paths();
- console.log("Writing icons to output directory...");
- for (const [file, contents] of Object.entries(light_icons)) {
- fs.writeFileSync(join(outputPath, "light", file), contents);
- }
- for (const [file, contents] of Object.entries(dark_icons)) {
- fs.writeFileSync(join(outputPath, "dark", file), contents);
- }
- }
- run();
|