summaryrefslogtreecommitdiffstats
path: root/modules/gdscript/editor
diff options
context:
space:
mode:
Diffstat (limited to 'modules/gdscript/editor')
-rw-r--r--modules/gdscript/editor/gdscript_docgen.cpp200
-rw-r--r--modules/gdscript/editor/gdscript_highlighter.cpp182
-rw-r--r--modules/gdscript/editor/gdscript_highlighter.h10
-rw-r--r--modules/gdscript/editor/gdscript_translation_parser_plugin.cpp11
-rw-r--r--modules/gdscript/editor/script_templates/CharacterBody2D/basic_movement.gd2
-rw-r--r--modules/gdscript/editor/script_templates/CharacterBody3D/basic_movement.gd2
-rw-r--r--modules/gdscript/editor/script_templates/EditorPlugin/plugin.gd3
-rw-r--r--modules/gdscript/editor/script_templates/EditorScenePostImport/basic_import_script.gd3
-rw-r--r--modules/gdscript/editor/script_templates/EditorScenePostImport/no_comments.gd3
-rw-r--r--modules/gdscript/editor/script_templates/EditorScript/basic_editor_script.gd3
-rw-r--r--modules/gdscript/editor/script_templates/RichTextEffect/default.gd7
-rw-r--r--modules/gdscript/editor/script_templates/VisualShaderNodeCustom/basic.gd9
12 files changed, 307 insertions, 128 deletions
diff --git a/modules/gdscript/editor/gdscript_docgen.cpp b/modules/gdscript/editor/gdscript_docgen.cpp
index 26f326838c..0b440274c0 100644
--- a/modules/gdscript/editor/gdscript_docgen.cpp
+++ b/modules/gdscript/editor/gdscript_docgen.cpp
@@ -36,19 +36,19 @@ using GDP = GDScriptParser;
using GDType = GDP::DataType;
static String _get_script_path(const String &p_path) {
- return vformat(R"("%s")", p_path.get_slice("://", 1));
+ return p_path.trim_prefix("res://").quote();
}
static String _get_class_name(const GDP::ClassNode &p_class) {
const GDP::ClassNode *curr_class = &p_class;
- if (!curr_class->identifier) { // All inner classes have a identifier, so this is the outer class
+ if (!curr_class->identifier) { // All inner classes have an identifier, so this is the outer class.
return _get_script_path(curr_class->fqcn);
}
String full_name = curr_class->identifier->name;
while (curr_class->outer) {
curr_class = curr_class->outer;
- if (!curr_class->identifier) { // All inner classes have a identifier, so this is the outer class
+ if (!curr_class->identifier) { // All inner classes have an identifier, so this is the outer class.
return vformat("%s.%s", _get_script_path(curr_class->fqcn), full_name);
}
full_name = vformat("%s.%s", curr_class->identifier->name, full_name);
@@ -56,20 +56,71 @@ static String _get_class_name(const GDP::ClassNode &p_class) {
return full_name;
}
-static PropertyInfo _property_info_from_datatype(const GDType &p_type) {
- PropertyInfo pi;
- pi.type = p_type.builtin_type;
- if (p_type.kind == GDType::CLASS) {
- pi.class_name = _get_class_name(*p_type.class_type);
- } else if (p_type.kind == GDType::ENUM && p_type.enum_type != StringName()) {
- pi.type = Variant::INT; // Only int types are recognized as enums by the EditorHelp
- pi.usage |= PROPERTY_USAGE_CLASS_IS_ENUM;
- // Replace :: from enum's use of fully qualified class names with regular .
- pi.class_name = String(p_type.native_type).replace("::", ".");
- } else if (p_type.kind == GDType::NATIVE) {
- pi.class_name = p_type.native_type;
+static void _doctype_from_gdtype(const GDType &p_gdtype, String &r_type, String &r_enum, bool p_is_return = false) {
+ if (!p_gdtype.is_hard_type()) {
+ r_type = "Variant";
+ return;
+ }
+ switch (p_gdtype.kind) {
+ case GDType::BUILTIN:
+ if (p_gdtype.builtin_type == Variant::NIL) {
+ r_type = p_is_return ? "void" : "null";
+ return;
+ }
+ if (p_gdtype.builtin_type == Variant::ARRAY && p_gdtype.has_container_element_type()) {
+ _doctype_from_gdtype(p_gdtype.get_container_element_type(), r_type, r_enum);
+ if (!r_enum.is_empty()) {
+ r_type = "int[]";
+ r_enum += "[]";
+ return;
+ }
+ if (!r_type.is_empty() && r_type != "Variant") {
+ r_type += "[]";
+ return;
+ }
+ }
+ r_type = Variant::get_type_name(p_gdtype.builtin_type);
+ return;
+ case GDType::NATIVE:
+ r_type = p_gdtype.native_type;
+ return;
+ case GDType::SCRIPT:
+ if (p_gdtype.script_type.is_valid()) {
+ if (p_gdtype.script_type->get_global_name() != StringName()) {
+ r_type = p_gdtype.script_type->get_global_name();
+ return;
+ }
+ if (!p_gdtype.script_type->get_path().is_empty()) {
+ r_type = _get_script_path(p_gdtype.script_type->get_path());
+ return;
+ }
+ }
+ if (!p_gdtype.script_path.is_empty()) {
+ r_type = _get_script_path(p_gdtype.script_path);
+ return;
+ }
+ r_type = "Object";
+ return;
+ case GDType::CLASS:
+ r_type = _get_class_name(*p_gdtype.class_type);
+ return;
+ case GDType::ENUM:
+ r_type = "int";
+ r_enum = String(p_gdtype.native_type).replace("::", ".");
+ if (r_enum.begins_with("res://")) {
+ r_enum = r_enum.trim_prefix("res://");
+ int dot_pos = r_enum.rfind(".");
+ if (dot_pos >= 0) {
+ r_enum = r_enum.left(dot_pos).quote() + r_enum.substr(dot_pos);
+ }
+ }
+ return;
+ case GDType::VARIANT:
+ case GDType::RESOLVING:
+ case GDType::UNRESOLVED:
+ r_type = "Variant";
+ return;
}
- return pi;
}
void GDScriptDocGen::generate_docs(GDScript *p_script, const GDP::ClassNode *p_class) {
@@ -78,10 +129,10 @@ void GDScriptDocGen::generate_docs(GDScript *p_script, const GDP::ClassNode *p_c
DocData::ClassDoc &doc = p_script->doc;
doc.script_path = _get_script_path(p_script->get_script_path());
- if (p_script->name.is_empty()) {
+ if (p_script->local_name == StringName()) {
doc.name = doc.script_path;
} else {
- doc.name = p_script->name;
+ doc.name = p_script->local_name;
}
if (p_script->_owner) {
@@ -120,8 +171,8 @@ void GDScriptDocGen::generate_docs(GDScript *p_script, const GDP::ClassNode *p_c
p_script->member_lines[class_name] = inner_class->start_line;
- // Recursively generate inner class docs
- // Needs inner GDScripts to exist: previously generated in GDScriptCompiler::make_scripts()
+ // Recursively generate inner class docs.
+ // Needs inner GDScripts to exist: previously generated in GDScriptCompiler::make_scripts().
GDScriptDocGen::generate_docs(*p_script->subclasses[class_name], inner_class);
} break;
@@ -144,22 +195,36 @@ void GDScriptDocGen::generate_docs(GDScript *p_script, const GDP::ClassNode *p_c
p_script->member_lines[func_name] = m_func->start_line;
- MethodInfo mi;
- mi.name = func_name;
+ DocData::MethodDoc method_doc;
+ method_doc.name = func_name;
+ method_doc.description = m_func->doc_data.description;
+ method_doc.is_deprecated = m_func->doc_data.is_deprecated;
+ method_doc.is_experimental = m_func->doc_data.is_experimental;
+ method_doc.qualifiers = m_func->is_static ? "static" : "";
if (m_func->return_type) {
- mi.return_val = _property_info_from_datatype(m_func->return_type->get_datatype());
+ _doctype_from_gdtype(m_func->return_type->get_datatype(), method_doc.return_type, method_doc.return_enum, true);
+ } else if (!m_func->body->has_return) {
+ // If no `return` statement, then return type is `void`, not `Variant`.
+ method_doc.return_type = "void";
+ } else {
+ method_doc.return_type = "Variant";
}
+
for (const GDScriptParser::ParameterNode *p : m_func->parameters) {
- PropertyInfo pi = _property_info_from_datatype(p->get_datatype());
- pi.name = p->identifier->name;
- mi.arguments.push_back(pi);
+ DocData::ArgumentDoc arg_doc;
+ arg_doc.name = p->identifier->name;
+ _doctype_from_gdtype(p->get_datatype(), arg_doc.type, arg_doc.enumeration);
+ if (p->initializer != nullptr) {
+ if (p->initializer->is_constant) {
+ arg_doc.default_value = p->initializer->reduced_value.get_construct_string().replace("\n", "\\n");
+ } else {
+ arg_doc.default_value = "<unknown>";
+ }
+ }
+ method_doc.arguments.push_back(arg_doc);
}
- DocData::MethodDoc method_doc;
- DocData::method_doc_from_methodinfo(method_doc, mi, m_func->doc_data.description);
- method_doc.is_deprecated = m_func->doc_data.is_deprecated;
- method_doc.is_experimental = m_func->doc_data.is_experimental;
doc.methods.push_back(method_doc);
} break;
@@ -169,18 +234,19 @@ void GDScriptDocGen::generate_docs(GDScript *p_script, const GDP::ClassNode *p_c
p_script->member_lines[signal_name] = m_signal->start_line;
- MethodInfo mi;
- mi.name = signal_name;
- for (const GDScriptParser::ParameterNode *p : m_signal->parameters) {
- PropertyInfo pi = _property_info_from_datatype(p->get_datatype());
- pi.name = p->identifier->name;
- mi.arguments.push_back(pi);
- }
-
DocData::MethodDoc signal_doc;
- DocData::signal_doc_from_methodinfo(signal_doc, mi, m_signal->doc_data.description);
+ signal_doc.name = signal_name;
+ signal_doc.description = m_signal->doc_data.description;
signal_doc.is_deprecated = m_signal->doc_data.is_deprecated;
signal_doc.is_experimental = m_signal->doc_data.is_experimental;
+
+ for (const GDScriptParser::ParameterNode *p : m_signal->parameters) {
+ DocData::ArgumentDoc arg_doc;
+ arg_doc.name = p->identifier->name;
+ _doctype_from_gdtype(p->get_datatype(), arg_doc.type, arg_doc.enumeration);
+ signal_doc.arguments.push_back(arg_doc);
+ }
+
doc.signals.push_back(signal_doc);
} break;
@@ -191,50 +257,41 @@ void GDScriptDocGen::generate_docs(GDScript *p_script, const GDP::ClassNode *p_c
p_script->member_lines[var_name] = m_var->start_line;
DocData::PropertyDoc prop_doc;
-
prop_doc.name = var_name;
prop_doc.description = m_var->doc_data.description;
prop_doc.is_deprecated = m_var->doc_data.is_deprecated;
prop_doc.is_experimental = m_var->doc_data.is_experimental;
+ _doctype_from_gdtype(m_var->get_datatype(), prop_doc.type, prop_doc.enumeration);
- GDType dt = m_var->get_datatype();
- switch (dt.kind) {
- case GDType::CLASS:
- prop_doc.type = _get_class_name(*dt.class_type);
+ switch (m_var->property) {
+ case GDP::VariableNode::PROP_NONE:
break;
- case GDType::VARIANT:
- prop_doc.type = "Variant";
+ case GDP::VariableNode::PROP_INLINE:
+ if (m_var->setter != nullptr) {
+ prop_doc.setter = m_var->setter->identifier->name;
+ }
+ if (m_var->getter != nullptr) {
+ prop_doc.getter = m_var->getter->identifier->name;
+ }
break;
- case GDType::ENUM:
- prop_doc.type = Variant::get_type_name(dt.builtin_type);
- // Replace :: from enum's use of fully qualified class names with regular .
- prop_doc.enumeration = String(dt.native_type).replace("::", ".");
- break;
- case GDType::NATIVE:;
- prop_doc.type = dt.native_type;
- break;
- case GDType::BUILTIN:
- prop_doc.type = Variant::get_type_name(dt.builtin_type);
- break;
- default:
- // SCRIPT: can be preload()'d and perhaps used as types directly?
- // RESOLVING & UNRESOLVED should never happen since docgen requires analyzing w/o errors
+ case GDP::VariableNode::PROP_SETGET:
+ if (m_var->setter_pointer != nullptr) {
+ prop_doc.setter = m_var->setter_pointer->name;
+ }
+ if (m_var->getter_pointer != nullptr) {
+ prop_doc.getter = m_var->getter_pointer->name;
+ }
break;
}
- if (m_var->property == GDP::VariableNode::PROP_SETGET) {
- if (m_var->setter_pointer != nullptr) {
- prop_doc.setter = m_var->setter_pointer->name;
- }
- if (m_var->getter_pointer != nullptr) {
- prop_doc.getter = m_var->getter_pointer->name;
+ if (m_var->initializer) {
+ if (m_var->initializer->is_constant) {
+ prop_doc.default_value = m_var->initializer->reduced_value.get_construct_string().replace("\n", "\\n");
+ } else {
+ prop_doc.default_value = "<unknown>";
}
}
- if (m_var->initializer && m_var->initializer->is_constant) {
- prop_doc.default_value = m_var->initializer->reduced_value.get_construct_string().replace("\n", "");
- }
-
prop_doc.overridden = false;
doc.properties.push_back(prop_doc);
@@ -280,8 +337,7 @@ void GDScriptDocGen::generate_docs(GDScript *p_script, const GDP::ClassNode *p_c
const_doc.is_experimental = m_enum_val.doc_data.is_experimental;
doc.constants.push_back(const_doc);
} break;
- case GDP::ClassNode::Member::GROUP:
- case GDP::ClassNode::Member::UNDEFINED:
+
default:
break;
}
diff --git a/modules/gdscript/editor/gdscript_highlighter.cpp b/modules/gdscript/editor/gdscript_highlighter.cpp
index b54dc502ae..1be690d894 100644
--- a/modules/gdscript/editor/gdscript_highlighter.cpp
+++ b/modules/gdscript/editor/gdscript_highlighter.cpp
@@ -52,6 +52,7 @@ Dictionary GDScriptSyntaxHighlighter::_get_line_syntax_highlighting_impl(int p_l
bool in_keyword = false;
bool in_word = false;
bool in_number = false;
+ bool in_raw_string = false;
bool in_node_path = false;
bool in_node_ref = false;
bool in_annotation = false;
@@ -145,6 +146,10 @@ Dictionary GDScriptSyntaxHighlighter::_get_line_syntax_highlighting_impl(int p_l
// Check if it's the whole line.
if (end_key_length == 0 || color_regions[c].line_only || from + end_key_length > line_length) {
+ // Don't skip comments, for highlighting markers.
+ if (color_regions[in_region].start_key == "#") {
+ break;
+ }
if (from + end_key_length > line_length) {
// If it's key length and there is a '\', dont skip to highlight esc chars.
if (str.find("\\", from) >= 0) {
@@ -163,7 +168,8 @@ Dictionary GDScriptSyntaxHighlighter::_get_line_syntax_highlighting_impl(int p_l
break;
}
- if (j == line_length) {
+ // Don't skip comments, for highlighting markers.
+ if (j == line_length && color_regions[in_region].start_key != "#") {
continue;
}
}
@@ -185,56 +191,101 @@ Dictionary GDScriptSyntaxHighlighter::_get_line_syntax_highlighting_impl(int p_l
highlighter_info["color"] = region_color;
color_map[j] = highlighter_info;
- // Search the line.
- int region_end_index = -1;
- int end_key_length = color_regions[in_region].end_key.length();
- const char32_t *end_key = color_regions[in_region].end_key.get_data();
- for (; from < line_length; from++) {
- if (line_length - from < end_key_length) {
- // Don't break if '\' to highlight esc chars.
- if (str.find("\\", from) < 0) {
- break;
+ if (color_regions[in_region].start_key == "#") {
+ int marker_start_pos = from;
+ int marker_len = 0;
+ while (from <= line_length) {
+ if (from < line_length && is_unicode_identifier_continue(str[from])) {
+ marker_len++;
+ } else {
+ if (marker_len > 0) {
+ HashMap<String, CommentMarkerLevel>::ConstIterator E = comment_markers.find(str.substr(marker_start_pos, marker_len));
+ if (E) {
+ Dictionary marker_highlighter_info;
+ marker_highlighter_info["color"] = comment_marker_colors[E->value];
+ color_map[marker_start_pos] = marker_highlighter_info;
+
+ Dictionary marker_continue_highlighter_info;
+ marker_continue_highlighter_info["color"] = region_color;
+ color_map[from] = marker_continue_highlighter_info;
+ }
+ }
+ marker_start_pos = from + 1;
+ marker_len = 0;
}
+ from++;
}
+ from = line_length - 1;
+ j = from;
+ } else {
+ // Search the line.
+ int region_end_index = -1;
+ int end_key_length = color_regions[in_region].end_key.length();
+ const char32_t *end_key = color_regions[in_region].end_key.get_data();
+ for (; from < line_length; from++) {
+ if (line_length - from < end_key_length) {
+ // Don't break if '\' to highlight esc chars.
+ if (str.find("\\", from) < 0) {
+ break;
+ }
+ }
- if (!is_symbol(str[from])) {
- continue;
- }
+ if (!is_symbol(str[from])) {
+ continue;
+ }
- if (str[from] == '\\') {
- Dictionary escape_char_highlighter_info;
- escape_char_highlighter_info["color"] = symbol_color;
- color_map[from] = escape_char_highlighter_info;
+ if (str[from] == '\\') {
+ if (!in_raw_string) {
+ Dictionary escape_char_highlighter_info;
+ escape_char_highlighter_info["color"] = symbol_color;
+ color_map[from] = escape_char_highlighter_info;
+ }
- from++;
+ from++;
+
+ if (!in_raw_string) {
+ int esc_len = 0;
+ if (str[from] == 'u') {
+ esc_len = 4;
+ } else if (str[from] == 'U') {
+ esc_len = 6;
+ }
+ for (int k = 0; k < esc_len && from < line_length - 1; k++) {
+ if (!is_hex_digit(str[from + 1])) {
+ break;
+ }
+ from++;
+ }
+
+ Dictionary region_continue_highlighter_info;
+ region_continue_highlighter_info["color"] = region_color;
+ color_map[from + 1] = region_continue_highlighter_info;
+ }
- Dictionary region_continue_highlighter_info;
- prev_color = region_color;
- region_continue_highlighter_info["color"] = region_color;
- color_map[from + 1] = region_continue_highlighter_info;
- continue;
- }
+ continue;
+ }
- region_end_index = from;
- for (int k = 0; k < end_key_length; k++) {
- if (end_key[k] != str[from + k]) {
- region_end_index = -1;
+ region_end_index = from;
+ for (int k = 0; k < end_key_length; k++) {
+ if (end_key[k] != str[from + k]) {
+ region_end_index = -1;
+ break;
+ }
+ }
+
+ if (region_end_index != -1) {
break;
}
}
-
- if (region_end_index != -1) {
- break;
+ j = from + (end_key_length - 1);
+ if (region_end_index == -1) {
+ color_region_cache[p_line] = in_region;
}
}
prev_type = REGION;
prev_text = "";
prev_column = j;
- j = from + (end_key_length - 1);
- if (region_end_index == -1) {
- color_region_cache[p_line] = in_region;
- }
in_region = -1;
prev_is_char = false;
@@ -272,7 +323,7 @@ Dictionary GDScriptSyntaxHighlighter::_get_line_syntax_highlighting_impl(int p_l
// Allow ABCDEF in hex notation.
if (is_hex_notation && (is_hex_digit(str[j]) || is_a_digit)) {
is_a_digit = true;
- } else {
+ } else if (str[j] != '_') {
is_hex_notation = false;
}
@@ -295,14 +346,14 @@ Dictionary GDScriptSyntaxHighlighter::_get_line_syntax_highlighting_impl(int p_l
} else if (!((str[j] == '-' || str[j] == '+') && str[j - 1] == 'e' && !prev_is_digit) &&
!(str[j] == '_' && (prev_is_digit || str[j - 1] == 'b' || str[j - 1] == 'x' || str[j - 1] == '.')) &&
!(str[j] == 'e' && (prev_is_digit || str[j - 1] == '_')) &&
- !(str[j] == '.' && (prev_is_digit || (!prev_is_binary_op && (j > 0 && (str[j - 1] == '-' || str[j - 1] == '+' || str[j - 1] == '~'))))) &&
+ !(str[j] == '.' && (prev_is_digit || (!prev_is_binary_op && (j > 0 && (str[j - 1] == '_' || str[j - 1] == '-' || str[j - 1] == '+' || str[j - 1] == '~'))))) &&
!((str[j] == '-' || str[j] == '+' || str[j] == '~') && !is_binary_op && !prev_is_binary_op && str[j - 1] != 'e')) {
/* This condition continues number highlighting in special cases.
1st row: '+' or '-' after scientific notation (like 3e-4);
2nd row: '_' as a numeric separator;
3rd row: Scientific notation 'e' and floating points;
4th row: Floating points inside the number, or leading if after a unary mathematical operator;
- 5th row: Multiple unary mathematical operators (like ~-7)*/
+ 5th row: Multiple unary mathematical operators (like ~-7) */
in_number = false;
}
} else if (str[j] == '.' && !is_binary_op && is_digit(str[j + 1]) && (j == 0 || (j > 0 && str[j - 1] != '.'))) {
@@ -457,6 +508,12 @@ Dictionary GDScriptSyntaxHighlighter::_get_line_syntax_highlighting_impl(int p_l
in_member_variable = false;
}
+ if (!in_raw_string && in_region == -1 && str[j] == 'r' && j < line_length - 1 && (str[j + 1] == '"' || str[j + 1] == '\'')) {
+ in_raw_string = true;
+ } else if (in_raw_string && in_region == -1) {
+ in_raw_string = false;
+ }
+
// Keep symbol color for binary '&&'. In the case of '&&&' use StringName color for the last ampersand.
if (!in_string_name && in_region == -1 && str[j] == '&' && !is_binary_op) {
if (j >= 2 && str[j - 1] == '&' && str[j - 2] != '&' && prev_is_binary_op) {
@@ -488,7 +545,9 @@ Dictionary GDScriptSyntaxHighlighter::_get_line_syntax_highlighting_impl(int p_l
in_annotation = false;
}
- if (in_node_ref) {
+ if (in_raw_string) {
+ color = string_color;
+ } else if (in_node_ref) {
next_type = NODE_REF;
color = node_ref_color;
} else if (in_annotation) {
@@ -660,7 +719,7 @@ void GDScriptSyntaxHighlighter::_update_cache() {
}
/* Strings */
- const Color string_color = EDITOR_GET("text_editor/theme/highlighting/string_color");
+ string_color = EDITOR_GET("text_editor/theme/highlighting/string_color");
List<String> strings;
gdscript->get_string_delimiters(&strings);
for (const String &string : strings) {
@@ -706,6 +765,9 @@ void GDScriptSyntaxHighlighter::_update_cache() {
node_ref_color = Color(0.39, 0.76, 0.35);
annotation_color = Color(1.0, 0.7, 0.45);
string_name_color = Color(1.0, 0.76, 0.65);
+ comment_marker_colors[COMMENT_MARKER_CRITICAL] = Color(0.77, 0.35, 0.35);
+ comment_marker_colors[COMMENT_MARKER_WARNING] = Color(0.72, 0.61, 0.48);
+ comment_marker_colors[COMMENT_MARKER_NOTICE] = Color(0.56, 0.67, 0.51);
} else {
function_definition_color = Color(0, 0.6, 0.6);
global_function_color = Color(0.36, 0.18, 0.72);
@@ -713,6 +775,9 @@ void GDScriptSyntaxHighlighter::_update_cache() {
node_ref_color = Color(0.0, 0.5, 0);
annotation_color = Color(0.8, 0.37, 0);
string_name_color = Color(0.8, 0.56, 0.45);
+ comment_marker_colors[COMMENT_MARKER_CRITICAL] = Color(0.8, 0.14, 0.14);
+ comment_marker_colors[COMMENT_MARKER_WARNING] = Color(0.75, 0.39, 0.03);
+ comment_marker_colors[COMMENT_MARKER_NOTICE] = Color(0.24, 0.54, 0.09);
}
EDITOR_DEF("text_editor/theme/highlighting/gdscript/function_definition_color", function_definition_color);
@@ -721,6 +786,14 @@ void GDScriptSyntaxHighlighter::_update_cache() {
EDITOR_DEF("text_editor/theme/highlighting/gdscript/node_reference_color", node_ref_color);
EDITOR_DEF("text_editor/theme/highlighting/gdscript/annotation_color", annotation_color);
EDITOR_DEF("text_editor/theme/highlighting/gdscript/string_name_color", string_name_color);
+ EDITOR_DEF("text_editor/theme/highlighting/comment_markers/critical_color", comment_marker_colors[COMMENT_MARKER_CRITICAL]);
+ EDITOR_DEF("text_editor/theme/highlighting/comment_markers/warning_color", comment_marker_colors[COMMENT_MARKER_WARNING]);
+ EDITOR_DEF("text_editor/theme/highlighting/comment_markers/notice_color", comment_marker_colors[COMMENT_MARKER_NOTICE]);
+ // The list is based on <https://github.com/KDE/syntax-highlighting/blob/master/data/syntax/alert.xml>.
+ EDITOR_DEF("text_editor/theme/highlighting/comment_markers/critical_list", "ALERT,ATTENTION,CAUTION,CRITICAL,DANGER,SECURITY");
+ EDITOR_DEF("text_editor/theme/highlighting/comment_markers/warning_list", "BUG,DEPRECATED,FIXME,HACK,TASK,TBD,TODO,WARNING");
+ EDITOR_DEF("text_editor/theme/highlighting/comment_markers/notice_list", "INFO,NOTE,NOTICE,TEST,TESTING");
+
if (text_edit_color_theme == "Default" || godot_2_theme) {
EditorSettings::get_singleton()->set_initial_value(
"text_editor/theme/highlighting/gdscript/function_definition_color",
@@ -746,6 +819,18 @@ void GDScriptSyntaxHighlighter::_update_cache() {
"text_editor/theme/highlighting/gdscript/string_name_color",
string_name_color,
true);
+ EditorSettings::get_singleton()->set_initial_value(
+ "text_editor/theme/highlighting/comment_markers/critical_color",
+ comment_marker_colors[COMMENT_MARKER_CRITICAL],
+ true);
+ EditorSettings::get_singleton()->set_initial_value(
+ "text_editor/theme/highlighting/comment_markers/warning_color",
+ comment_marker_colors[COMMENT_MARKER_WARNING],
+ true);
+ EditorSettings::get_singleton()->set_initial_value(
+ "text_editor/theme/highlighting/comment_markers/notice_color",
+ comment_marker_colors[COMMENT_MARKER_NOTICE],
+ true);
}
function_definition_color = EDITOR_GET("text_editor/theme/highlighting/gdscript/function_definition_color");
@@ -755,6 +840,23 @@ void GDScriptSyntaxHighlighter::_update_cache() {
annotation_color = EDITOR_GET("text_editor/theme/highlighting/gdscript/annotation_color");
string_name_color = EDITOR_GET("text_editor/theme/highlighting/gdscript/string_name_color");
type_color = EDITOR_GET("text_editor/theme/highlighting/base_type_color");
+ comment_marker_colors[COMMENT_MARKER_CRITICAL] = EDITOR_GET("text_editor/theme/highlighting/comment_markers/critical_color");
+ comment_marker_colors[COMMENT_MARKER_WARNING] = EDITOR_GET("text_editor/theme/highlighting/comment_markers/warning_color");
+ comment_marker_colors[COMMENT_MARKER_NOTICE] = EDITOR_GET("text_editor/theme/highlighting/comment_markers/notice_color");
+
+ comment_markers.clear();
+ Vector<String> critical_list = EDITOR_GET("text_editor/theme/highlighting/comment_markers/critical_list").operator String().split(",", false);
+ for (int i = 0; i < critical_list.size(); i++) {
+ comment_markers[critical_list[i]] = COMMENT_MARKER_CRITICAL;
+ }
+ Vector<String> warning_list = EDITOR_GET("text_editor/theme/highlighting/comment_markers/warning_list").operator String().split(",", false);
+ for (int i = 0; i < warning_list.size(); i++) {
+ comment_markers[warning_list[i]] = COMMENT_MARKER_WARNING;
+ }
+ Vector<String> notice_list = EDITOR_GET("text_editor/theme/highlighting/comment_markers/notice_list").operator String().split(",", false);
+ for (int i = 0; i < notice_list.size(); i++) {
+ comment_markers[notice_list[i]] = COMMENT_MARKER_NOTICE;
+ }
}
void GDScriptSyntaxHighlighter::add_color_region(const String &p_start_key, const String &p_end_key, const Color &p_color, bool p_line_only) {
diff --git a/modules/gdscript/editor/gdscript_highlighter.h b/modules/gdscript/editor/gdscript_highlighter.h
index aceb644658..090857f397 100644
--- a/modules/gdscript/editor/gdscript_highlighter.h
+++ b/modules/gdscript/editor/gdscript_highlighter.h
@@ -78,12 +78,22 @@ private:
Color built_in_type_color;
Color number_color;
Color member_color;
+ Color string_color;
Color node_path_color;
Color node_ref_color;
Color annotation_color;
Color string_name_color;
Color type_color;
+ enum CommentMarkerLevel {
+ COMMENT_MARKER_CRITICAL,
+ COMMENT_MARKER_WARNING,
+ COMMENT_MARKER_NOTICE,
+ COMMENT_MARKER_MAX,
+ };
+ Color comment_marker_colors[COMMENT_MARKER_MAX];
+ HashMap<String, CommentMarkerLevel> comment_markers;
+
void add_color_region(const String &p_start_key, const String &p_end_key, const Color &p_color, bool p_line_only = false);
public:
diff --git a/modules/gdscript/editor/gdscript_translation_parser_plugin.cpp b/modules/gdscript/editor/gdscript_translation_parser_plugin.cpp
index 064143f400..becc2876f9 100644
--- a/modules/gdscript/editor/gdscript_translation_parser_plugin.cpp
+++ b/modules/gdscript/editor/gdscript_translation_parser_plugin.cpp
@@ -225,10 +225,15 @@ void GDScriptEditorTranslationParserPlugin::_assess_assignment(const GDScriptPar
if (p_assignment->assignee->type == GDScriptParser::Node::IDENTIFIER) {
assignee_name = static_cast<const GDScriptParser::IdentifierNode *>(p_assignment->assignee)->name;
} else if (p_assignment->assignee->type == GDScriptParser::Node::SUBSCRIPT) {
- assignee_name = static_cast<const GDScriptParser::SubscriptNode *>(p_assignment->assignee)->attribute->name;
+ const GDScriptParser::SubscriptNode *subscript = static_cast<const GDScriptParser::SubscriptNode *>(p_assignment->assignee);
+ if (subscript->is_attribute && subscript->attribute) {
+ assignee_name = subscript->attribute->name;
+ } else if (subscript->index && _is_constant_string(subscript->index)) {
+ assignee_name = subscript->index->reduced_value;
+ }
}
- if (assignment_patterns.has(assignee_name) && _is_constant_string(p_assignment->assigned_value)) {
+ if (assignee_name != StringName() && assignment_patterns.has(assignee_name) && _is_constant_string(p_assignment->assigned_value)) {
// If the assignment is towards one of the extract patterns (text, tooltip_text etc.), and the value is a constant string, we collect the string.
ids->push_back(p_assignment->assigned_value->reduced_value);
} else if (assignee_name == fd_filters && p_assignment->assigned_value->type == GDScriptParser::Node::CALL) {
@@ -236,7 +241,7 @@ void GDScriptEditorTranslationParserPlugin::_assess_assignment(const GDScriptPar
// get_node("FileDialog").filters = PackedStringArray(["*.png ; PNG Images","*.gd ; GDScript Files"]).
const GDScriptParser::CallNode *call_node = static_cast<const GDScriptParser::CallNode *>(p_assignment->assigned_value);
- if (call_node->arguments[0]->type == GDScriptParser::Node::ARRAY) {
+ if (!call_node->arguments.is_empty() && call_node->arguments[0]->type == GDScriptParser::Node::ARRAY) {
const GDScriptParser::ArrayNode *array_node = static_cast<const GDScriptParser::ArrayNode *>(call_node->arguments[0]);
// Extract the name in "extension ; name" of PackedStringArray.
diff --git a/modules/gdscript/editor/script_templates/CharacterBody2D/basic_movement.gd b/modules/gdscript/editor/script_templates/CharacterBody2D/basic_movement.gd
index b8fc8c75dc..28ab080dd2 100644
--- a/modules/gdscript/editor/script_templates/CharacterBody2D/basic_movement.gd
+++ b/modules/gdscript/editor/script_templates/CharacterBody2D/basic_movement.gd
@@ -15,7 +15,7 @@ func _physics_process(delta: float) -> void:
if not is_on_floor():
velocity.y += gravity * delta
- # Handle Jump.
+ # Handle jump.
if Input.is_action_just_pressed("ui_accept") and is_on_floor():
velocity.y = JUMP_VELOCITY
diff --git a/modules/gdscript/editor/script_templates/CharacterBody3D/basic_movement.gd b/modules/gdscript/editor/script_templates/CharacterBody3D/basic_movement.gd
index 53bc606c9a..9b0e4be4ed 100644
--- a/modules/gdscript/editor/script_templates/CharacterBody3D/basic_movement.gd
+++ b/modules/gdscript/editor/script_templates/CharacterBody3D/basic_movement.gd
@@ -15,7 +15,7 @@ func _physics_process(delta: float) -> void:
if not is_on_floor():
velocity.y -= gravity * delta
- # Handle Jump.
+ # Handle jump.
if Input.is_action_just_pressed("ui_accept") and is_on_floor():
velocity.y = JUMP_VELOCITY
diff --git a/modules/gdscript/editor/script_templates/EditorPlugin/plugin.gd b/modules/gdscript/editor/script_templates/EditorPlugin/plugin.gd
index b27b3e5655..547943b910 100644
--- a/modules/gdscript/editor/script_templates/EditorPlugin/plugin.gd
+++ b/modules/gdscript/editor/script_templates/EditorPlugin/plugin.gd
@@ -1,6 +1,7 @@
# meta-description: Basic plugin template
+
@tool
-extends EditorPlugin
+extends _BASE_
func _enter_tree() -> void:
diff --git a/modules/gdscript/editor/script_templates/EditorScenePostImport/basic_import_script.gd b/modules/gdscript/editor/script_templates/EditorScenePostImport/basic_import_script.gd
index 556afe994b..6772ea4a26 100644
--- a/modules/gdscript/editor/script_templates/EditorScenePostImport/basic_import_script.gd
+++ b/modules/gdscript/editor/script_templates/EditorScenePostImport/basic_import_script.gd
@@ -1,6 +1,7 @@
# meta-description: Basic import script template
+
@tool
-extends EditorScenePostImport
+extends _BASE_
# Called by the editor when a scene has this script set as the import script in the import tab.
diff --git a/modules/gdscript/editor/script_templates/EditorScenePostImport/no_comments.gd b/modules/gdscript/editor/script_templates/EditorScenePostImport/no_comments.gd
index 875afb4fc0..e8f907f43b 100644
--- a/modules/gdscript/editor/script_templates/EditorScenePostImport/no_comments.gd
+++ b/modules/gdscript/editor/script_templates/EditorScenePostImport/no_comments.gd
@@ -1,6 +1,7 @@
# meta-description: Basic import script template (no comments)
+
@tool
-extends EditorScenePostImport
+extends _BASE_
func _post_import(scene: Node) -> Object:
diff --git a/modules/gdscript/editor/script_templates/EditorScript/basic_editor_script.gd b/modules/gdscript/editor/script_templates/EditorScript/basic_editor_script.gd
index fdb8550d43..fee7353f0d 100644
--- a/modules/gdscript/editor/script_templates/EditorScript/basic_editor_script.gd
+++ b/modules/gdscript/editor/script_templates/EditorScript/basic_editor_script.gd
@@ -1,6 +1,7 @@
# meta-description: Basic editor script template
+
@tool
-extends EditorScript
+extends _BASE_
# Called when the script is executed (using File -> Run in Script Editor).
diff --git a/modules/gdscript/editor/script_templates/RichTextEffect/default.gd b/modules/gdscript/editor/script_templates/RichTextEffect/default.gd
index c79eeb91ec..c7a999ef24 100644
--- a/modules/gdscript/editor/script_templates/RichTextEffect/default.gd
+++ b/modules/gdscript/editor/script_templates/RichTextEffect/default.gd
@@ -1,15 +1,16 @@
# meta-description: Base template for rich text effects
@tool
-class_name _CLASS_
+# Having a class name is handy for picking the effect in the Inspector.
+class_name RichText_CLASS_
extends _BASE_
# To use this effect:
# - Enable BBCode on a RichTextLabel.
# - Register this effect on the label.
-# - Use [_CLASS_ param=2.0]hello[/_CLASS_] in text.
-var bbcode := "_CLASS_"
+# - Use [_CLASS_SNAKE_CASE_ param=2.0]hello[/_CLASS_SNAKE_CASE_] in text.
+var bbcode := "_CLASS_SNAKE_CASE_"
func _process_custom_fx(char_fx: CharFXTransform) -> bool:
diff --git a/modules/gdscript/editor/script_templates/VisualShaderNodeCustom/basic.gd b/modules/gdscript/editor/script_templates/VisualShaderNodeCustom/basic.gd
index 283a95d3b4..458e22dae4 100644
--- a/modules/gdscript/editor/script_templates/VisualShaderNodeCustom/basic.gd
+++ b/modules/gdscript/editor/script_templates/VisualShaderNodeCustom/basic.gd
@@ -1,6 +1,7 @@
# meta-description: Visual shader's node plugin template
@tool
+# Having a class name is required for a custom node.
class_name VisualShaderNode_CLASS_
extends _BASE_
@@ -17,7 +18,7 @@ func _get_description() -> String:
return ""
-func _get_return_icon_type() -> int:
+func _get_return_icon_type() -> PortType:
return PORT_TYPE_SCALAR
@@ -29,7 +30,7 @@ func _get_input_port_name(port: int) -> String:
return ""
-func _get_input_port_type(port: int) -> int:
+func _get_input_port_type(port: int) -> PortType:
return PORT_TYPE_SCALAR
@@ -41,10 +42,10 @@ func _get_output_port_name(port: int) -> String:
return "result"
-func _get_output_port_type(port: int) -> int:
+func _get_output_port_type(port: int) -> PortType:
return PORT_TYPE_SCALAR
func _get_code(input_vars: Array[String], output_vars: Array[String],
- mode: int, type: int) -> String:
+ mode: Shader.Mode, type: VisualShader.Type) -> String:
return output_vars[0] + " = 0.0;"