summaryrefslogtreecommitdiff
path: root/modules
diff options
context:
space:
mode:
Diffstat (limited to 'modules')
-rw-r--r--modules/gdnative/doc_classes/GDNativeLibrary.xml15
-rw-r--r--modules/gdnative/gdnative.cpp2
-rw-r--r--modules/gdnative/register_types.cpp2
-rw-r--r--modules/gdscript/doc_classes/@GDScript.xml8
-rw-r--r--modules/gdscript/editor/gdscript_highlighter.cpp28
-rw-r--r--modules/gdscript/gdscript_function.cpp8
-rw-r--r--modules/gdscript/gdscript_functions.cpp44
-rw-r--r--modules/gdscript/language_server/gdscript_extend_parser.cpp109
-rw-r--r--modules/gdscript/language_server/gdscript_extend_parser.h8
-rw-r--r--modules/gdscript/language_server/gdscript_language_protocol.cpp6
-rw-r--r--modules/gdscript/language_server/gdscript_text_document.cpp86
-rw-r--r--modules/gdscript/language_server/gdscript_text_document.h4
-rw-r--r--modules/gdscript/language_server/gdscript_workspace.cpp35
-rw-r--r--modules/gdscript/language_server/gdscript_workspace.h4
-rw-r--r--modules/gdscript/language_server/lsp.hpp179
-rw-r--r--modules/jsonrpc/jsonrpc.cpp10
-rw-r--r--modules/mono/editor/GodotTools/GodotTools/Build/MsBuildFinder.cs4
-rw-r--r--modules/visual_script/visual_script_editor.cpp111
-rw-r--r--modules/visual_script/visual_script_editor.h1
-rw-r--r--modules/visual_script/visual_script_nodes.cpp19
-rw-r--r--modules/visual_script/visual_script_property_selector.cpp38
21 files changed, 475 insertions, 246 deletions
diff --git a/modules/gdnative/doc_classes/GDNativeLibrary.xml b/modules/gdnative/doc_classes/GDNativeLibrary.xml
index 7e1cac243a..aa48ab44f2 100644
--- a/modules/gdnative/doc_classes/GDNativeLibrary.xml
+++ b/modules/gdnative/doc_classes/GDNativeLibrary.xml
@@ -1,35 +1,50 @@
<?xml version="1.0" encoding="UTF-8" ?>
<class name="GDNativeLibrary" inherits="Resource" category="Core" version="3.2">
<brief_description>
+ An external library containing functions or script classes to use in Godot.
</brief_description>
<description>
+ A GDNative library can implement [NativeScript]s, global functions to call with the [GDNative] class, or low-level engine extensions through interfaces such as [ARVRInterfaceGDNative]. The library must be compiled for each platform and architecture that the project will run on.
</description>
<tutorials>
+ <link>https://docs.godotengine.org/en/latest/tutorials/plugins/gdnative/gdnative-c-example.html</link>
+ <link>https://docs.godotengine.org/en/latest/tutorials/plugins/gdnative/gdnative-cpp-example.html</link>
</tutorials>
<methods>
<method name="get_current_dependencies" qualifiers="const">
<return type="PoolStringArray">
</return>
<description>
+ Returns paths to all dependency libraries for the current platform and architecture.
</description>
</method>
<method name="get_current_library_path" qualifiers="const">
<return type="String">
</return>
<description>
+ Returns the path to the dynamic library file for the current platform and architecture.
</description>
</method>
</methods>
<members>
<member name="config_file" type="ConfigFile" setter="set_config_file" getter="get_config_file">
+ This resource in INI-style [ConfigFile] format, as in [code].gdnlib[/code] files.
</member>
<member name="load_once" type="bool" setter="set_load_once" getter="should_load_once" default="true">
+ If [code]true[/code], Godot loads only one copy of the library and each script that references the library will share static data like static or global variables.
+ If [code]false[/code], Godot loads a separate copy of the library into memory for each script that references it.
</member>
<member name="reloadable" type="bool" setter="set_reloadable" getter="is_reloadable" default="true">
+ If [code]true[/code], the editor will temporarily unload the library whenever the user switches away from the editor window, allowing the user to recompile the library without restarting Godot.
+ [b]Note:[/b] If the library defines tool scripts that run inside the editor, [code]reloadable[/code] must be [code]false[/code]. Otherwise, the editor will attempt to unload the tool scripts while they're in use and crash.
</member>
<member name="singleton" type="bool" setter="set_singleton" getter="is_singleton" default="false">
+ If [code]true[/code], Godot loads the library at startup rather than the first time a script uses the library, calling [code]{prefix}gdnative_singleton[/code] after initializing the library (where [code]{prefix}[/code] is the value of [member symbol_prefix]). The library remains loaded as long as Godot is running.
+ [b]Note:[/b] A singleton library cannot be [member reloadable].
</member>
<member name="symbol_prefix" type="String" setter="set_symbol_prefix" getter="get_symbol_prefix" default="&quot;godot_&quot;">
+ The prefix this library's entry point functions begin with. For example, a GDNativeLibrary would declare its [code]gdnative_init[/code] function as [code]godot_gdnative_init[/code] by default.
+ On platforms that require statically linking libraries (currently only iOS), each library must have a different [code]symbol_prefix[/code].
</member>
</members>
<constants>
diff --git a/modules/gdnative/gdnative.cpp b/modules/gdnative/gdnative.cpp
index 783ad4e147..ee9e71d4a0 100644
--- a/modules/gdnative/gdnative.cpp
+++ b/modules/gdnative/gdnative.cpp
@@ -339,7 +339,7 @@ bool GDNative::initialize() {
if (err || !library_init) {
OS::get_singleton()->close_dynamic_library(native_handle);
native_handle = NULL;
- ERR_PRINT("Failed to obtain godot_gdnative_init symbol");
+ ERR_PRINTS("Failed to obtain " + library->get_symbol_prefix() + "gdnative_init symbol");
return false;
}
diff --git a/modules/gdnative/register_types.cpp b/modules/gdnative/register_types.cpp
index 6ff6262b56..0194199133 100644
--- a/modules/gdnative/register_types.cpp
+++ b/modules/gdnative/register_types.cpp
@@ -277,7 +277,7 @@ void register_gdnative_types() {
proc_ptr);
if (err != OK) {
- ERR_PRINT((String("No godot_gdnative_singleton in \"" + singleton->get_library()->get_current_library_path()) + "\" found").utf8().get_data());
+ ERR_PRINTS("No " + lib->get_symbol_prefix() + "gdnative_singleton in \"" + singleton->get_library()->get_current_library_path() + "\" found");
} else {
singleton_gdnatives.push_back(singleton);
((void (*)())proc_ptr)();
diff --git a/modules/gdscript/doc_classes/@GDScript.xml b/modules/gdscript/doc_classes/@GDScript.xml
index 788db7fb86..1d0567dd8d 100644
--- a/modules/gdscript/doc_classes/@GDScript.xml
+++ b/modules/gdscript/doc_classes/@GDScript.xml
@@ -590,10 +590,10 @@
extends Sprite
var elapsed = 0.0
func _process(delta):
- var min_angle = deg2rad(0.0)
- var max_angle = deg2rad(90.0)
- rotation = lerp_angle(min_angle, max_angle, elapsed)
- elapsed += delta
+ var min_angle = deg2rad(0.0)
+ var max_angle = deg2rad(90.0)
+ rotation = lerp_angle(min_angle, max_angle, elapsed)
+ elapsed += delta
[/codeblock]
</description>
</method>
diff --git a/modules/gdscript/editor/gdscript_highlighter.cpp b/modules/gdscript/editor/gdscript_highlighter.cpp
index 963b40529d..4d6279074c 100644
--- a/modules/gdscript/editor/gdscript_highlighter.cpp
+++ b/modules/gdscript/editor/gdscript_highlighter.cpp
@@ -247,7 +247,7 @@ Map<int, TextEdit::HighlighterInfo> GDScriptSyntaxHighlighter::_get_line_syntax_
in_function_args = false;
}
- if (expect_type && prev_is_char) {
+ if (expect_type && (prev_is_char || str[j] == '=')) {
expect_type = false;
}
@@ -364,20 +364,28 @@ void GDScriptSyntaxHighlighter::_update_cache() {
number_color = text_editor->get_color("number_color");
member_color = text_editor->get_color("member_variable_color");
- EditorSettings *settings = EditorSettings::get_singleton();
- String text_editor_color_theme = settings->get("text_editor/theme/color_theme");
+ const String text_editor_color_theme = EditorSettings::get_singleton()->get("text_editor/theme/color_theme");
+ const bool default_theme = text_editor_color_theme == "Default";
- bool default_theme = text_editor_color_theme == "Default";
- bool dark_theme = settings->is_dark_theme();
-
- function_definition_color = default_theme ? Color(0.0, 0.88, 1.0) : dark_theme ? Color(0.0, 0.88, 1.0) : Color(0.0, 0.65, 0.73);
- node_path_color = default_theme ? Color(0.39, 0.76, 0.35) : dark_theme ? Color(0.39, 0.76, 0.35) : Color(0.32, 0.55, 0.29);
+ if (default_theme || EditorSettings::get_singleton()->is_dark_theme()) {
+ function_definition_color = Color(0.4, 0.9, 1.0);
+ node_path_color = Color(0.39, 0.76, 0.35);
+ } else {
+ function_definition_color = Color(0.0, 0.65, 0.73);
+ node_path_color = Color(0.32, 0.55, 0.29);
+ }
EDITOR_DEF("text_editor/highlighting/gdscript/function_definition_color", function_definition_color);
EDITOR_DEF("text_editor/highlighting/gdscript/node_path_color", node_path_color);
if (text_editor_color_theme == "Adaptive" || default_theme) {
- settings->set_initial_value("text_editor/highlighting/gdscript/function_definition_color", function_definition_color, true);
- settings->set_initial_value("text_editor/highlighting/gdscript/node_path_color", node_path_color, true);
+ EditorSettings::get_singleton()->set_initial_value(
+ "text_editor/highlighting/gdscript/function_definition_color",
+ function_definition_color,
+ true);
+ EditorSettings::get_singleton()->set_initial_value(
+ "text_editor/highlighting/gdscript/node_path_color",
+ node_path_color,
+ true);
}
function_definition_color = EDITOR_GET("text_editor/highlighting/gdscript/function_definition_color");
diff --git a/modules/gdscript/gdscript_function.cpp b/modules/gdscript/gdscript_function.cpp
index bdeea9cef3..83d02e4977 100644
--- a/modules/gdscript/gdscript_function.cpp
+++ b/modules/gdscript/gdscript_function.cpp
@@ -1419,7 +1419,7 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a
if (!container->iter_init(*counter, valid)) {
#ifdef DEBUG_ENABLED
if (!valid) {
- err_text = "Unable to iterate on object of type " + Variant::get_type_name(container->get_type()) + "'.";
+ err_text = "Unable to iterate on object of type '" + Variant::get_type_name(container->get_type()) + "'.";
OPCODE_BREAK;
}
#endif
@@ -1432,7 +1432,7 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a
*iterator = container->iter_get(*counter, valid);
#ifdef DEBUG_ENABLED
if (!valid) {
- err_text = "Unable to obtain iterator object of type " + Variant::get_type_name(container->get_type()) + "'.";
+ err_text = "Unable to obtain iterator object of type '" + Variant::get_type_name(container->get_type()) + "'.";
OPCODE_BREAK;
}
#endif
@@ -1452,7 +1452,7 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a
if (!container->iter_next(*counter, valid)) {
#ifdef DEBUG_ENABLED
if (!valid) {
- err_text = "Unable to iterate on object of type " + Variant::get_type_name(container->get_type()) + "' (type changed since first iteration?).";
+ err_text = "Unable to iterate on object of type '" + Variant::get_type_name(container->get_type()) + "' (type changed since first iteration?).";
OPCODE_BREAK;
}
#endif
@@ -1465,7 +1465,7 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a
*iterator = container->iter_get(*counter, valid);
#ifdef DEBUG_ENABLED
if (!valid) {
- err_text = "Unable to obtain iterator object of type " + Variant::get_type_name(container->get_type()) + "' (but was obtained on first iteration?).";
+ err_text = "Unable to obtain iterator object of type '" + Variant::get_type_name(container->get_type()) + "' (but was obtained on first iteration?).";
OPCODE_BREAK;
}
#endif
diff --git a/modules/gdscript/gdscript_functions.cpp b/modules/gdscript/gdscript_functions.cpp
index 97790e00bb..d9535d0f1f 100644
--- a/modules/gdscript/gdscript_functions.cpp
+++ b/modules/gdscript/gdscript_functions.cpp
@@ -572,37 +572,31 @@ void GDScriptFunctions::call(Function p_func, const Variant **p_args, int p_arg_
} break;
case OBJ_WEAKREF: {
VALIDATE_ARG_COUNT(1);
- if (p_args[0]->get_type() != Variant::OBJECT) {
-
+ if (p_args[0]->get_type() == Variant::OBJECT) {
+ if (p_args[0]->is_ref()) {
+ Ref<WeakRef> wref = memnew(WeakRef);
+ REF r = *p_args[0];
+ if (r.is_valid()) {
+ wref->set_ref(r);
+ }
+ r_ret = wref;
+ } else {
+ Ref<WeakRef> wref = memnew(WeakRef);
+ Object *obj = *p_args[0];
+ if (obj) {
+ wref->set_obj(obj);
+ }
+ r_ret = wref;
+ }
+ } else if (p_args[0]->get_type() == Variant::NIL) {
+ r_ret = memnew(WeakRef);
+ } else {
r_error.error = Variant::CallError::CALL_ERROR_INVALID_ARGUMENT;
r_error.argument = 0;
r_error.expected = Variant::OBJECT;
r_ret = Variant();
return;
}
-
- if (p_args[0]->is_ref()) {
-
- REF r = *p_args[0];
- if (!r.is_valid()) {
- r_ret = Variant();
- return;
- }
-
- Ref<WeakRef> wref = memnew(WeakRef);
- wref->set_ref(r);
- r_ret = wref;
- } else {
- Object *obj = *p_args[0];
- if (!obj) {
- r_ret = Variant();
- return;
- }
- Ref<WeakRef> wref = memnew(WeakRef);
- wref->set_obj(obj);
- r_ret = wref;
- }
-
} break;
case FUNC_FUNCREF: {
VALIDATE_ARG_COUNT(2);
diff --git a/modules/gdscript/language_server/gdscript_extend_parser.cpp b/modules/gdscript/language_server/gdscript_extend_parser.cpp
index 6db8cb2c88..03d731a5f0 100644
--- a/modules/gdscript/language_server/gdscript_extend_parser.cpp
+++ b/modules/gdscript/language_server/gdscript_extend_parser.cpp
@@ -105,6 +105,40 @@ void ExtendGDScriptParser::update_symbols() {
}
}
+void ExtendGDScriptParser::update_document_links(const String &p_code) {
+ document_links.clear();
+
+ GDScriptTokenizerText tokenizer;
+ FileAccessRef fs = FileAccess::create(FileAccess::ACCESS_RESOURCES);
+ tokenizer.set_code(p_code);
+ while (true) {
+ if (tokenizer.get_token() == GDScriptTokenizer::TK_EOF) {
+ break;
+ } else if (tokenizer.get_token() == GDScriptTokenizer::TK_CONSTANT) {
+ Variant const_val = tokenizer.get_token_constant();
+ if (const_val.get_type() == Variant::STRING) {
+ String path = const_val;
+ bool exists = fs->file_exists(path);
+ if (!exists) {
+ path = get_path().get_base_dir() + "/" + path;
+ exists = fs->file_exists(path);
+ }
+ if (exists) {
+ String value = const_val;
+ lsp::DocumentLink link;
+ link.target = GDScriptLanguageProtocol::get_singleton()->get_workspace()->get_file_uri(path);
+ link.range.start.line = LINE_NUMBER_TO_INDEX(tokenizer.get_token_line());
+ link.range.end.line = link.range.start.line;
+ link.range.end.character = LINE_NUMBER_TO_INDEX(tokenizer.get_token_column());
+ link.range.start.character = link.range.end.character - value.length();
+ document_links.push_back(link);
+ }
+ }
+ }
+ tokenizer.advance();
+ }
+}
+
void ExtendGDScriptParser::parse_class_symbol(const GDScriptParser::ClassNode *p_class, lsp::DocumentSymbol &r_symbol) {
const String uri = get_uri();
@@ -123,7 +157,7 @@ void ExtendGDScriptParser::parse_class_symbol(const GDScriptParser::ClassNode *p
r_symbol.selectionRange.start.line = r_symbol.range.start.line;
r_symbol.detail = "class " + r_symbol.name;
bool is_root_class = &r_symbol == &class_symbol;
- r_symbol.documentation = parse_documentation_as_markdown(is_root_class ? 0 : LINE_NUMBER_TO_INDEX(p_class->line), is_root_class);
+ r_symbol.documentation = parse_documentation(is_root_class ? 0 : LINE_NUMBER_TO_INDEX(p_class->line), is_root_class);
for (int i = 0; i < p_class->variables.size(); ++i) {
@@ -150,7 +184,7 @@ void ExtendGDScriptParser::parse_class_symbol(const GDScriptParser::ClassNode *p
symbol.detail += " = " + JSON::print(m.default_value);
}
- symbol.documentation = parse_documentation_as_markdown(line);
+ symbol.documentation = parse_documentation(line);
symbol.uri = uri;
symbol.script_path = path;
@@ -170,7 +204,7 @@ void ExtendGDScriptParser::parse_class_symbol(const GDScriptParser::ClassNode *p
symbol.range.end.line = symbol.range.start.line;
symbol.range.end.character = lines[line].length();
symbol.selectionRange.start.line = symbol.range.start.line;
- symbol.documentation = parse_documentation_as_markdown(line);
+ symbol.documentation = parse_documentation(line);
symbol.uri = uri;
symbol.script_path = path;
symbol.detail = "signal " + signal.name + "(";
@@ -199,7 +233,7 @@ void ExtendGDScriptParser::parse_class_symbol(const GDScriptParser::ClassNode *p
symbol.range.end.line = symbol.range.start.line;
symbol.range.end.character = lines[line].length();
symbol.selectionRange.start.line = symbol.range.start.line;
- symbol.documentation = parse_documentation_as_markdown(line);
+ symbol.documentation = parse_documentation(line);
symbol.uri = uri;
symbol.script_path = path;
@@ -267,7 +301,7 @@ void ExtendGDScriptParser::parse_function_symbol(const GDScriptParser::FunctionN
r_symbol.range.end.line = MAX(p_func->body->end_line - 2, p_func->body->line);
r_symbol.range.end.character = lines[r_symbol.range.end.line].length();
r_symbol.selectionRange.start.line = r_symbol.range.start.line;
- r_symbol.documentation = parse_documentation_as_markdown(line);
+ r_symbol.documentation = parse_documentation(line);
r_symbol.uri = uri;
r_symbol.script_path = path;
@@ -325,65 +359,11 @@ void ExtendGDScriptParser::parse_function_symbol(const GDScriptParser::FunctionN
if (var->datatype.kind != GDScriptParser::DataType::UNRESOLVED) {
symbol.detail += ": " + var->datatype.to_string();
}
- symbol.documentation = parse_documentation_as_markdown(line);
+ symbol.documentation = parse_documentation(line);
r_symbol.children.push_back(symbol);
}
}
-String ExtendGDScriptParser::marked_documentation(const String &p_bbcode) {
-
- String markdown = p_bbcode.strip_edges();
-
- Vector<String> lines = markdown.split("\n");
- bool in_code_block = false;
- int code_block_indent = -1;
-
- markdown = "";
- for (int i = 0; i < lines.size(); i++) {
- String line = lines[i];
- int block_start = line.find("[codeblock]");
- if (block_start != -1) {
- code_block_indent = block_start;
- in_code_block = true;
- line = "'''gdscript\n";
- } else if (in_code_block) {
- line = "\t" + line.substr(code_block_indent, line.length());
- }
-
- if (in_code_block && line.find("[/codeblock]") != -1) {
- line = "'''\n\n";
- in_code_block = false;
- }
-
- if (!in_code_block) {
- line = line.strip_edges();
- line = line.replace("[code]", "`");
- line = line.replace("[/code]", "`");
- line = line.replace("[i]", "*");
- line = line.replace("[/i]", "*");
- line = line.replace("[b]", "**");
- line = line.replace("[/b]", "**");
- line = line.replace("[u]", "__");
- line = line.replace("[/u]", "__");
- line = line.replace("[method ", "`");
- line = line.replace("[member ", "`");
- line = line.replace("[signal ", "`");
- line = line.replace("[enum ", "`");
- line = line.replace("[constant ", "`");
- line = line.replace("[", "`");
- line = line.replace("]", "`");
- }
-
- if (!in_code_block && i < lines.size() - 1) {
- line += "\n\n";
- } else if (i < lines.size() - 1) {
- line += "\n";
- }
- markdown += line;
- }
- return markdown;
-}
-
String ExtendGDScriptParser::parse_documentation(int p_line, bool p_docs_down) {
ERR_FAIL_INDEX_V(p_line, lines.size(), String());
@@ -542,10 +522,6 @@ const lsp::DocumentSymbol *ExtendGDScriptParser::search_symbol_defined_at_line(i
return ret;
}
-String ExtendGDScriptParser::parse_documentation_as_markdown(int p_line, bool p_docs_down) {
- return marked_documentation(parse_documentation(p_line, p_docs_down));
-}
-
const lsp::DocumentSymbol *ExtendGDScriptParser::get_symbol_defined_at_line(int p_line) const {
if (p_line <= 0) {
return &class_symbol;
@@ -572,6 +548,10 @@ const lsp::DocumentSymbol *ExtendGDScriptParser::get_member_symbol(const String
return NULL;
}
+const List<lsp::DocumentLink> &ExtendGDScriptParser::get_document_links() const {
+ return document_links;
+}
+
const Array &ExtendGDScriptParser::get_member_completions() {
if (member_completions.empty()) {
@@ -755,5 +735,6 @@ Error ExtendGDScriptParser::parse(const String &p_code, const String &p_path) {
Error err = GDScriptParser::parse(p_code, p_path.get_base_dir(), false, p_path, false, NULL, false);
update_diagnostics();
update_symbols();
+ update_document_links(p_code);
return err;
}
diff --git a/modules/gdscript/language_server/gdscript_extend_parser.h b/modules/gdscript/language_server/gdscript_extend_parser.h
index dd0453d3ff..a6e0ca5534 100644
--- a/modules/gdscript/language_server/gdscript_extend_parser.h
+++ b/modules/gdscript/language_server/gdscript_extend_parser.h
@@ -56,12 +56,14 @@ class ExtendGDScriptParser : public GDScriptParser {
lsp::DocumentSymbol class_symbol;
Vector<lsp::Diagnostic> diagnostics;
+ List<lsp::DocumentLink> document_links;
ClassMembers members;
HashMap<String, ClassMembers> inner_classes;
void update_diagnostics();
void update_symbols();
+ void update_document_links(const String &p_code);
void parse_class_symbol(const GDScriptParser::ClassNode *p_class, lsp::DocumentSymbol &r_symbol);
void parse_function_symbol(const GDScriptParser::FunctionNode *p_func, lsp::DocumentSymbol &r_symbol);
@@ -73,11 +75,6 @@ class ExtendGDScriptParser : public GDScriptParser {
Array member_completions;
- String parse_documentation_as_markdown(int p_line, bool p_docs_down = false);
-
-public:
- static String marked_documentation(const String &p_bbcode);
-
public:
_FORCE_INLINE_ const String &get_path() const { return path; }
_FORCE_INLINE_ const Vector<String> &get_lines() const { return lines; }
@@ -93,6 +90,7 @@ public:
const lsp::DocumentSymbol *get_symbol_defined_at_line(int p_line) const;
const lsp::DocumentSymbol *get_member_symbol(const String &p_name, const String &p_subclass = "") const;
+ const List<lsp::DocumentLink> &get_document_links() const;
const Array &get_member_completions();
Dictionary generate_api() const;
diff --git a/modules/gdscript/language_server/gdscript_language_protocol.cpp b/modules/gdscript/language_server/gdscript_language_protocol.cpp
index ce3de9bc3b..ae2aaf6aee 100644
--- a/modules/gdscript/language_server/gdscript_language_protocol.cpp
+++ b/modules/gdscript/language_server/gdscript_language_protocol.cpp
@@ -153,7 +153,13 @@ Error GDScriptLanguageProtocol::start(int p_port) {
}
void GDScriptLanguageProtocol::stop() {
+ const int *ptr = clients.next(NULL);
+ while (ptr) {
+ clients.get(*ptr)->close();
+ ptr = clients.next(ptr);
+ }
server->stop();
+ clients.clear();
}
void GDScriptLanguageProtocol::notify_all_clients(const String &p_method, const Variant &p_params) {
diff --git a/modules/gdscript/language_server/gdscript_text_document.cpp b/modules/gdscript/language_server/gdscript_text_document.cpp
index 7c58c7aa15..b83db718b8 100644
--- a/modules/gdscript/language_server/gdscript_text_document.cpp
+++ b/modules/gdscript/language_server/gdscript_text_document.cpp
@@ -39,6 +39,7 @@
void GDScriptTextDocument::_bind_methods() {
ClassDB::bind_method(D_METHOD("didOpen"), &GDScriptTextDocument::didOpen);
ClassDB::bind_method(D_METHOD("didChange"), &GDScriptTextDocument::didChange);
+ ClassDB::bind_method(D_METHOD("nativeSymbol"), &GDScriptTextDocument::nativeSymbol);
ClassDB::bind_method(D_METHOD("documentSymbol"), &GDScriptTextDocument::documentSymbol);
ClassDB::bind_method(D_METHOD("completion"), &GDScriptTextDocument::completion);
ClassDB::bind_method(D_METHOD("resolve"), &GDScriptTextDocument::resolve);
@@ -75,6 +76,11 @@ lsp::TextDocumentItem GDScriptTextDocument::load_document_item(const Variant &p_
return doc;
}
+void GDScriptTextDocument::notify_client_show_symbol(const lsp::DocumentSymbol *symbol) {
+ ERR_FAIL_NULL(symbol);
+ GDScriptLanguageProtocol::get_singleton()->notify_client("gdscript/show_native_symbol", symbol->to_json(true));
+}
+
void GDScriptTextDocument::initialize() {
if (GDScriptLanguageProtocol::get_singleton()->is_smart_resolve_enabled()) {
@@ -102,6 +108,21 @@ void GDScriptTextDocument::initialize() {
}
}
+Variant GDScriptTextDocument::nativeSymbol(const Dictionary &p_params) {
+
+ Variant ret;
+
+ lsp::NativeSymbolInspectParams params;
+ params.load(p_params);
+
+ if (const lsp::DocumentSymbol *symbol = GDScriptLanguageProtocol::get_singleton()->get_workspace()->resolve_native_symbol(params)) {
+ ret = symbol->to_json(true);
+ notify_client_show_symbol(symbol);
+ }
+
+ return ret;
+}
+
Array GDScriptTextDocument::documentSymbol(const Dictionary &p_params) {
Dictionary params = p_params["textDocument"];
String uri = params["uri"];
@@ -271,8 +292,17 @@ Array GDScriptTextDocument::codeLens(const Dictionary &p_params) {
return arr;
}
-Variant GDScriptTextDocument::documentLink(const Dictionary &p_params) {
- Variant ret;
+Array GDScriptTextDocument::documentLink(const Dictionary &p_params) {
+ Array ret;
+
+ lsp::DocumentLinkParams params;
+ params.load(p_params);
+
+ List<lsp::DocumentLink> links;
+ GDScriptLanguageProtocol::get_singleton()->get_workspace()->resolve_document_links(params.textDocument.uri, links);
+ for (const List<lsp::DocumentLink>::Element *E = links.front(); E; E = E->next()) {
+ ret.push_back(E->get().to_json());
+ }
return ret;
}
@@ -326,31 +356,35 @@ Array GDScriptTextDocument::definition(const Dictionary &p_params) {
const String &path = GDScriptLanguageProtocol::get_singleton()->get_workspace()->get_file_path(symbol->uri);
if (file_checker->file_exists(path)) {
arr.push_back(location.to_json());
- } else if (!symbol->native_class.empty() && GDScriptLanguageProtocol::get_singleton()->is_goto_native_symbols_enabled()) {
- String id;
- switch (symbol->kind) {
- case lsp::SymbolKind::Class:
- id = "class_name:" + symbol->name;
- break;
- case lsp::SymbolKind::Constant:
- id = "class_constant:" + symbol->native_class + ":" + symbol->name;
- break;
- case lsp::SymbolKind::Property:
- case lsp::SymbolKind::Variable:
- id = "class_property:" + symbol->native_class + ":" + symbol->name;
- break;
- case lsp::SymbolKind::Enum:
- id = "class_enum:" + symbol->native_class + ":" + symbol->name;
- break;
- case lsp::SymbolKind::Method:
- case lsp::SymbolKind::Function:
- id = "class_method:" + symbol->native_class + ":" + symbol->name;
- break;
- default:
- id = "class_global:" + symbol->native_class + ":" + symbol->name;
- break;
+ } else if (!symbol->native_class.empty()) {
+ if (GDScriptLanguageProtocol::get_singleton()->is_goto_native_symbols_enabled()) {
+ String id;
+ switch (symbol->kind) {
+ case lsp::SymbolKind::Class:
+ id = "class_name:" + symbol->name;
+ break;
+ case lsp::SymbolKind::Constant:
+ id = "class_constant:" + symbol->native_class + ":" + symbol->name;
+ break;
+ case lsp::SymbolKind::Property:
+ case lsp::SymbolKind::Variable:
+ id = "class_property:" + symbol->native_class + ":" + symbol->name;
+ break;
+ case lsp::SymbolKind::Enum:
+ id = "class_enum:" + symbol->native_class + ":" + symbol->name;
+ break;
+ case lsp::SymbolKind::Method:
+ case lsp::SymbolKind::Function:
+ id = "class_method:" + symbol->native_class + ":" + symbol->name;
+ break;
+ default:
+ id = "class_global:" + symbol->native_class + ":" + symbol->name;
+ break;
+ }
+ call_deferred("show_native_symbol_in_editor", id);
+ } else {
+ notify_client_show_symbol(symbol);
}
- call_deferred("show_native_symbol_in_editor", id);
}
} else if (GDScriptLanguageProtocol::get_singleton()->is_smart_resolve_enabled()) {
diff --git a/modules/gdscript/language_server/gdscript_text_document.h b/modules/gdscript/language_server/gdscript_text_document.h
index d15022d2c4..235e2c3f6e 100644
--- a/modules/gdscript/language_server/gdscript_text_document.h
+++ b/modules/gdscript/language_server/gdscript_text_document.h
@@ -52,14 +52,16 @@ protected:
private:
lsp::TextDocumentItem load_document_item(const Variant &p_param);
+ void notify_client_show_symbol(const lsp::DocumentSymbol *symbol);
public:
+ Variant nativeSymbol(const Dictionary &p_params);
Array documentSymbol(const Dictionary &p_params);
Array completion(const Dictionary &p_params);
Dictionary resolve(const Dictionary &p_params);
Array foldingRange(const Dictionary &p_params);
Array codeLens(const Dictionary &p_params);
- Variant documentLink(const Dictionary &p_params);
+ Array documentLink(const Dictionary &p_params);
Array colorPresentation(const Dictionary &p_params);
Variant hover(const Dictionary &p_params);
Array definition(const Dictionary &p_params);
diff --git a/modules/gdscript/language_server/gdscript_workspace.cpp b/modules/gdscript/language_server/gdscript_workspace.cpp
index 1901daacff..6baa7e4219 100644
--- a/modules/gdscript/language_server/gdscript_workspace.cpp
+++ b/modules/gdscript/language_server/gdscript_workspace.cpp
@@ -198,7 +198,7 @@ Error GDScriptWorkspace::initialize() {
if (!class_data.inherits.empty()) {
class_symbol.detail += " extends " + class_data.inherits;
}
- class_symbol.documentation = ExtendGDScriptParser::marked_documentation(class_data.brief_description) + "\n" + ExtendGDScriptParser::marked_documentation(class_data.description);
+ class_symbol.documentation = class_data.brief_description + "\n" + class_data.description;
for (int i = 0; i < class_data.constants.size(); i++) {
const DocData::ConstantDoc &const_data = class_data.constants[i];
@@ -211,7 +211,7 @@ Error GDScriptWorkspace::initialize() {
symbol.detail += ": " + const_data.enumeration;
}
symbol.detail += " = " + const_data.value;
- symbol.documentation = ExtendGDScriptParser::marked_documentation(const_data.description);
+ symbol.documentation = const_data.description;
class_symbol.children.push_back(symbol);
}
@@ -232,7 +232,7 @@ Error GDScriptWorkspace::initialize() {
} else {
symbol.detail += ": " + data.type;
}
- symbol.documentation = ExtendGDScriptParser::marked_documentation(data.description);
+ symbol.documentation = data.description;
class_symbol.children.push_back(symbol);
}
@@ -270,7 +270,7 @@ Error GDScriptWorkspace::initialize() {
}
symbol.detail = "func " + class_name + "." + data.name + "(" + params + ") -> " + data.return_type;
- symbol.documentation = ExtendGDScriptParser::marked_documentation(data.description);
+ symbol.documentation = data.description;
class_symbol.children.push_back(symbol);
}
@@ -475,6 +475,33 @@ void GDScriptWorkspace::resolve_related_symbols(const lsp::TextDocumentPositionP
}
}
+const lsp::DocumentSymbol *GDScriptWorkspace::resolve_native_symbol(const lsp::NativeSymbolInspectParams &p_params) {
+
+ if (Map<StringName, lsp::DocumentSymbol>::Element *E = native_symbols.find(p_params.native_class)) {
+ const lsp::DocumentSymbol &symbol = E->get();
+ if (p_params.symbol_name.empty() || p_params.symbol_name == symbol.name) {
+ return &symbol;
+ }
+
+ for (int i = 0; i < symbol.children.size(); ++i) {
+ if (symbol.children[i].name == p_params.symbol_name) {
+ return &(symbol.children[i]);
+ }
+ }
+ }
+
+ return NULL;
+}
+
+void GDScriptWorkspace::resolve_document_links(const String &p_uri, List<lsp::DocumentLink> &r_list) {
+ if (const ExtendGDScriptParser *parser = get_parse_successed_script(get_file_path(p_uri))) {
+ const List<lsp::DocumentLink> &links = parser->get_document_links();
+ for (const List<lsp::DocumentLink>::Element *E = links.front(); E; E = E->next()) {
+ r_list.push_back(E->get());
+ }
+ }
+}
+
Dictionary GDScriptWorkspace::generate_script_api(const String &p_path) {
Dictionary api;
if (const ExtendGDScriptParser *parser = get_parse_successed_script(p_path)) {
diff --git a/modules/gdscript/language_server/gdscript_workspace.h b/modules/gdscript/language_server/gdscript_workspace.h
index adce169d4b..a416ae1075 100644
--- a/modules/gdscript/language_server/gdscript_workspace.h
+++ b/modules/gdscript/language_server/gdscript_workspace.h
@@ -53,7 +53,6 @@ protected:
ExtendGDScriptParser *get_parse_successed_script(const String &p_path);
ExtendGDScriptParser *get_parse_result(const String &p_path);
- void strip_flat_symbols(const String &p_branch);
void list_script_files(const String &p_root_dir, List<String> &r_files);
public:
@@ -81,7 +80,8 @@ public:
const lsp::DocumentSymbol *resolve_symbol(const lsp::TextDocumentPositionParams &p_doc_pos, const String &p_symbol_name = "", bool p_func_requred = false);
void resolve_related_symbols(const lsp::TextDocumentPositionParams &p_doc_pos, List<const lsp::DocumentSymbol *> &r_list);
-
+ const lsp::DocumentSymbol *resolve_native_symbol(const lsp::NativeSymbolInspectParams &p_params);
+ void resolve_document_links(const String &p_uri, List<lsp::DocumentLink> &r_list);
Dictionary generate_script_api(const String &p_path);
GDScriptWorkspace();
diff --git a/modules/gdscript/language_server/lsp.hpp b/modules/gdscript/language_server/lsp.hpp
index 3e57b6ee7e..61a0980c41 100644
--- a/modules/gdscript/language_server/lsp.hpp
+++ b/modules/gdscript/language_server/lsp.hpp
@@ -37,6 +37,9 @@ namespace lsp {
typedef String DocumentUri;
+/** Format BBCode documentation from DocData to markdown */
+static String marked_documentation(const String &p_bbcode);
+
/**
* Text documents are identified using a URI. On the protocol level, URIs are passed as strings.
*/
@@ -199,6 +202,41 @@ struct TextDocumentPositionParams {
}
};
+struct DocumentLinkParams {
+ /**
+ * The document to provide document links for.
+ */
+ TextDocumentIdentifier textDocument;
+
+ _FORCE_INLINE_ void load(const Dictionary &p_params) {
+ textDocument.load(p_params["textDocument"]);
+ }
+};
+
+/**
+ * A document link is a range in a text document that links to an internal or external resource, like another
+ * text document or a web site.
+ */
+struct DocumentLink {
+
+ /**
+ * The range this link applies to.
+ */
+ Range range;
+
+ /**
+ * The uri this link points to. If missing a resolve request is sent later.
+ */
+ DocumentUri target;
+
+ Dictionary to_json() const {
+ Dictionary dict;
+ dict["range"] = range.to_json();
+ dict["target"] = target;
+ return dict;
+ }
+};
+
/**
* A textual edit applicable to a text document.
*/
@@ -247,6 +285,9 @@ struct Command {
}
};
+// Use namespace instead of enumeration to follow the LSP specifications
+// lsp::EnumName::EnumValue is OK but lsp::EnumValue is not
+
namespace TextDocumentSyncKind {
/**
* Documents should not be synced at all.
@@ -557,6 +598,7 @@ struct TextDocumentContentChangeEvent {
}
};
+// Use namespace instead of enumeration to follow the LSP specifications
namespace DiagnosticSeverity {
/**
* Reports an error.
@@ -657,6 +699,7 @@ struct Diagnostic {
}
};
+// Use namespace instead of enumeration to follow the LSP specifications
/**
* Describes the content type that a client supports in various
* result literals like `Hover`, `ParameterInfo` or `CompletionItem`.
@@ -721,6 +764,9 @@ struct MarkupContent {
}
};
+// Use namespace instead of enumeration to follow the LSP specifications
+// lsp::EnumName::EnumValue is OK but lsp::EnumValue is not
+// And here C++ compilers are unhappy with our enumeration name like Color, File, Reference etc.
/**
* The kind of a completion entry.
*/
@@ -752,6 +798,7 @@ static const int Operator = 24;
static const int TypeParameter = 25;
}; // namespace CompletionItemKind
+// Use namespace instead of enumeration to follow the LSP specifications
/**
* Defines whether the insert text in a completion item should be interpreted as
* plain text or a snippet.
@@ -944,36 +991,39 @@ struct CompletionList {
Vector<CompletionItem> items;
};
+// Use namespace instead of enumeration to follow the LSP specifications
+// lsp::EnumName::EnumValue is OK but lsp::EnumValue is not
+// And here C++ compilers are unhappy with our enumeration name like String, Array, Object etc
/**
* A symbol kind.
*/
namespace SymbolKind {
-static const int File = 1;
-static const int Module = 2;
-static const int Namespace = 3;
-static const int Package = 4;
-static const int Class = 5;
-static const int Method = 6;
-static const int Property = 7;
-static const int Field = 8;
-static const int Constructor = 9;
-static const int Enum = 10;
-static const int Interface = 11;
-static const int Function = 12;
-static const int Variable = 13;
-static const int Constant = 14;
-static const int String = 15;
-static const int Number = 16;
-static const int Boolean = 17;
-static const int Array = 18;
-static const int Object = 19;
-static const int Key = 20;
-static const int Null = 21;
-static const int EnumMember = 22;
-static const int Struct = 23;
-static const int Event = 24;
-static const int Operator = 25;
-static const int TypeParameter = 26;
+static const int File = 0;
+static const int Module = 1;
+static const int Namespace = 2;
+static const int Package = 3;
+static const int Class = 4;
+static const int Method = 5;
+static const int Property = 6;
+static const int Field = 7;
+static const int Constructor = 8;
+static const int Enum = 9;
+static const int Interface = 10;
+static const int Function = 11;
+static const int Variable = 12;
+static const int Constant = 13;
+static const int String = 14;
+static const int Number = 15;
+static const int Boolean = 16;
+static const int Array = 17;
+static const int Object = 18;
+static const int Key = 19;
+static const int Null = 20;
+static const int EnumMember = 21;
+static const int Struct = 22;
+static const int Event = 23;
+static const int Operator = 24;
+static const int TypeParameter = 25;
}; // namespace SymbolKind
/**
@@ -1099,7 +1149,7 @@ struct DocumentSymbol {
*/
Vector<DocumentSymbol> children;
- _FORCE_INLINE_ Dictionary to_json() const {
+ Dictionary to_json(bool with_doc = false) const {
Dictionary dict;
dict["name"] = name;
dict["detail"] = detail;
@@ -1107,10 +1157,14 @@ struct DocumentSymbol {
dict["deprecated"] = deprecated;
dict["range"] = range.to_json();
dict["selectionRange"] = selectionRange.to_json();
+ if (with_doc) {
+ dict["documentation"] = documentation;
+ dict["native_class"] = native_class;
+ }
Array arr;
arr.resize(children.size());
for (int i = 0; i < children.size(); i++) {
- arr[i] = children[i].to_json();
+ arr[i] = children[i].to_json(with_doc);
}
dict["children"] = arr;
return dict;
@@ -1142,7 +1196,7 @@ struct DocumentSymbol {
markdown.value = "\t" + detail + "\n\n";
}
if (documentation.length()) {
- markdown.value += documentation + "\n\n";
+ markdown.value += marked_documentation(documentation) + "\n\n";
}
if (script_path.length()) {
markdown.value += "Defined in [" + script_path + "](" + uri + ")";
@@ -1194,6 +1248,17 @@ struct DocumentSymbol {
}
};
+struct NativeSymbolInspectParams {
+
+ String native_class;
+ String symbol_name;
+
+ void load(const Dictionary &p_params) {
+ native_class = p_params["native_class"];
+ symbol_name = p_params["symbol_name"];
+ }
+};
+
/**
* Enum of known range kinds
*/
@@ -1254,6 +1319,7 @@ struct FoldingRange {
}
};
+// Use namespace instead of enumeration to follow the LSP specifications
/**
* How a completion was triggered
*/
@@ -1501,6 +1567,61 @@ struct InitializeResult {
}
};
+/** Format BBCode documentation from DocData to markdown */
+static String marked_documentation(const String &p_bbcode) {
+
+ String markdown = p_bbcode.strip_edges();
+
+ Vector<String> lines = markdown.split("\n");
+ bool in_code_block = false;
+ int code_block_indent = -1;
+
+ markdown = "";
+ for (int i = 0; i < lines.size(); i++) {
+ String line = lines[i];
+ int block_start = line.find("[codeblock]");
+ if (block_start != -1) {
+ code_block_indent = block_start;
+ in_code_block = true;
+ line = "\n";
+ } else if (in_code_block) {
+ line = "\t" + line.substr(code_block_indent, line.length());
+ }
+
+ if (in_code_block && line.find("[/codeblock]") != -1) {
+ line = "\n";
+ in_code_block = false;
+ }
+
+ if (!in_code_block) {
+ line = line.strip_edges();
+ line = line.replace("[code]", "`");
+ line = line.replace("[/code]", "`");
+ line = line.replace("[i]", "*");
+ line = line.replace("[/i]", "*");
+ line = line.replace("[b]", "**");
+ line = line.replace("[/b]", "**");
+ line = line.replace("[u]", "__");
+ line = line.replace("[/u]", "__");
+ line = line.replace("[method ", "`");
+ line = line.replace("[member ", "`");
+ line = line.replace("[signal ", "`");
+ line = line.replace("[enum ", "`");
+ line = line.replace("[constant ", "`");
+ line = line.replace("[", "`");
+ line = line.replace("]", "`");
+ }
+
+ if (!in_code_block && i < lines.size() - 1) {
+ line += "\n\n";
+ } else if (i < lines.size() - 1) {
+ line += "\n";
+ }
+ markdown += line;
+ }
+ return markdown;
+}
+
} // namespace lsp
#endif
diff --git a/modules/jsonrpc/jsonrpc.cpp b/modules/jsonrpc/jsonrpc.cpp
index e1bba60f2f..ea90cce83d 100644
--- a/modules/jsonrpc/jsonrpc.cpp
+++ b/modules/jsonrpc/jsonrpc.cpp
@@ -47,11 +47,11 @@ void JSONRPC::_bind_methods() {
ClassDB::bind_method(D_METHOD("make_notification", "method", "params"), &JSONRPC::make_notification);
ClassDB::bind_method(D_METHOD("make_response_error", "code", "message", "id"), &JSONRPC::make_response_error, DEFVAL(Variant()));
- BIND_ENUM_CONSTANT(PARSE_ERROR)
- BIND_ENUM_CONSTANT(INVALID_REQUEST)
- BIND_ENUM_CONSTANT(METHOD_NOT_FOUND)
- BIND_ENUM_CONSTANT(INVALID_PARAMS)
- BIND_ENUM_CONSTANT(INTERNAL_ERROR)
+ BIND_ENUM_CONSTANT(PARSE_ERROR);
+ BIND_ENUM_CONSTANT(INVALID_REQUEST);
+ BIND_ENUM_CONSTANT(METHOD_NOT_FOUND);
+ BIND_ENUM_CONSTANT(INVALID_PARAMS);
+ BIND_ENUM_CONSTANT(INTERNAL_ERROR);
}
Dictionary JSONRPC::make_response_error(int p_code, const String &p_message, const Variant &p_id) const {
diff --git a/modules/mono/editor/GodotTools/GodotTools/Build/MsBuildFinder.cs b/modules/mono/editor/GodotTools/GodotTools/Build/MsBuildFinder.cs
index 4c1e47ecad..eb2c2dd77c 100644
--- a/modules/mono/editor/GodotTools/GodotTools/Build/MsBuildFinder.cs
+++ b/modules/mono/editor/GodotTools/GodotTools/Build/MsBuildFinder.cs
@@ -34,7 +34,7 @@ namespace GodotTools.Build
if (_msbuildToolsPath.Empty())
{
- throw new FileNotFoundException($"Cannot find executable for '{BuildManager.PropNameMsbuildVs}'. Tried with path: {_msbuildToolsPath}");
+ throw new FileNotFoundException($"Cannot find executable for '{BuildManager.PropNameMsbuildVs}'.");
}
}
@@ -142,7 +142,7 @@ namespace GodotTools.Build
int exitCode = Godot.OS.Execute(vsWherePath, vsWhereArgs,
blocking: true, output: (Godot.Collections.Array) outputArray);
- if (exitCode == 0)
+ if (exitCode != 0)
return string.Empty;
if (outputArray.Count == 0)
diff --git a/modules/visual_script/visual_script_editor.cpp b/modules/visual_script/visual_script_editor.cpp
index 0399dbc87c..093901ad07 100644
--- a/modules/visual_script/visual_script_editor.cpp
+++ b/modules/visual_script/visual_script_editor.cpp
@@ -1166,13 +1166,11 @@ void VisualScriptEditor::_member_edited() {
}
void VisualScriptEditor::_create_function_dialog() {
- function_create_dialog->popup();
- function_create_dialog->set_position(graph->get_global_position() + Vector2(55, 80));
+ function_create_dialog->popup_centered();
func_name_box->set_text("");
func_name_box->grab_focus();
for (int i = 0; i < func_input_vbox->get_child_count(); i++) {
Node *nd = func_input_vbox->get_child(i);
- func_input_vbox->remove_child(nd);
nd->queue_delete();
}
}
@@ -1252,7 +1250,6 @@ void VisualScriptEditor::_add_func_input() {
func_input_vbox->add_child(hbox);
hbox->set_meta("id", hbox->get_position_in_parent());
- function_create_dialog->set_size(Size2(-1, -1));
delete_button->connect("pressed", this, "_remove_func_input", varray(hbox));
@@ -1263,7 +1260,6 @@ void VisualScriptEditor::_add_func_input() {
void VisualScriptEditor::_remove_func_input(Node *p_node) {
func_input_vbox->remove_child(p_node);
p_node->queue_delete();
- function_create_dialog->set_size(Size2(-1, -1));
}
void VisualScriptEditor::_deselect_input_names() {
@@ -1353,6 +1349,8 @@ void VisualScriptEditor::_member_button(Object *p_item, int p_column, int p_butt
selected = ti->get_text(0);
function_name_edit->set_position(Input::get_singleton()->get_mouse_position() - Vector2(60, -10));
function_name_edit->popup();
+ function_name_box->set_text(selected);
+ function_name_box->select_all();
}
}
@@ -1757,8 +1755,7 @@ void VisualScriptEditor::_members_gui_input(const Ref<InputEvent> &p_event) {
Ref<InputEventMouseButton> btn = p_event;
if (btn.is_valid() && btn->is_doubleclick()) {
TreeItem *ti = members->get_selected();
- ERR_FAIL_COND(!ti);
- if (ti->get_parent() == members->get_root()->get_children()) // to check if it's a function
+ if (ti && ti->get_parent() == members->get_root()->get_children()) // to check if it's a function
_center_on_node(ti->get_metadata(0), script->get_function_node_id(ti->get_metadata(0)));
}
}
@@ -3907,51 +3904,62 @@ void VisualScriptEditor::_hide_timer() {
void VisualScriptEditor::_notification(int p_what) {
- if (p_what == NOTIFICATION_READY || (p_what == NOTIFICATION_THEME_CHANGED && is_visible_in_tree())) {
- if (p_what == NOTIFICATION_READY) {
+ switch (p_what) {
+ case NOTIFICATION_READY: {
variable_editor->connect("changed", this, "_update_members");
signal_editor->connect("changed", this, "_update_members");
+ FALLTHROUGH;
}
+ case NOTIFICATION_THEME_CHANGED: {
+ if (p_what != NOTIFICATION_READY && !is_visible_in_tree()) {
+ return;
+ }
- Ref<Theme> tm = EditorNode::get_singleton()->get_theme_base()->get_theme();
+ edit_variable_edit->add_style_override("bg", get_stylebox("bg", "Tree"));
+ edit_signal_edit->add_style_override("bg", get_stylebox("bg", "Tree"));
+ func_input_scroll->add_style_override("bg", get_stylebox("bg", "Tree"));
- bool dark_theme = tm->get_constant("dark_theme", "Editor");
+ Ref<Theme> tm = EditorNode::get_singleton()->get_theme_base()->get_theme();
- List<Pair<String, Color> > colors;
- if (dark_theme) {
- colors.push_back(Pair<String, Color>("flow_control", Color(0.96, 0.96, 0.96)));
- colors.push_back(Pair<String, Color>("functions", Color(0.96, 0.52, 0.51)));
- colors.push_back(Pair<String, Color>("data", Color(0.5, 0.96, 0.81)));
- colors.push_back(Pair<String, Color>("operators", Color(0.67, 0.59, 0.87)));
- colors.push_back(Pair<String, Color>("custom", Color(0.5, 0.73, 0.96)));
- colors.push_back(Pair<String, Color>("constants", Color(0.96, 0.5, 0.69)));
- } else {
- colors.push_back(Pair<String, Color>("flow_control", Color(0.26, 0.26, 0.26)));
- colors.push_back(Pair<String, Color>("functions", Color(0.95, 0.4, 0.38)));
- colors.push_back(Pair<String, Color>("data", Color(0.07, 0.73, 0.51)));
- colors.push_back(Pair<String, Color>("operators", Color(0.51, 0.4, 0.82)));
- colors.push_back(Pair<String, Color>("custom", Color(0.31, 0.63, 0.95)));
- colors.push_back(Pair<String, Color>("constants", Color(0.94, 0.18, 0.49)));
- }
+ bool dark_theme = tm->get_constant("dark_theme", "Editor");
- for (List<Pair<String, Color> >::Element *E = colors.front(); E; E = E->next()) {
- Ref<StyleBoxFlat> sb = tm->get_stylebox("frame", "GraphNode");
- if (!sb.is_null()) {
- Ref<StyleBoxFlat> frame_style = sb->duplicate();
- Color c = sb->get_border_color();
- Color cn = E->get().second;
- cn.a = c.a;
- frame_style->set_border_color(cn);
- node_styles[E->get().first] = frame_style;
+ List<Pair<String, Color> > colors;
+ if (dark_theme) {
+ colors.push_back(Pair<String, Color>("flow_control", Color(0.96, 0.96, 0.96)));
+ colors.push_back(Pair<String, Color>("functions", Color(0.96, 0.52, 0.51)));
+ colors.push_back(Pair<String, Color>("data", Color(0.5, 0.96, 0.81)));
+ colors.push_back(Pair<String, Color>("operators", Color(0.67, 0.59, 0.87)));
+ colors.push_back(Pair<String, Color>("custom", Color(0.5, 0.73, 0.96)));
+ colors.push_back(Pair<String, Color>("constants", Color(0.96, 0.5, 0.69)));
+ } else {
+ colors.push_back(Pair<String, Color>("flow_control", Color(0.26, 0.26, 0.26)));
+ colors.push_back(Pair<String, Color>("functions", Color(0.95, 0.4, 0.38)));
+ colors.push_back(Pair<String, Color>("data", Color(0.07, 0.73, 0.51)));
+ colors.push_back(Pair<String, Color>("operators", Color(0.51, 0.4, 0.82)));
+ colors.push_back(Pair<String, Color>("custom", Color(0.31, 0.63, 0.95)));
+ colors.push_back(Pair<String, Color>("constants", Color(0.94, 0.18, 0.49)));
}
- }
- if (is_visible_in_tree() && script.is_valid()) {
- _update_members();
- _update_graph();
- }
- } else if (p_what == NOTIFICATION_VISIBILITY_CHANGED) {
- members_section->set_visible(is_visible_in_tree());
+ for (List<Pair<String, Color> >::Element *E = colors.front(); E; E = E->next()) {
+ Ref<StyleBoxFlat> sb = tm->get_stylebox("frame", "GraphNode");
+ if (!sb.is_null()) {
+ Ref<StyleBoxFlat> frame_style = sb->duplicate();
+ Color c = sb->get_border_color();
+ Color cn = E->get().second;
+ cn.a = c.a;
+ frame_style->set_border_color(cn);
+ node_styles[E->get().first] = frame_style;
+ }
+ }
+
+ if (is_visible_in_tree() && script.is_valid()) {
+ _update_members();
+ _update_graph();
+ }
+ } break;
+ case NOTIFICATION_VISIBILITY_CHANGED: {
+ members_section->set_visible(is_visible_in_tree());
+ } break;
}
}
@@ -4541,6 +4549,8 @@ void VisualScriptEditor::_member_option(int p_option) {
} else if (p_option == MEMBER_EDIT) {
selected = members->get_selected()->get_text(0);
function_name_edit->popup();
+ function_name_box->set_text(selected);
+ function_name_box->select_all();
}
} break;
case MEMBER_VARIABLE: {
@@ -4762,7 +4772,7 @@ VisualScriptEditor::VisualScriptEditor() {
add_nds->connect("pressed", this, "_add_node_dialog");
Button *fn_btn = memnew(Button);
- fn_btn->set_text("Add Function");
+ fn_btn->set_text("Add Function...");
graph_hbc->add_child(fn_btn);
fn_btn->connect("pressed", this, "_create_function_dialog");
@@ -4790,17 +4800,20 @@ VisualScriptEditor::VisualScriptEditor() {
Button *add_input_button = memnew(Button);
add_input_button->set_h_size_flags(SIZE_EXPAND_FILL);
- add_input_button->set_text(TTR("Add input +"));
+ add_input_button->set_text(TTR("Add Input"));
add_input_button->connect("pressed", this, "_add_func_input");
function_vb->add_child(add_input_button);
- func_input_vbox = memnew(VBoxContainer);
- function_vb->add_child(func_input_vbox);
+ func_input_scroll = memnew(ScrollContainer);
+ func_input_scroll->set_v_size_flags(SIZE_EXPAND_FILL);
+ function_vb->add_child(func_input_scroll);
- function_vb->add_child(memnew(HSeparator));
+ func_input_vbox = memnew(VBoxContainer);
+ func_input_vbox->set_h_size_flags(SIZE_EXPAND_FILL);
+ func_input_scroll->add_child(func_input_vbox);
function_create_dialog = memnew(ConfirmationDialog);
- function_create_dialog->set_custom_minimum_size(Size2(450 * EDSCALE, 0));
+ function_create_dialog->set_custom_minimum_size(Size2(450, 300) * EDSCALE);
function_create_dialog->set_v_size_flags(SIZE_EXPAND_FILL);
function_create_dialog->set_title(TTR("Create Function"));
function_create_dialog->add_child(function_vb);
diff --git a/modules/visual_script/visual_script_editor.h b/modules/visual_script/visual_script_editor.h
index 0e7783214b..5a00469eea 100644
--- a/modules/visual_script/visual_script_editor.h
+++ b/modules/visual_script/visual_script_editor.h
@@ -89,6 +89,7 @@ class VisualScriptEditor : public ScriptEditorBase {
Button *base_type_select;
LineEdit *func_name_box;
+ ScrollContainer *func_input_scroll;
VBoxContainer *func_input_vbox;
ConfirmationDialog *function_create_dialog;
diff --git a/modules/visual_script/visual_script_nodes.cpp b/modules/visual_script/visual_script_nodes.cpp
index dbcd3c19f8..957127fe61 100644
--- a/modules/visual_script/visual_script_nodes.cpp
+++ b/modules/visual_script/visual_script_nodes.cpp
@@ -4075,6 +4075,14 @@ VisualScriptDeconstruct::VisualScriptDeconstruct() {
type = Variant::NIL;
}
+template <Variant::Type T>
+static Ref<VisualScriptNode> create_node_deconst_typed(const String &p_name) {
+ Ref<VisualScriptDeconstruct> node;
+ node.instance();
+ node->set_deconstruct_type(T);
+ return node;
+}
+
void register_visual_script_nodes() {
VisualScriptLanguage::singleton->add_register_func("data/set_variable", create_node_generic<VisualScriptVariableSet>);
@@ -4132,7 +4140,16 @@ void register_visual_script_nodes() {
VisualScriptLanguage::singleton->add_register_func("operators/logic/in", create_op_node<Variant::OP_IN>);
VisualScriptLanguage::singleton->add_register_func("operators/logic/select", create_node_generic<VisualScriptSelect>);
- VisualScriptLanguage::singleton->add_register_func("functions/deconstruct", create_node_generic<VisualScriptDeconstruct>);
+ VisualScriptLanguage::singleton->add_register_func("functions/deconstruct/" + Variant::get_type_name(Variant::Type::VECTOR2), create_node_deconst_typed<Variant::Type::VECTOR2>);
+ VisualScriptLanguage::singleton->add_register_func("functions/deconstruct/" + Variant::get_type_name(Variant::Type::VECTOR3), create_node_deconst_typed<Variant::Type::VECTOR3>);
+ VisualScriptLanguage::singleton->add_register_func("functions/deconstruct/" + Variant::get_type_name(Variant::Type::COLOR), create_node_deconst_typed<Variant::Type::COLOR>);
+ VisualScriptLanguage::singleton->add_register_func("functions/deconstruct/" + Variant::get_type_name(Variant::Type::RECT2), create_node_deconst_typed<Variant::Type::RECT2>);
+ VisualScriptLanguage::singleton->add_register_func("functions/deconstruct/" + Variant::get_type_name(Variant::Type::TRANSFORM2D), create_node_deconst_typed<Variant::Type::TRANSFORM2D>);
+ VisualScriptLanguage::singleton->add_register_func("functions/deconstruct/" + Variant::get_type_name(Variant::Type::PLANE), create_node_deconst_typed<Variant::Type::PLANE>);
+ VisualScriptLanguage::singleton->add_register_func("functions/deconstruct/" + Variant::get_type_name(Variant::Type::QUAT), create_node_deconst_typed<Variant::Type::QUAT>);
+ VisualScriptLanguage::singleton->add_register_func("functions/deconstruct/" + Variant::get_type_name(Variant::Type::AABB), create_node_deconst_typed<Variant::Type::AABB>);
+ VisualScriptLanguage::singleton->add_register_func("functions/deconstruct/" + Variant::get_type_name(Variant::Type::BASIS), create_node_deconst_typed<Variant::Type::BASIS>);
+ VisualScriptLanguage::singleton->add_register_func("functions/deconstruct/" + Variant::get_type_name(Variant::Type::TRANSFORM), create_node_deconst_typed<Variant::Type::TRANSFORM>);
VisualScriptLanguage::singleton->add_register_func("functions/compose_array", create_node_generic<VisualScriptComposeArray>);
for (int i = 1; i < Variant::VARIANT_MAX; i++) {
diff --git a/modules/visual_script/visual_script_property_selector.cpp b/modules/visual_script/visual_script_property_selector.cpp
index 0366801a11..42d4c5e209 100644
--- a/modules/visual_script/visual_script_property_selector.cpp
+++ b/modules/visual_script/visual_script_property_selector.cpp
@@ -271,6 +271,7 @@ void VisualScriptPropertySelector::_update_search() {
get_visual_node_names("flow_control/type_cast", Set<String>(), found, root, search_box);
get_visual_node_names("functions/built_in/print", Set<String>(), found, root, search_box);
get_visual_node_names("functions/by_type/" + Variant::get_type_name(type), Set<String>(), found, root, search_box);
+ get_visual_node_names("functions/deconstruct/" + Variant::get_type_name(type), Set<String>(), found, root, search_box);
get_visual_node_names("operators/compare/", Set<String>(), found, root, search_box);
if (type == Variant::INT) {
get_visual_node_names("operators/bitwise/", Set<String>(), found, root, search_box);
@@ -324,7 +325,7 @@ void VisualScriptPropertySelector::create_visualscript_item(const String &name,
}
}
-void VisualScriptPropertySelector::get_visual_node_names(const String &root_filter, const Set<String> &filter, bool &found, TreeItem *const root, LineEdit *const search_box) {
+void VisualScriptPropertySelector::get_visual_node_names(const String &root_filter, const Set<String> &p_modifiers, bool &found, TreeItem *const root, LineEdit *const search_box) {
Map<String, TreeItem *> path_cache;
List<String> fnodes;
@@ -335,27 +336,34 @@ void VisualScriptPropertySelector::get_visual_node_names(const String &root_filt
continue;
}
Vector<String> path = E->get().split("/");
- bool is_filter = false;
- for (Set<String>::Element *F = filter.front(); F; F = F->next()) {
- if (path.size() >= 2 && path[1].findn(F->get()) != -1) {
- is_filter = true;
+
+ // check if the name has the filter
+ bool in_filter = false;
+ Vector<String> tx_filters = search_box->get_text().split(" ");
+ for (int i = 0; i < tx_filters.size(); i++) {
+ if (tx_filters[i] == "") {
+ in_filter = true;
+ } else {
+ in_filter = false;
+ }
+ if (E->get().findn(tx_filters[i]) != -1) {
+ in_filter = true;
break;
}
}
- if (is_filter) {
+ if (!in_filter) {
continue;
}
- Vector<String> tx_filters = search_box->get_text().split(" ");
- for (int i = 0; i < tx_filters.size(); i++) {
- if (tx_filters[i] != String() && E->get().findn(tx_filters[i]) == -1) {
- is_filter = true;
- break;
- }
+ bool in_modifier = false | p_modifiers.empty();
+ for (Set<String>::Element *F = p_modifiers.front(); F && in_modifier; F = F->next()) {
+ if (E->get().findn(F->get()) != -1)
+ in_modifier = true;
}
- if (is_filter) {
+ if (!in_modifier) {
continue;
}
+
TreeItem *item = search_options->create_item(root);
Ref<VisualScriptNode> vnode = VisualScriptLanguage::singleton->create_node_from_name(E->get());
Ref<VisualScriptOperator> vnode_operator = vnode;
@@ -376,6 +384,10 @@ void VisualScriptPropertySelector::get_visual_node_names(const String &root_filt
if (vnode_constructor.is_valid()) {
type_name = "Construct ";
}
+ Ref<VisualScriptDeconstruct> vnode_deconstruct = vnode;
+ if (vnode_deconstruct.is_valid()) {
+ type_name = "Deconstruct ";
+ }
Vector<String> desc = path[path.size() - 1].replace("(", " ").replace(")", " ").replace(",", " ").split(" ");
for (int i = 0; i < desc.size(); i++) {
desc.write[i] = desc[i].capitalize();