Various QoL Improvements (#529)

* 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
This commit is contained in:
Daelon Suzuka
2023-12-06 09:53:10 -05:00
committed by GitHub
parent f65033c626
commit e7e2d0439d
1090 changed files with 6483 additions and 5297 deletions

View File

@@ -1,50 +1,50 @@
import { join, extname } from 'path';
import fs = require('fs');
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',
"#fc7f7f": "#fc9c9c",
"#8da5f3": "#a5b7f3",
"#e0e0e0": "#e0e0e0",
"#c38ef1": "#cea4f1",
"#8eef97": "#a5efac",
};
const light_colors = {
'#fc7f7f': '#ff5f5f',
'#8da5f3': '#6d90ff',
'#e0e0e0': '#4f4f4f',
'#c38ef1': '#bb6dff',
'#8eef97': '#29d739',
"#fc7f7f": "#ff5f5f",
"#8da5f3": "#6d90ff",
"#e0e0e0": "#4f4f4f",
"#c38ef1": "#bb6dff",
"#8eef97": "#29d739",
};
function replace_colors(colors: Object, data: String) {
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 iconsPath = "editor/icons";
const modulesPath = "modules";
const outputPath = "resources/godot_icons";
const godotPath = process.argv[2];
const util = require('node:util');
const _exec = util.promisify(require('node:child_process').exec);
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',
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) {
@@ -57,11 +57,56 @@ function to_title_case(str) {
}
function get_class_list(modules) {
const classes = [];
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'];
const files = ["scene/register_scene_types.cpp"];
modules.forEach(mod => {
files.push(join(mod, 'register_types.cpp'));
files.push(join(mod, "register_types.cpp"));
});
const patterns = [
@@ -70,12 +115,12 @@ function get_class_list(modules) {
];
files.forEach(fileName => {
const file = fs.readFileSync(fileName, 'utf8');
file.split('\n').forEach(line => {
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');
classes.push(match[1] + ".svg");
}
});
});
@@ -86,13 +131,13 @@ function get_class_list(modules) {
}
function discover_modules() {
const modules = [];
const modules: string[] = [];
// a valid module is a subdir of modulesPath, and contains a subdir 'icons'
fs.readdirSync(modulesPath, {withFileTypes:true}).forEach(mod => {
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') {
fs.readdirSync(join(modulesPath, mod.name), { withFileTypes: true }).forEach(child => {
if (child.isDirectory() && child.name == "icons") {
modules.push(join(modulesPath, mod.name));
}
});
@@ -101,47 +146,52 @@ function discover_modules() {
return modules;
}
interface IconData {
name: string;
contents: string;
}
function get_icons() {
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'));
searchPaths.push(join(mod, "icons"));
});
const icons = [];
const icons: IconData[] = [];
searchPaths.forEach(searchPath => {
fs.readdirSync(searchPath).forEach(file => {
if (extname(file) === '.svg') {
if (extname(file) === ".svg") {
let name = file;
if (name.startsWith('icon_')) {
name = name.replace('icon_', '');
let parts = name.split('_');
if (name.startsWith("icon_")) {
name = name.replace("icon_", "");
let parts = name.split("_");
parts = parts.map(to_title_case);
name = parts.join('');
name = parts.join("");
}
if (!classes.includes(name)) {
return;
}
const f = {
name: name,
contents: fs.readFileSync(join(searchPath, file), 'utf8')
contents: fs.readFileSync(join(searchPath, file), "utf8")
};
icons.push(f);
}
});
});
return icons;
}
function ensure_paths() {
const paths = [
outputPath,
join(outputPath, 'light'),
join(outputPath, 'dark'),
join(outputPath, "light"),
join(outputPath, "dark"),
];
paths.forEach(path => {
@@ -153,7 +203,7 @@ function ensure_paths() {
async function run() {
if (godotPath == undefined) {
console.log('Please provide the absolute path to your godot repo');
console.log("Please provide the absolute path to your godot repo");
return;
}
@@ -163,18 +213,18 @@ async function run() {
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');
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...');
console.log("Gathering Godot 3 icons...");
await exec(git.checkout_3);
const g3 = get_icons();
console.log('Gathering Godot 4 icons...');
console.log("Gathering Godot 4 icons...");
await exec(git.checkout_4);
const g4 = get_icons();
@@ -184,10 +234,10 @@ async function run() {
console.log(`Found ${g3.length + g4.length} icons...`);
const light_icons = {};
const dark_icons = {};
const light_icons: Map<string, string> = new Map();
const dark_icons: Map<string, string> = new Map();
console.log('Generating themed icons...');
console.log("Generating themed icons...");
g3.forEach(file => {
light_icons[file.name] = replace_colors(light_colors, file.contents);
});
@@ -201,15 +251,15 @@ async function run() {
dark_icons[file.name] = replace_colors(dark_colors, file.contents);
});
console.log('Ensuring output directory...');
console.log("Ensuring output directory...");
ensure_paths();
console.log('Writing icons to output directory...');
console.log("Writing icons to output directory...");
for (const [file, contents] of Object.entries(light_icons)) {
fs.writeFileSync(join(outputPath, 'light', file), contents);
fs.writeFileSync(join(outputPath, "light", file), contents);
}
for (const [file, contents] of Object.entries(dark_icons)) {
fs.writeFileSync(join(outputPath, 'dark', file), contents);
fs.writeFileSync(join(outputPath, "dark", file), contents);
}
}