diff options
Diffstat (limited to 'modules/gdscript/editor')
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;" |