diff options
Diffstat (limited to 'modules/gdscript')
-rw-r--r-- | modules/gdscript/doc_classes/@GDScript.xml | 188 | ||||
-rw-r--r-- | modules/gdscript/editor/gdscript_highlighter.cpp | 180 | ||||
-rw-r--r-- | modules/gdscript/editor/gdscript_highlighter.h | 6 | ||||
-rw-r--r-- | modules/gdscript/editor/gdscript_translation_parser_plugin.cpp | 8 | ||||
-rw-r--r-- | modules/gdscript/editor/script_templates/CharacterBody2D/basic_movement.gd | 2 | ||||
-rw-r--r-- | modules/gdscript/editor/script_templates/CharacterBody3D/basic_movement.gd | 2 | ||||
-rw-r--r-- | modules/gdscript/gdscript.cpp | 49 | ||||
-rw-r--r-- | modules/gdscript/gdscript.h | 5 | ||||
-rw-r--r-- | modules/gdscript/gdscript_analyzer.cpp | 4 | ||||
-rw-r--r-- | modules/gdscript/gdscript_parser.cpp | 2 | ||||
-rw-r--r-- | modules/gdscript/gdscript_utility_functions.cpp | 13 | ||||
-rw-r--r-- | modules/gdscript/gdscript_utility_functions.h | 3 | ||||
-rw-r--r-- | modules/gdscript/language_server/gdscript_workspace.cpp | 4 | ||||
-rw-r--r-- | modules/gdscript/tests/gdscript_test_runner.cpp | 6 |
14 files changed, 381 insertions, 91 deletions
diff --git a/modules/gdscript/doc_classes/@GDScript.xml b/modules/gdscript/doc_classes/@GDScript.xml index 4fbf8c6936..c2301c3e27 100644 --- a/modules/gdscript/doc_classes/@GDScript.xml +++ b/modules/gdscript/doc_classes/@GDScript.xml @@ -8,6 +8,7 @@ For the list of the global functions and constants see [@GlobalScope]. </description> <tutorials> + <link title="GDScript exports">$DOCS_URL/tutorials/scripting/gdscript/gdscript_exports.html</link> </tutorials> <methods> <method name="Color8"> @@ -73,11 +74,11 @@ [/codeblock] </description> </method> - <method name="dict2inst"> + <method name="dict_to_inst"> <return type="Object" /> <param index="0" name="dictionary" type="Dictionary" /> <description> - Converts a dictionary (previously created with [method inst2dict]) back to an instance. Useful for deserializing. + Converts a [param dictionary] (previously created with [method inst_to_dict]) back to an Object instance. Useful for deserializing. </description> </method> <method name="get_stack"> @@ -101,15 +102,15 @@ [b]Note:[/b] Not supported for calling from threads. Instead, this will return an empty array. </description> </method> - <method name="inst2dict"> + <method name="inst_to_dict"> <return type="Dictionary" /> <param index="0" name="instance" type="Object" /> <description> - Returns the passed instance converted to a dictionary (useful for serializing). + Returns the passed [param instance] converted to a Dictionary (useful for serializing). [codeblock] var foo = "bar" func _ready(): - var d = inst2dict(self) + var d = inst_to_dict(self) print(d.keys()) print(d.values()) [/codeblock] @@ -267,87 +268,178 @@ <annotation name="@export"> <return type="void" /> <description> + Mark the following property as exported (editable in the Inspector dock and saved to disk). To control the type of the exported property use the type hint notation. + [codeblock] + @export var int_number = 5 + @export var float_number: float = 5 + [/codeblock] </description> </annotation> <annotation name="@export_category"> <return type="void" /> <param index="0" name="name" type="String" /> <description> + Define a new category for the following exported properties. This helps to organize properties in the Inspector dock. + See also [constant PROPERTY_USAGE_CATEGORY]. + [codeblock] + @export_category("My Properties") + @export var number = 3 + @export var string = "" + [/codeblock] + [b]Note:[/b] Categories in the property list are supposed to indicate different base types, so the use of this annotation is not encouraged. See [annotation @export_group] and [annotation @export_subgroup] instead. </description> </annotation> <annotation name="@export_color_no_alpha"> <return type="void" /> <description> + Export a [Color] property without an alpha (fixed as [code]1.0[/code]). + See also [constant PROPERTY_HINT_COLOR_NO_ALPHA]. + [codeblock] + @export_color_no_alpha var modulate_color: Color + [/codeblock] </description> </annotation> <annotation name="@export_dir"> <return type="void" /> <description> + Export a [String] property as a path to a directory. The path will be limited to the project folder and its subfolders. See [annotation @export_global_dir] to allow picking from the entire filesystem. + See also [constant PROPERTY_HINT_DIR]. + [codeblock] + @export_dir var sprite_folder: String + [/codeblock] </description> </annotation> <annotation name="@export_enum" qualifiers="vararg"> <return type="void" /> <param index="0" name="names" type="String" /> <description> + Export a [String] or integer property as an enumerated list of options. If the property is an integer field, then the index of the value is stored, in the same order the values are provided. You can add specific identifiers for allowed values using a colon. + See also [constant PROPERTY_HINT_ENUM]. + [codeblock] + @export_enum("Rebecca", "Mary", "Leah") var character_name: String + @export_enum("Warrior", "Magician", "Thief") var character_class: int + @export_enum("Walking:30", "Running:60", "Riding:200") var character_speed: int + [/codeblock] </description> </annotation> <annotation name="@export_exp_easing" qualifiers="vararg"> <return type="void" /> <param index="0" name="hints" type="String" default="""" /> <description> + Export a floating-point property with an easing editor widget. Additional hints can be provided to adjust the behavior of the widget. [code]"attenuation"[/code] flips the curve, which makes it more intuitive for editing attenuation properties. [code]"positive_only"[/code] limits values to only be greater than or equal to zero. + See also [constant PROPERTY_HINT_EXP_EASING]. + [codeblock] + @export_exp_easing var transition_speed + @export_exp_easing("attenuation") var fading_attenuation + @export_exp_easing("positive_only") var effect_power + [/codeblock] </description> </annotation> <annotation name="@export_file" qualifiers="vararg"> <return type="void" /> <param index="0" name="filter" type="String" default="""" /> <description> + Export a [String] property as a path to a file. The path will be limited to the project folder and its subfolders. See [annotation @export_global_file] to allow picking from the entire filesystem. + If [param filter] is provided, only matching files will be available for picking. + See also [constant PROPERTY_HINT_FILE]. + [codeblock] + @export_file var sound_effect_file: String + @export_file("*.txt") var notes_file: String + [/codeblock] </description> </annotation> <annotation name="@export_flags" qualifiers="vararg"> <return type="void" /> <param index="0" name="names" type="String" /> <description> + Export an integer property as a bit flag field. This allows to store several "checked" or [code]true[/code] values with one property, and comfortably select them from the Inspector dock. + See also [constant PROPERTY_HINT_FLAGS]. + [codeblock] + @export_flags("Fire", "Water", "Earth", "Wind") var spell_elements = 0 + [/codeblock] </description> </annotation> <annotation name="@export_flags_2d_navigation"> <return type="void" /> <description> + Export an integer property as a bit flag field for 2D navigation layers. The widget in the Inspector dock will use the layer names defined in [member ProjectSettings.layer_names/2d_navigation/layer_1]. + See also [constant PROPERTY_HINT_LAYERS_2D_NAVIGATION]. + [codeblock] + @export_flags_2d_navigation var navigation_layers: int + [/codeblock] </description> </annotation> <annotation name="@export_flags_2d_physics"> <return type="void" /> <description> + Export an integer property as a bit flag field for 2D physics layers. The widget in the Inspector dock will use the layer names defined in [member ProjectSettings.layer_names/2d_physics/layer_1]. + See also [constant PROPERTY_HINT_LAYERS_2D_PHYSICS]. + [codeblock] + @export_flags_2d_physics var physics_layers: int + [/codeblock] </description> </annotation> <annotation name="@export_flags_2d_render"> <return type="void" /> <description> + Export an integer property as a bit flag field for 2D render layers. The widget in the Inspector dock will use the layer names defined in [member ProjectSettings.layer_names/2d_render/layer_1]. + See also [constant PROPERTY_HINT_LAYERS_2D_RENDER]. + [codeblock] + @export_flags_2d_render var render_layers: int + [/codeblock] </description> </annotation> <annotation name="@export_flags_3d_navigation"> <return type="void" /> <description> + Export an integer property as a bit flag field for 3D navigation layers. The widget in the Inspector dock will use the layer names defined in [member ProjectSettings.layer_names/3d_navigation/layer_1]. + See also [constant PROPERTY_HINT_LAYERS_3D_NAVIGATION]. + [codeblock] + @export_flags_3d_navigation var navigation_layers: int + [/codeblock] </description> </annotation> <annotation name="@export_flags_3d_physics"> <return type="void" /> <description> + Export an integer property as a bit flag field for 3D physics layers. The widget in the Inspector dock will use the layer names defined in [member ProjectSettings.layer_names/3d_physics/layer_1]. + See also [constant PROPERTY_HINT_LAYERS_3D_PHYSICS]. + [codeblock] + @export_flags_3d_physics var physics_layers: int + [/codeblock] </description> </annotation> <annotation name="@export_flags_3d_render"> <return type="void" /> <description> + Export an integer property as a bit flag field for 3D render layers. The widget in the Inspector dock will use the layer names defined in [member ProjectSettings.layer_names/3d_render/layer_1]. + See also [constant PROPERTY_HINT_LAYERS_3D_RENDER]. + [codeblock] + @export_flags_3d_render var render_layers: int + [/codeblock] </description> </annotation> <annotation name="@export_global_dir"> <return type="void" /> <description> + Export a [String] property as a path to a directory. The path can be picked from the entire filesystem. See [annotation @export_dir] to limit it to the project folder and its subfolders. + See also [constant PROPERTY_HINT_GLOBAL_DIR]. + [codeblock] + @export_global_dir var sprite_folder: String + [/codeblock] </description> </annotation> <annotation name="@export_global_file" qualifiers="vararg"> <return type="void" /> <param index="0" name="filter" type="String" default="""" /> <description> + Export a [String] property as a path to a file. The path can be picked from the entire filesystem. See [annotation @export_file] to limit it to the project folder and its subfolders. + If [param filter] is provided, only matching files will be available for picking. + See also [constant PROPERTY_HINT_GLOBAL_FILE]. + [codeblock] + @export_global_file var sound_effect_file: String + @export_global_file("*.txt") var notes_file: String + [/codeblock] </description> </annotation> <annotation name="@export_group"> @@ -355,22 +447,54 @@ <param index="0" name="name" type="String" /> <param index="1" name="prefix" type="String" default="""" /> <description> + Define a new group for the following exported properties. This helps to organize properties in the Inspector dock. Groups can be added with an optional [param prefix], which would make group to only consider properties that have this prefix. The grouping will break on the first property that doesn't have a prefix. The prefix is also removed from the property's name in the Inspector dock. + If no [param prefix] is provided, the every following property is added to the group. The group ends when then next group or category is defined. You can also force end a group by using this annotation with empty strings for paramters, [code]@export_group("", "")[/code]. + Groups cannot be nested, use [annotation @export_subgroup] to add subgroups to your groups. + See also [constant PROPERTY_USAGE_GROUP]. + [codeblock] + @export_group("My Properties") + @export var number = 3 + @export var string = "" + + @export_group("Prefixed Properties", "prefix_") + @export var prefix_number = 3 + @export var prefix_string = "" + + @export_group("", "") + @export var ungrouped_number = 3 + [/codeblock] </description> </annotation> <annotation name="@export_multiline"> <return type="void" /> <description> + Export a [String] property with a large [TextEdit] widget instead of a [LineEdit]. This adds support for multiline content and makes it easier to edit large amount of text stored in the property. + See also [constant PROPERTY_HINT_MULTILINE_TEXT]. + [codeblock] + @export_multiline var character_bio + [/codeblock] </description> </annotation> <annotation name="@export_node_path" qualifiers="vararg"> <return type="void" /> <param index="0" name="type" type="String" default="""" /> <description> + Export a [NodePath] property with a filter for allowed node types. + See also [constant PROPERTY_HINT_NODE_PATH_VALID_TYPES]. + [codeblock] + @export_node_path(Button, TouchScreenButton) var some_button + [/codeblock] </description> </annotation> <annotation name="@export_placeholder"> <return type="void" /> + <param index="0" name="placeholder" type="String" /> <description> + Export a [String] property with a placeholder text displayed in the editor widget when no value is present. + See also [constant PROPERTY_HINT_PLACEHOLDER_TEXT]. + [codeblock] + @export_placeholder("Name in lowercase") var character_id: String + [/codeblock] </description> </annotation> <annotation name="@export_range" qualifiers="vararg"> @@ -380,6 +504,22 @@ <param index="2" name="step" type="float" default="1.0" /> <param index="3" name="extra_hints" type="String" default="""" /> <description> + Export a numeric property as a range value. The range must be defined by [param min] and [param max], as well as an optional [param step] and a variety of extra hints. The [param step] defaults to [code]1[/code] for integer properties. For floating-point numbers this value depends on your [code]EditorSettings.interface/inspector/default_float_step[/code] setting. + If hints [code]"or_greater"[/code] and [code]"or_lesser"[/code] are provided, the editor widget will not cap the value at range boundaries. The [code]"exp"[/code] hint will make the edited values on range to change exponentially. The [code]"no_slider"[/code] hint will hide the slider element of the editor widget. + Hints also allow to indicate the units for the edited value. Using [code]"radians"[/code] you can specify that the actual value is in radians, but should be displayed in degrees in the Inspector dock. [code]"degrees"[/code] allows to add a degree sign as a unit suffix. Finally, a custom suffix can be provided using [code]"suffix:unit"[/code], where "unit" can be any string. + See also [constant PROPERTY_HINT_RANGE]. + [codeblock] + @export_range(0, 20) var number + @export_range(-10, 20) var number + @export_range(-10, 20, 0.2) var number: float + + @export_range(0, 100, 1, "or_greater") var power_percent + @export_range(0, 100, 1, "or_greater", "or_lesser") var health_delta + + @export_range(-3.14, 3.14, 0.001, "radians") var angle_radians + @export_range(0, 360, 1, "degrees") var angle_degrees + @export_range(-8, 8, 2, "suffix:px") var target_offset + [/codeblock] </description> </annotation> <annotation name="@export_subgroup"> @@ -387,17 +527,38 @@ <param index="0" name="name" type="String" /> <param index="1" name="prefix" type="String" default="""" /> <description> + Define a new subgroup for the following exported properties. This helps to organize properties in the Inspector dock. Subgroups work exactly like groups, except they need a parent group to exist. See [annotation @export_group]. + See also [constant PROPERTY_USAGE_SUBGROUP]. + [codeblock] + @export_group("My Properties") + @export var number = 3 + @export var string = "" + + @export_subgroup("My Prefixed Properties", "prefix_") + @export var prefix_number = 3 + @export var prefix_string = "" + [/codeblock] + [b]Note:[/b] Subgroups cannot be nested, they only provide one extra level of depth. Just like the next group ends the previous group, so do the subsequent subgroups. </description> </annotation> <annotation name="@icon"> <return type="void" /> <param index="0" name="icon_path" type="String" /> <description> + Add a custom icon to the current script. The icon is displayed in the Scene dock for every node that the script is attached to. For named classes the icon is also displayed in various editor dialogs. + [codeblock] + @icon("res://path/to/class/icon.svg") + [/codeblock] + [b]Note:[/b] Only the script can have a custom icon. Inner classes are not supported yet. </description> </annotation> <annotation name="@onready"> <return type="void" /> <description> + Mark the following property as assigned on [Node]'s ready state change. Values for these properties are no assigned immediately upon the node's creation, and instead are computed and stored right before [method Node._ready]. + [codeblock] + @onready var character_name: Label = $Label + [/codeblock] </description> </annotation> <annotation name="@rpc" qualifiers="vararg"> @@ -407,17 +568,34 @@ <param index="2" name="transfer_mode" type="String" default="""" /> <param index="3" name="transfer_channel" type="int" default="0" /> <description> + Mark the following method for remote procedure calls. See [url=$DOCS_URL/tutorials/networking/high_level_multiplayer.html]High-level multiplayer[/url]. + [codeblock] + @rpc() + [/codeblock] </description> </annotation> <annotation name="@tool"> <return type="void" /> <description> + Mark the current script as a tool script, allowing it to be loaded and executed by the editor. See [url=$DOCS_URL/tutorials/plugins/running_code_in_the_editor.html]Running code in the editor[/url]. + [codeblock] + @tool + extends Node + [/codeblock] </description> </annotation> <annotation name="@warning_ignore" qualifiers="vararg"> <return type="void" /> <param index="0" name="warning" type="String" /> <description> + Mark the following statement to ignore the specified warning. See [url=$DOCS_URL/tutorials/scripting/gdscript/warning_system.html]GDScript warning system[/url]. + [codeblock] + func test(): + print("hello") + return + @warning_ignore("unreachable_code") + print("unreachable") + [/codeblock] </description> </annotation> </annotations> diff --git a/modules/gdscript/editor/gdscript_highlighter.cpp b/modules/gdscript/editor/gdscript_highlighter.cpp index a23f19de85..02922086f0 100644 --- a/modules/gdscript/editor/gdscript_highlighter.cpp +++ b/modules/gdscript/editor/gdscript_highlighter.cpp @@ -45,9 +45,11 @@ Dictionary GDScriptSyntaxHighlighter::_get_line_syntax_highlighting_impl(int p_l int previous_column = 0; bool prev_is_char = false; - bool prev_is_number = false; + bool prev_is_digit = false; + bool prev_is_binary_op = false; bool in_keyword = false; bool in_word = false; + bool in_number = false; bool in_function_name = false; bool in_lambda = false; bool in_variable_declaration = false; @@ -84,16 +86,17 @@ Dictionary GDScriptSyntaxHighlighter::_get_line_syntax_highlighting_impl(int p_l const int line_length = str.length(); Color prev_color; - if (in_region != -1 && str.length() == 0) { + if (in_region != -1 && line_length == 0) { color_region_cache[p_line] = in_region; } - for (int j = 0; j < str.length(); j++) { + for (int j = 0; j < line_length; j++) { Dictionary highlighter_info; color = font_color; bool is_char = !is_symbol(str[j]); bool is_a_symbol = is_symbol(str[j]); - bool is_number = is_digit(str[j]); + bool is_a_digit = is_digit(str[j]); + bool is_binary_op = false; /* color regions */ if (is_a_symbol || in_region != -1) { @@ -231,67 +234,94 @@ Dictionary GDScriptSyntaxHighlighter::_get_line_syntax_highlighting_impl(int p_l in_region = -1; prev_is_char = false; - prev_is_number = false; + prev_is_digit = false; + prev_is_binary_op = false; continue; } } } + // A bit of a hack, but couldn't come up with anything better. + if (j > 0 && (str[j] == '&' || str[j] == '^' || str[j] == '%' || str[j] == '+' || str[j] == '-' || str[j] == '~' || str[j] == '.')) { + if (!keywords.has(previous_text)) { + if (previous_text == "PI" || previous_text == "TAU" || previous_text == "INF" || previous_text == "NAN") { + is_binary_op = true; + } else { + int k = j - 1; + while (k > 0 && is_whitespace(str[k])) { + k--; + } + if (!is_symbol(str[k]) || str[k] == '"' || str[k] == '\'' || str[k] == ')' || str[k] == ']' || str[k] == '}') { + is_binary_op = true; + } + } + } + } + + if (!is_char) { + in_keyword = false; + } + // allow ABCDEF in hex notation - if (is_hex_notation && (is_hex_digit(str[j]) || is_number)) { - is_number = true; + if (is_hex_notation && (is_hex_digit(str[j]) || is_a_digit)) { + is_a_digit = true; } else { is_hex_notation = false; } - // disallow anything not a 0 or 1 - if (is_bin_notation && (is_binary_digit(str[j]))) { - is_number = true; - } else if (is_bin_notation) { - is_bin_notation = false; - is_number = false; - } else { + // disallow anything not a 0 or 1 in binary notation + if (is_bin_notation && !is_binary_digit(str[j])) { + is_a_digit = false; is_bin_notation = false; } - // check for dot or underscore or 'x' for hex notation in floating point number or 'e' for scientific notation - if ((str[j] == '.' || str[j] == 'x' || str[j] == 'b' || str[j] == '_' || str[j] == 'e') && !in_word && prev_is_number && !is_number) { - is_number = true; - is_a_symbol = false; - is_char = false; + if (!in_number && !in_word && is_a_digit) { + in_number = true; + } - if (str[j] == 'x' && str[j - 1] == '0') { - is_hex_notation = true; - } else if (str[j] == 'b' && str[j - 1] == '0') { + // Special cases for numbers + if (in_number && !is_a_digit) { + if (str[j] == 'b' && str[j - 1] == '0') { is_bin_notation = true; + } else if (str[j] == 'x' && str[j - 1] == '0') { + is_hex_notation = true; + } 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' || str[j] == '.') && (prev_is_digit || str[j - 1] == '_')) && + !((str[j] == '-' || str[j] == '+' || str[j] == '~') && !prev_is_binary_op && str[j - 1] != 'e')) { + /* 1st row of condition: '+' or '-' after scientific notation; + 2nd row of condition: '_' as a numeric separator; + 3rd row of condition: Scientific notation 'e' and floating points; + 4th row of condition: Multiple unary operators. */ + in_number = false; } + } else if ((str[j] == '-' || str[j] == '+' || str[j] == '~' || (str[j] == '.' && str[j + 1] != '.' && (j == 0 || (j > 0 && str[j - 1] != '.')))) && !is_binary_op) { + // Start a number from unary mathematical operators and floating points, except for '..' + in_number = true; } - if (!in_word && (is_ascii_char(str[j]) || is_underscore(str[j])) && !is_number) { + if (!in_word && (is_ascii_char(str[j]) || is_underscore(str[j])) && !in_number) { in_word = true; } - if ((in_keyword || in_word) && !is_hex_notation) { - is_number = false; - } - if (is_a_symbol && str[j] != '.' && in_word) { in_word = false; } - if (!is_char) { - in_keyword = false; - } - if (!in_keyword && is_char && !prev_is_char) { int to = j; - while (to < str.length() && !is_symbol(str[to])) { + while (to < line_length && !is_symbol(str[to])) { to++; } String word = str.substr(j, to - j); Color col = Color(); - if (keywords.has(word)) { + if (global_functions.has(word)) { + // "assert" and "preload" are reserved, so highlight even if not followed by a bracket. + if (word == "assert" || word == "preload" || str[to] == '(') { + col = global_function_color; + } + } else if (keywords.has(word)) { col = keywords[word]; } else if (member_keywords.has(word)) { col = member_keywords[word]; @@ -300,12 +330,13 @@ Dictionary GDScriptSyntaxHighlighter::_get_line_syntax_highlighting_impl(int p_l if (col != Color()) { for (int k = j - 1; k >= 0; k--) { if (str[k] == '.') { - col = Color(); // keyword & member indexing not allowed + col = Color(); // keyword, member & global func indexing not allowed break; } else if (str[k] > 32) { break; } } + if (col != Color()) { in_keyword = true; keyword_color = col; @@ -318,12 +349,12 @@ Dictionary GDScriptSyntaxHighlighter::_get_line_syntax_highlighting_impl(int p_l in_signal_declaration = true; } else { int k = j; - while (k < str.length() && !is_symbol(str[k]) && str[k] != '\t' && str[k] != ' ') { + while (k < line_length && !is_symbol(str[k]) && !is_whitespace(str[k])) { k++; } // check for space between name and bracket - while (k < str.length() && (str[k] == '\t' || str[k] == ' ')) { + while (k < line_length && is_whitespace(str[k])) { k++; } @@ -336,7 +367,7 @@ Dictionary GDScriptSyntaxHighlighter::_get_line_syntax_highlighting_impl(int p_l // Check for lambda. if (in_function_name && previous_text == GDScriptTokenizer::get_token_name(GDScriptTokenizer::Token::FUNC)) { k = j - 1; - while (k > 0 && (str[k] == '\t' || str[k] == ' ')) { + while (k > 0 && is_whitespace(str[k])) { k--; } @@ -347,9 +378,9 @@ Dictionary GDScriptSyntaxHighlighter::_get_line_syntax_highlighting_impl(int p_l } } - if (!in_function_name && !in_member_variable && !in_keyword && !is_number && in_word) { + if (!in_function_name && !in_member_variable && !in_keyword && !in_number && in_word) { int k = j; - while (k > 0 && !is_symbol(str[k]) && str[k] != '\t' && str[k] != ' ') { + while (k > 0 && !is_symbol(str[k]) && !is_whitespace(str[k])) { k--; } @@ -378,7 +409,7 @@ Dictionary GDScriptSyntaxHighlighter::_get_line_syntax_highlighting_impl(int p_l if (in_variable_declaration || in_function_args) { int k = j; // Skip space - while (k < str.length() && (str[k] == '\t' || str[k] == ' ')) { + while (k < line_length && is_whitespace(str[k])) { k++; } @@ -395,13 +426,25 @@ Dictionary GDScriptSyntaxHighlighter::_get_line_syntax_highlighting_impl(int p_l in_member_variable = false; } - if (!in_node_path && in_region == -1 && (str[j] == '^')) { + // 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) { + is_binary_op = true; + } else if (j == 0 || (j > 0 && str[j - 1] != '&') || prev_is_binary_op) { + in_string_name = true; + } + } else if (in_region != -1 || is_a_symbol) { + in_string_name = false; + } + + // '^^' has no special meaning, so unlike StringName, when binary, use NodePath color for the last caret + if (!in_node_path && in_region == -1 && str[j] == '^' && !is_binary_op && (j == 0 || (j > 0 && str[j - 1] != '^') || prev_is_binary_op)) { in_node_path = true; - } else if (in_region != -1 || (is_a_symbol && str[j] != '/' && str[j] != '%')) { + } else if (in_region != -1 || is_a_symbol) { in_node_path = false; } - if (!in_node_ref && in_region == -1 && (str[j] == '$' || str[j] == '%')) { + if (!in_node_ref && in_region == -1 && (str[j] == '$' || (str[j] == '%' && !is_binary_op))) { in_node_ref = true; } else if (in_region != -1 || (is_a_symbol && str[j] != '/' && str[j] != '%')) { in_node_ref = false; @@ -413,16 +456,7 @@ Dictionary GDScriptSyntaxHighlighter::_get_line_syntax_highlighting_impl(int p_l in_annotation = false; } - if (!in_string_name && in_region == -1 && str[j] == '&') { - in_string_name = true; - } else if (in_region != -1 || is_a_symbol) { - in_string_name = false; - } - - if (in_node_path) { - next_type = NODE_PATH; - color = node_path_color; - } else if (in_node_ref) { + if (in_node_ref) { next_type = NODE_REF; color = node_ref_color; } else if (in_annotation) { @@ -431,6 +465,9 @@ Dictionary GDScriptSyntaxHighlighter::_get_line_syntax_highlighting_impl(int p_l } else if (in_string_name) { next_type = STRING_NAME; color = string_name_color; + } else if (in_node_path) { + next_type = NODE_PATH; + color = node_path_color; } else if (in_keyword) { next_type = KEYWORD; color = keyword_color; @@ -449,12 +486,12 @@ Dictionary GDScriptSyntaxHighlighter::_get_line_syntax_highlighting_impl(int p_l } else { color = function_color; } + } else if (in_number) { + next_type = NUMBER; + color = number_color; } else if (is_a_symbol) { next_type = SYMBOL; color = symbol_color; - } else if (is_number) { - next_type = NUMBER; - color = number_color; } else if (expect_type) { next_type = TYPE; color = type_color; @@ -486,7 +523,8 @@ Dictionary GDScriptSyntaxHighlighter::_get_line_syntax_highlighting_impl(int p_l } prev_is_char = is_char; - prev_is_number = is_number; + prev_is_digit = is_a_digit; + prev_is_binary_op = is_binary_op; if (color != prev_color) { prev_color = color; @@ -501,8 +539,8 @@ String GDScriptSyntaxHighlighter::_get_name() const { return "GDScript"; } -Array GDScriptSyntaxHighlighter::_get_supported_languages() const { - Array languages; +PackedStringArray GDScriptSyntaxHighlighter::_get_supported_languages() const { + PackedStringArray languages; languages.push_back("GDScript"); return languages; } @@ -510,6 +548,7 @@ Array GDScriptSyntaxHighlighter::_get_supported_languages() const { void GDScriptSyntaxHighlighter::_update_cache() { keywords.clear(); member_keywords.clear(); + global_functions.clear(); color_regions.clear(); color_region_cache.clear(); @@ -566,6 +605,17 @@ void GDScriptSyntaxHighlighter::_update_cache() { } } + /* Global functions. */ + List<StringName> global_function_list; + GDScriptUtilityFunctions::get_function_list(&global_function_list); + Variant::get_utility_function_list(&global_function_list); + // "assert" and "preload" are not utility functions, but are global nonetheless, so insert them. + global_functions.insert(SNAME("assert")); + global_functions.insert(SNAME("preload")); + for (const StringName &E : global_function_list) { + global_functions.insert(E); + } + /* Comments */ const Color comment_color = EDITOR_GET("text_editor/theme/highlighting/comment_color"); List<String> comments; @@ -618,19 +668,22 @@ void GDScriptSyntaxHighlighter::_update_cache() { if (godot_2_theme || EditorSettings::get_singleton()->is_dark_theme()) { function_definition_color = Color(0.4, 0.9, 1.0); + global_function_color = Color(0.6, 0.6, 0.9); node_path_color = Color(0.72, 0.77, 0.49); 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.66, 0.72); + string_name_color = Color(1.0, 0.76, 0.65); } else { function_definition_color = Color(0, 0.6, 0.6); + global_function_color = Color(0.4, 0.2, 0.8); node_path_color = Color(0.18, 0.55, 0); node_ref_color = Color(0.0, 0.5, 0); annotation_color = Color(0.8, 0.37, 0); - string_name_color = Color(0.8, 0.46, 0.52); + string_name_color = Color(0.8, 0.56, 0.45); } EDITOR_DEF("text_editor/theme/highlighting/gdscript/function_definition_color", function_definition_color); + EDITOR_DEF("text_editor/theme/highlighting/gdscript/global_function_color", global_function_color); EDITOR_DEF("text_editor/theme/highlighting/gdscript/node_path_color", node_path_color); EDITOR_DEF("text_editor/theme/highlighting/gdscript/node_reference_color", node_ref_color); EDITOR_DEF("text_editor/theme/highlighting/gdscript/annotation_color", annotation_color); @@ -641,6 +694,10 @@ void GDScriptSyntaxHighlighter::_update_cache() { function_definition_color, true); EditorSettings::get_singleton()->set_initial_value( + "text_editor/theme/highlighting/gdscript/global_function_color", + global_function_color, + true); + EditorSettings::get_singleton()->set_initial_value( "text_editor/theme/highlighting/gdscript/node_path_color", node_path_color, true); @@ -659,6 +716,7 @@ void GDScriptSyntaxHighlighter::_update_cache() { } function_definition_color = EDITOR_GET("text_editor/theme/highlighting/gdscript/function_definition_color"); + global_function_color = EDITOR_GET("text_editor/theme/highlighting/gdscript/global_function_color"); node_path_color = EDITOR_GET("text_editor/theme/highlighting/gdscript/node_path_color"); node_ref_color = EDITOR_GET("text_editor/theme/highlighting/gdscript/node_reference_color"); annotation_color = EDITOR_GET("text_editor/theme/highlighting/gdscript/annotation_color"); diff --git a/modules/gdscript/editor/gdscript_highlighter.h b/modules/gdscript/editor/gdscript_highlighter.h index 7987582f07..60b5b092d4 100644 --- a/modules/gdscript/editor/gdscript_highlighter.h +++ b/modules/gdscript/editor/gdscript_highlighter.h @@ -49,6 +49,7 @@ private: HashMap<StringName, Color> keywords; HashMap<StringName, Color> member_keywords; + HashSet<StringName> global_functions; enum Type { NONE, @@ -67,10 +68,11 @@ private: TYPE, }; - // colours + // Colors. Color font_color; Color symbol_color; Color function_color; + Color global_function_color; Color function_definition_color; Color built_in_type_color; Color number_color; @@ -88,7 +90,7 @@ public: virtual Dictionary _get_line_syntax_highlighting_impl(int p_line) override; virtual String _get_name() const override; - virtual Array _get_supported_languages() const override; + virtual PackedStringArray _get_supported_languages() const override; virtual Ref<EditorSyntaxHighlighter> _create() const override; }; diff --git a/modules/gdscript/editor/gdscript_translation_parser_plugin.cpp b/modules/gdscript/editor/gdscript_translation_parser_plugin.cpp index 9b540b16f2..518d4bcb62 100644 --- a/modules/gdscript/editor/gdscript_translation_parser_plugin.cpp +++ b/modules/gdscript/editor/gdscript_translation_parser_plugin.cpp @@ -41,7 +41,7 @@ Error GDScriptEditorTranslationParserPlugin::parse_file(const String &p_path, Ve // Extract all translatable strings using the parsed tree from GDSriptParser. // The strategy is to find all ExpressionNode and AssignmentNode from the tree and extract strings if relevant, i.e // Search strings in ExpressionNode -> CallNode -> tr(), set_text(), set_placeholder() etc. - // Search strings in AssignmentNode -> text = "__", hint_tooltip = "__" etc. + // Search strings in AssignmentNode -> text = "__", tooltip_text = "__" etc. Error err; Ref<Resource> loaded_res = ResourceLoader::load(p_path, "", ResourceFormatLoader::CACHE_MODE_REUSE, &err); @@ -221,7 +221,7 @@ void GDScriptEditorTranslationParserPlugin::_assess_assignment(GDScriptParser::A } if (assignment_patterns.has(assignee_name) && p_assignment->assigned_value->type == GDScriptParser::Node::LITERAL) { - // If the assignment is towards one of the extract patterns (text, hint_tooltip etc.), and the value is a string literal, we collect the string. + // If the assignment is towards one of the extract patterns (text, tooltip_text etc.), and the value is a string literal, we collect the string. ids->push_back(static_cast<GDScriptParser::LiteralNode *>(p_assignment->assigned_value)->value); } else if (assignee_name == fd_filters && p_assignment->assigned_value->type == GDScriptParser::Node::CALL) { // FileDialog.filters accepts assignment in the form of PackedStringArray. For example, @@ -330,10 +330,10 @@ void GDScriptEditorTranslationParserPlugin::_extract_fd_literals(GDScriptParser: GDScriptEditorTranslationParserPlugin::GDScriptEditorTranslationParserPlugin() { assignment_patterns.insert("text"); assignment_patterns.insert("placeholder_text"); - assignment_patterns.insert("hint_tooltip"); + assignment_patterns.insert("tooltip_text"); first_arg_patterns.insert("set_text"); - first_arg_patterns.insert("set_tooltip"); + first_arg_patterns.insert("set_tooltip_text"); first_arg_patterns.insert("set_placeholder"); first_arg_patterns.insert("add_tab"); first_arg_patterns.insert("add_check_item"); diff --git a/modules/gdscript/editor/script_templates/CharacterBody2D/basic_movement.gd b/modules/gdscript/editor/script_templates/CharacterBody2D/basic_movement.gd index a379d915a9..b8fc8c75dc 100644 --- a/modules/gdscript/editor/script_templates/CharacterBody2D/basic_movement.gd +++ b/modules/gdscript/editor/script_templates/CharacterBody2D/basic_movement.gd @@ -6,7 +6,7 @@ extends _BASE_ const SPEED = 300.0 const JUMP_VELOCITY = -400.0 -# Get the gravity from the project settings to be synced with RigidDynamicBody nodes. +# Get the gravity from the project settings to be synced with RigidBody nodes. var gravity: int = ProjectSettings.get_setting("physics/2d/default_gravity") diff --git a/modules/gdscript/editor/script_templates/CharacterBody3D/basic_movement.gd b/modules/gdscript/editor/script_templates/CharacterBody3D/basic_movement.gd index 360b199e56..53bc606c9a 100644 --- a/modules/gdscript/editor/script_templates/CharacterBody3D/basic_movement.gd +++ b/modules/gdscript/editor/script_templates/CharacterBody3D/basic_movement.gd @@ -6,7 +6,7 @@ extends _BASE_ const SPEED = 5.0 const JUMP_VELOCITY = 4.5 -# Get the gravity from the project settings to be synced with RigidDynamicBody nodes. +# Get the gravity from the project settings to be synced with RigidBody nodes. var gravity: float = ProjectSettings.get_setting("physics/3d/default_gravity") diff --git a/modules/gdscript/gdscript.cpp b/modules/gdscript/gdscript.cpp index 8a5e93eeff..10babad378 100644 --- a/modules/gdscript/gdscript.cpp +++ b/modules/gdscript/gdscript.cpp @@ -683,7 +683,7 @@ bool GDScript::_update_exports(bool *r_err, bool p_recursive_call, PlaceHolderSc if (base.is_empty() || base.is_relative_path()) { ERR_PRINT(("Could not resolve relative path for parent class: " + path).utf8().get_data()); } else { - path = base.get_base_dir().plus_file(path); + path = base.get_base_dir().path_join(path); } } } else if (c->extends.size() != 0) { @@ -1538,6 +1538,47 @@ void GDScriptInstance::get_property_list(List<PropertyInfo> *p_properties) const } } +bool GDScriptInstance::property_can_revert(const StringName &p_name) const { + Variant name = p_name; + const Variant *args[1] = { &name }; + + const GDScript *sptr = script.ptr(); + while (sptr) { + HashMap<StringName, GDScriptFunction *>::ConstIterator E = sptr->member_functions.find(GDScriptLanguage::get_singleton()->strings._property_can_revert); + if (E) { + Callable::CallError err; + Variant ret = E->value->call(const_cast<GDScriptInstance *>(this), args, 1, err); + if (err.error == Callable::CallError::CALL_OK && ret.get_type() == Variant::BOOL && ret.operator bool()) { + return true; + } + } + sptr = sptr->_base; + } + + return false; +} + +bool GDScriptInstance::property_get_revert(const StringName &p_name, Variant &r_ret) const { + Variant name = p_name; + const Variant *args[1] = { &name }; + + const GDScript *sptr = script.ptr(); + while (sptr) { + HashMap<StringName, GDScriptFunction *>::ConstIterator E = sptr->member_functions.find(GDScriptLanguage::get_singleton()->strings._property_get_revert); + if (E) { + Callable::CallError err; + Variant ret = E->value->call(const_cast<GDScriptInstance *>(this), args, 1, err); + if (err.error == Callable::CallError::CALL_OK && ret.get_type() != Variant::NIL) { + r_ret = ret; + return true; + } + } + sptr = sptr->_base; + } + + return false; +} + void GDScriptInstance::get_method_list(List<MethodInfo> *p_list) const { const GDScript *sptr = script.ptr(); while (sptr) { @@ -2163,7 +2204,7 @@ String GDScriptLanguage::get_global_class_name(const String &p_path, String *r_b if (c->icon_path.is_empty() || c->icon_path.is_absolute_path()) { *r_icon_path = c->icon_path; } else if (c->icon_path.is_relative_path()) { - *r_icon_path = p_path.get_base_dir().plus_file(c->icon_path).simplify_path(); + *r_icon_path = p_path.get_base_dir().path_join(c->icon_path).simplify_path(); } } if (r_base_type) { @@ -2191,7 +2232,7 @@ String GDScriptLanguage::get_global_class_name(const String &p_path, String *r_b } String subpath = subclass->extends_path; if (subpath.is_relative_path()) { - subpath = path.get_base_dir().plus_file(subpath).simplify_path(); + subpath = path.get_base_dir().path_join(subpath).simplify_path(); } if (OK != subparser.parse(subsource, subpath, false)) { @@ -2248,6 +2289,8 @@ GDScriptLanguage::GDScriptLanguage() { strings._set = StaticCString::create("_set"); strings._get = StaticCString::create("_get"); strings._get_property_list = StaticCString::create("_get_property_list"); + strings._property_can_revert = StaticCString::create("_property_can_revert"); + strings._property_get_revert = StaticCString::create("_property_get_revert"); strings._script_source = StaticCString::create("script/source"); _debug_parse_err_line = -1; _debug_parse_err_file = ""; diff --git a/modules/gdscript/gdscript.h b/modules/gdscript/gdscript.h index 5123cccddd..e4b12d4ddb 100644 --- a/modules/gdscript/gdscript.h +++ b/modules/gdscript/gdscript.h @@ -287,6 +287,9 @@ public: virtual void get_property_list(List<PropertyInfo> *p_properties) const; virtual Variant::Type get_property_type(const StringName &p_name, bool *r_is_valid = nullptr) const; + virtual bool property_can_revert(const StringName &p_name) const; + virtual bool property_get_revert(const StringName &p_name, Variant &r_ret) const; + virtual void get_method_list(List<MethodInfo> *p_list) const; virtual bool has_method(const StringName &p_method) const; virtual Variant callp(const StringName &p_method, const Variant **p_args, int p_argcount, Callable::CallError &r_error); @@ -423,6 +426,8 @@ public: StringName _set; StringName _get; StringName _get_property_list; + StringName _property_can_revert; + StringName _property_get_revert; StringName _script_source; } strings; diff --git a/modules/gdscript/gdscript_analyzer.cpp b/modules/gdscript/gdscript_analyzer.cpp index a07d4855f3..c8c876369f 100644 --- a/modules/gdscript/gdscript_analyzer.cpp +++ b/modules/gdscript/gdscript_analyzer.cpp @@ -260,7 +260,7 @@ Error GDScriptAnalyzer::resolve_inheritance(GDScriptParser::ClassNode *p_class, if (!p_class->extends_path.is_empty()) { if (p_class->extends_path.is_relative_path()) { - p_class->extends_path = class_type.script_path.get_base_dir().plus_file(p_class->extends_path).simplify_path(); + p_class->extends_path = class_type.script_path.get_base_dir().path_join(p_class->extends_path).simplify_path(); } Ref<GDScriptParserRef> parser = get_parser_for(p_class->extends_path); if (parser.is_null()) { @@ -3185,7 +3185,7 @@ void GDScriptAnalyzer::reduce_preload(GDScriptParser::PreloadNode *p_preload) { p_preload->resolved_path = p_preload->path->reduced_value; // TODO: Save this as script dependency. if (p_preload->resolved_path.is_relative_path()) { - p_preload->resolved_path = parser->script_path.get_base_dir().plus_file(p_preload->resolved_path); + p_preload->resolved_path = parser->script_path.get_base_dir().path_join(p_preload->resolved_path); } p_preload->resolved_path = p_preload->resolved_path.simplify_path(); if (!FileAccess::exists(p_preload->resolved_path)) { diff --git a/modules/gdscript/gdscript_parser.cpp b/modules/gdscript/gdscript_parser.cpp index 6f5397e1a3..6b6ad427a7 100644 --- a/modules/gdscript/gdscript_parser.cpp +++ b/modules/gdscript/gdscript_parser.cpp @@ -127,7 +127,7 @@ GDScriptParser::GDScriptParser() { register_annotation(MethodInfo("@export_global_file", PropertyInfo(Variant::STRING, "filter")), AnnotationInfo::VARIABLE, &GDScriptParser::export_annotations<PROPERTY_HINT_GLOBAL_FILE, Variant::STRING>, varray(""), true); register_annotation(MethodInfo("@export_global_dir"), AnnotationInfo::VARIABLE, &GDScriptParser::export_annotations<PROPERTY_HINT_GLOBAL_DIR, Variant::STRING>); register_annotation(MethodInfo("@export_multiline"), AnnotationInfo::VARIABLE, &GDScriptParser::export_annotations<PROPERTY_HINT_MULTILINE_TEXT, Variant::STRING>); - register_annotation(MethodInfo("@export_placeholder"), AnnotationInfo::VARIABLE, &GDScriptParser::export_annotations<PROPERTY_HINT_PLACEHOLDER_TEXT, Variant::STRING>); + register_annotation(MethodInfo("@export_placeholder", PropertyInfo(Variant::STRING, "placeholder")), AnnotationInfo::VARIABLE, &GDScriptParser::export_annotations<PROPERTY_HINT_PLACEHOLDER_TEXT, Variant::STRING>); register_annotation(MethodInfo("@export_range", PropertyInfo(Variant::FLOAT, "min"), PropertyInfo(Variant::FLOAT, "max"), PropertyInfo(Variant::FLOAT, "step"), PropertyInfo(Variant::STRING, "extra_hints")), AnnotationInfo::VARIABLE, &GDScriptParser::export_annotations<PROPERTY_HINT_RANGE, Variant::FLOAT>, varray(1.0, ""), true); register_annotation(MethodInfo("@export_exp_easing", PropertyInfo(Variant::STRING, "hints")), AnnotationInfo::VARIABLE, &GDScriptParser::export_annotations<PROPERTY_HINT_EXP_EASING, Variant::FLOAT>, varray(""), true); register_annotation(MethodInfo("@export_color_no_alpha"), AnnotationInfo::VARIABLE, &GDScriptParser::export_annotations<PROPERTY_HINT_COLOR_NO_ALPHA, Variant::COLOR>); diff --git a/modules/gdscript/gdscript_utility_functions.cpp b/modules/gdscript/gdscript_utility_functions.cpp index 4b97486cb3..bcbe8b8d2b 100644 --- a/modules/gdscript/gdscript_utility_functions.cpp +++ b/modules/gdscript/gdscript_utility_functions.cpp @@ -36,6 +36,7 @@ #include "core/object/object.h" #include "core/templates/oa_hash_map.h" #include "core/templates/vector.h" +#include "core/variant/typed_array.h" #include "gdscript.h" #ifdef DEBUG_ENABLED @@ -261,7 +262,7 @@ struct GDScriptUtilityFunctionsDefinitions { } } - static inline void inst2dict(Variant *r_ret, const Variant **p_args, int p_arg_count, Callable::CallError &r_error) { + static inline void inst_to_dict(Variant *r_ret, const Variant **p_args, int p_arg_count, Callable::CallError &r_error) { VALIDATE_ARG_COUNT(1); if (p_args[0]->get_type() == Variant::NIL) { @@ -328,7 +329,7 @@ struct GDScriptUtilityFunctionsDefinitions { } } - static inline void dict2inst(Variant *r_ret, const Variant **p_args, int p_arg_count, Callable::CallError &r_error) { + static inline void dict_to_inst(Variant *r_ret, const Variant **p_args, int p_arg_count, Callable::CallError &r_error) { VALIDATE_ARG_COUNT(1); if (p_args[0]->get_type() != Variant::DICTIONARY) { @@ -468,12 +469,12 @@ struct GDScriptUtilityFunctionsDefinitions { static inline void get_stack(Variant *r_ret, const Variant **p_args, int p_arg_count, Callable::CallError &r_error) { VALIDATE_ARG_COUNT(0); if (Thread::get_caller_id() != Thread::get_main_id()) { - *r_ret = Array(); + *r_ret = TypedArray<Dictionary>(); return; } ScriptLanguage *script = GDScriptLanguage::get_singleton(); - Array ret; + TypedArray<Dictionary> ret; for (int i = 0; i < script->debug_get_stack_level_count(); i++) { Dictionary frame; frame["source"] = script->debug_get_stack_level_source(i); @@ -652,8 +653,8 @@ void GDScriptUtilityFunctions::register_functions() { REGISTER_VARARG_FUNC(str, true, Variant::STRING); REGISTER_VARARG_FUNC(range, false, Variant::ARRAY); REGISTER_CLASS_FUNC(load, false, "Resource", ARG("path", Variant::STRING)); - REGISTER_FUNC(inst2dict, false, Variant::DICTIONARY, ARG("instance", Variant::OBJECT)); - REGISTER_FUNC(dict2inst, false, Variant::OBJECT, ARG("dictionary", Variant::DICTIONARY)); + REGISTER_FUNC(inst_to_dict, false, Variant::DICTIONARY, ARG("instance", Variant::OBJECT)); + REGISTER_FUNC(dict_to_inst, false, Variant::OBJECT, ARG("dictionary", Variant::DICTIONARY)); REGISTER_FUNC_DEF(Color8, true, 255, Variant::COLOR, ARG("r8", Variant::INT), ARG("g8", Variant::INT), ARG("b8", Variant::INT), ARG("a8", Variant::INT)); REGISTER_VARARG_FUNC(print_debug, false, Variant::NIL); REGISTER_FUNC_NO_ARGS(print_stack, false, Variant::NIL); diff --git a/modules/gdscript/gdscript_utility_functions.h b/modules/gdscript/gdscript_utility_functions.h index 9ca7cf33d8..0f07db857f 100644 --- a/modules/gdscript/gdscript_utility_functions.h +++ b/modules/gdscript/gdscript_utility_functions.h @@ -34,6 +34,9 @@ #include "core/string/string_name.h" #include "core/variant/variant.h" +template <typename T> +class TypedArray; + class GDScriptUtilityFunctions { public: typedef void (*FunctionPtr)(Variant *r_ret, const Variant **p_args, int p_arg_count, Callable::CallError &r_error); diff --git a/modules/gdscript/language_server/gdscript_workspace.cpp b/modules/gdscript/language_server/gdscript_workspace.cpp index 44b60369ab..fd213e7b37 100644 --- a/modules/gdscript/language_server/gdscript_workspace.cpp +++ b/modules/gdscript/language_server/gdscript_workspace.cpp @@ -228,9 +228,9 @@ void GDScriptWorkspace::list_script_files(const String &p_root_dir, List<String> String file_name = dir->get_next(); while (file_name.length()) { if (dir->current_is_dir() && file_name != "." && file_name != ".." && file_name != "./") { - list_script_files(p_root_dir.plus_file(file_name), r_files); + list_script_files(p_root_dir.path_join(file_name), r_files); } else if (file_name.ends_with(".gd")) { - String script_file = p_root_dir.plus_file(file_name); + String script_file = p_root_dir.path_join(file_name); r_files.push_back(script_file); } file_name = dir->get_next(); diff --git a/modules/gdscript/tests/gdscript_test_runner.cpp b/modules/gdscript/tests/gdscript_test_runner.cpp index e3b956369d..6c346acb7e 100644 --- a/modules/gdscript/tests/gdscript_test_runner.cpp +++ b/modules/gdscript/tests/gdscript_test_runner.cpp @@ -247,7 +247,7 @@ bool GDScriptTestRunner::make_tests_for_dir(const String &p_dir) { next = dir->get_next(); continue; } - if (!make_tests_for_dir(current_dir.plus_file(next))) { + if (!make_tests_for_dir(current_dir.path_join(next))) { return false; } } else { @@ -255,7 +255,7 @@ bool GDScriptTestRunner::make_tests_for_dir(const String &p_dir) { #ifndef DEBUG_ENABLED // On release builds, skip tests marked as debug only. Error open_err = OK; - Ref<FileAccess> script_file(FileAccess::open(current_dir.plus_file(next), FileAccess::READ, &open_err)); + Ref<FileAccess> script_file(FileAccess::open(current_dir.path_join(next), FileAccess::READ, &open_err)); if (open_err != OK) { ERR_PRINT(vformat(R"(Couldn't open test file "%s".)", next)); next = dir->get_next(); @@ -272,7 +272,7 @@ bool GDScriptTestRunner::make_tests_for_dir(const String &p_dir) { if (!is_generating && !dir->file_exists(out_file)) { ERR_FAIL_V_MSG(false, "Could not find output file for " + next); } - GDScriptTest test(current_dir.plus_file(next), current_dir.plus_file(out_file), source_dir); + GDScriptTest test(current_dir.path_join(next), current_dir.path_join(out_file), source_dir); tests.push_back(test); } } |