Browse Source

Generate script resource preview without parsing

Yuri Sizov 1 year ago
parent
commit
9c919ea285

+ 12 - 0
core/object/script_language.cpp

@@ -168,6 +168,18 @@ ScriptLanguage *ScriptServer::get_language(int p_idx) {
 	return _languages[p_idx];
 }
 
+ScriptLanguage *ScriptServer::get_language_for_extension(const String &p_extension) {
+	MutexLock lock(languages_mutex);
+
+	for (int i = 0; i < _language_count; i++) {
+		if (_languages[i] && _languages[i]->get_extension() == p_extension) {
+			return _languages[i];
+		}
+	}
+
+	return nullptr;
+}
+
 Error ScriptServer::register_language(ScriptLanguage *p_language) {
 	MutexLock lock(languages_mutex);
 	ERR_FAIL_NULL_V(p_language, ERR_INVALID_PARAMETER);

+ 1 - 0
core/object/script_language.h

@@ -75,6 +75,7 @@ public:
 	static bool is_scripting_enabled();
 	_FORCE_INLINE_ static int get_language_count() { return _language_count; }
 	static ScriptLanguage *get_language(int p_idx);
+	static ScriptLanguage *get_language_for_extension(const String &p_extension);
 	static Error register_language(ScriptLanguage *p_language);
 	static Error unregister_language(const ScriptLanguage *p_language);
 

+ 27 - 10
editor/plugins/editor_preview_plugins.cpp

@@ -464,6 +464,17 @@ bool EditorScriptPreviewPlugin::handles(const String &p_type) const {
 	return ClassDB::is_parent_class(p_type, "Script");
 }
 
+Ref<Texture2D> EditorScriptPreviewPlugin::generate_from_path(const String &p_path, const Size2 &p_size, Dictionary &p_metadata) const {
+	Error err;
+	String code = FileAccess::get_file_as_string(p_path, &err);
+	if (err != OK) {
+		return Ref<Texture2D>();
+	}
+
+	ScriptLanguage *lang = ScriptServer::get_language_for_extension(p_path.get_extension());
+	return _generate_from_source_code(lang, code, p_size, p_metadata);
+}
+
 Ref<Texture2D> EditorScriptPreviewPlugin::generate(const Ref<Resource> &p_from, const Size2 &p_size, Dictionary &p_metadata) const {
 	Ref<Script> scr = p_from;
 	if (scr.is_null()) {
@@ -471,18 +482,24 @@ Ref<Texture2D> EditorScriptPreviewPlugin::generate(const Ref<Resource> &p_from,
 	}
 
 	String code = scr->get_source_code().strip_edges();
-	if (code.is_empty()) {
+	return _generate_from_source_code(scr->get_language(), code, p_size, p_metadata);
+}
+
+Ref<Texture2D> EditorScriptPreviewPlugin::_generate_from_source_code(const ScriptLanguage *p_language, const String &p_source_code, const Size2 &p_size, Dictionary &p_metadata) const {
+	if (p_source_code.is_empty()) {
 		return Ref<Texture2D>();
 	}
 
 	List<String> kwors;
-	scr->get_language()->get_reserved_words(&kwors);
+	if (p_language) {
+		p_language->get_reserved_words(&kwors);
+	}
 
 	HashSet<String> control_flow_keywords;
 	HashSet<String> keywords;
 
 	for (const String &E : kwors) {
-		if (scr->get_language()->is_control_flow_keyword(E)) {
+		if (p_language && p_language->is_control_flow_keyword(E)) {
 			control_flow_keywords.insert(E);
 		} else {
 			keywords.insert(E);
@@ -505,7 +522,7 @@ Ref<Texture2D> EditorScriptPreviewPlugin::generate(const Ref<Resource> &p_from,
 	if (bg_color.a == 0) {
 		bg_color = Color(0, 0, 0, 0);
 	}
-	bg_color.a = MAX(bg_color.a, 0.2); // some background
+	bg_color.a = MAX(bg_color.a, 0.2); // Ensure we have some background, regardless of the text editor setting.
 
 	img->fill(bg_color);
 
@@ -519,14 +536,14 @@ Ref<Texture2D> EditorScriptPreviewPlugin::generate(const Ref<Resource> &p_from,
 	bool in_keyword = false;
 	bool in_comment = false;
 	bool in_doc_comment = false;
-	for (int i = 0; i < code.length(); i++) {
-		char32_t c = code[i];
+	for (int i = 0; i < p_source_code.length(); i++) {
+		char32_t c = p_source_code[i];
 		if (c > 32) {
 			if (col < thumbnail_size) {
 				Color color = text_color;
 
 				if (c == '#') {
-					if (i < code.length() - 1 && code[i + 1] == '#') {
+					if (i < p_source_code.length() - 1 && p_source_code[i + 1] == '#') {
 						in_doc_comment = true;
 					} else {
 						in_comment = true;
@@ -539,17 +556,17 @@ Ref<Texture2D> EditorScriptPreviewPlugin::generate(const Ref<Resource> &p_from,
 					color = doc_comment_color;
 				} else {
 					if (is_symbol(c)) {
-						//make symbol a little visible
+						// Make symbol a little visible.
 						color = symbol_color;
 						in_control_flow_keyword = false;
 						in_keyword = false;
 					} else if (!prev_is_text && is_ascii_identifier_char(c)) {
 						int pos = i;
 
-						while (is_ascii_identifier_char(code[pos])) {
+						while (is_ascii_identifier_char(p_source_code[pos])) {
 							pos++;
 						}
-						String word = code.substr(i, pos - i);
+						String word = p_source_code.substr(i, pos - i);
 						if (control_flow_keywords.has(word)) {
 							in_control_flow_keyword = true;
 						} else if (keywords.has(word)) {

+ 5 - 0
editor/plugins/editor_preview_plugins.h

@@ -34,6 +34,8 @@
 #include "core/templates/safe_refcount.h"
 #include "editor/editor_resource_preview.h"
 
+class ScriptLanguage;
+
 void post_process_preview(Ref<Image> p_image);
 
 class EditorTexturePreviewPlugin : public EditorResourcePreviewGenerator {
@@ -112,9 +114,12 @@ public:
 class EditorScriptPreviewPlugin : public EditorResourcePreviewGenerator {
 	GDCLASS(EditorScriptPreviewPlugin, EditorResourcePreviewGenerator);
 
+	Ref<Texture2D> _generate_from_source_code(const ScriptLanguage *p_language, const String &p_source_code, const Size2 &p_size, Dictionary &p_metadata) const;
+
 public:
 	virtual bool handles(const String &p_type) const override;
 	virtual Ref<Texture2D> generate(const Ref<Resource> &p_from, const Size2 &p_size, Dictionary &p_metadata) const override;
+	virtual Ref<Texture2D> generate_from_path(const String &p_path, const Size2 &p_size, Dictionary &p_metadata) const override;
 
 	EditorScriptPreviewPlugin();
 };