mirror of
https://github.com/godotengine/godot-vscode-plugin.git
synced 2025-12-31 13:48:24 +03:00
* Updated Godot icons (and removed old ones) * Improve "Debug Pinned Scene" command by making the pinned scene persist between VSCode sessions * Fix scene file highlighting not working * Fix ScenePreview not working in Godot 3 * Add buttons for relevant actions to ScenePreview items * Add internal document links for SubResource() and ExtResource() statements in scene files * Add hover for SubResource() and ExtResource() statements in scene files * Improve ability to right click -> open docs for methods of builtin types (doesn't always work) * Add a file decorator to show the pinned debug file in the filesystem view/editor tabs * Add item decorators to the Scene Preview to show Node attributes more clearly * Updated readme * Overhauled documentation viewer * Added GDScript formatter * Add (disabled) experimental providers for custom completions, semantic tokens, and tasks * Lots of internal refactoring
267 lines
5.8 KiB
TypeScript
267 lines
5.8 KiB
TypeScript
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();
|