|
@@ -30,6 +30,7 @@
|
|
|
#include "editor/editor_settings.h"
|
|
|
#include "gd_compiler.h"
|
|
|
#include "gd_script.h"
|
|
|
+#include "global_constants.h"
|
|
|
#include "os/file_access.h"
|
|
|
#include "project_settings.h"
|
|
|
#ifdef TOOLS_ENABLED
|
|
@@ -355,6 +356,7 @@ String GDScriptLanguage::make_function(const String &p_class, const String &p_na
|
|
|
|
|
|
struct GDCompletionIdentifier {
|
|
|
|
|
|
+ String enumeration;
|
|
|
StringName obj_type;
|
|
|
Ref<GDScript> script;
|
|
|
Variant::Type type;
|
|
@@ -608,7 +610,7 @@ static bool _guess_expression_type(GDCompletionContext &context, const GDParser:
|
|
|
|
|
|
#ifdef TOOLS_ENABLED
|
|
|
MethodBind *mb = ClassDB::get_method(base.obj_type, id);
|
|
|
- PropertyInfo pi = mb->get_argument_info(-1);
|
|
|
+ PropertyInfo pi = mb->get_return_info();
|
|
|
|
|
|
//try calling the function if constant and all args are constant, should not crash..
|
|
|
Object *baseptr = base.value;
|
|
@@ -809,6 +811,32 @@ static bool _guess_expression_type(GDCompletionContext &context, const GDParser:
|
|
|
|
|
|
if (p1.value.get_type() == Variant::OBJECT) {
|
|
|
//??
|
|
|
+ if (p1.obj_type != StringName() && p2.type == Variant::STRING) {
|
|
|
+ StringName index = p2.value;
|
|
|
+ bool valid;
|
|
|
+ Variant::Type t = ClassDB::get_property_type(p1.obj_type, index, &valid);
|
|
|
+ if (t != Variant::NIL && valid) {
|
|
|
+ r_type.type = t;
|
|
|
+ if (t == Variant::INT) {
|
|
|
+//check for enum!
|
|
|
+#if defined(DEBUG_METHODS_ENABLED) && defined(TOOLS_ENABLED)
|
|
|
+
|
|
|
+ StringName getter = ClassDB::get_property_getter(p1.obj_type, index);
|
|
|
+ if (getter != StringName()) {
|
|
|
+ MethodBind *mb = ClassDB::get_method(p1.obj_type, getter);
|
|
|
+ if (mb) {
|
|
|
+ PropertyInfo rt = mb->get_return_info();
|
|
|
+ if (rt.usage & PROPERTY_USAGE_CLASS_IS_ENUM) {
|
|
|
+ r_type.enumeration = rt.class_name;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+#endif
|
|
|
+ }
|
|
|
+
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+ }
|
|
|
} else if (p1.value.get_type() != Variant::NIL) {
|
|
|
|
|
|
bool valid;
|
|
@@ -908,6 +936,22 @@ static bool _guess_identifier_type_in_block(GDCompletionContext &context, int p_
|
|
|
Variant::Type t = ClassDB::get_property_type(gdi.obj_type, p_identifier, &valid);
|
|
|
if (t != Variant::NIL && valid) {
|
|
|
r_type.type = t;
|
|
|
+ if (t == Variant::INT) {
|
|
|
+//check for enum!
|
|
|
+#if defined(DEBUG_METHODS_ENABLED) && defined(TOOLS_ENABLED)
|
|
|
+
|
|
|
+ StringName getter = ClassDB::get_property_getter(gdi.obj_type, p_identifier);
|
|
|
+ if (getter != StringName()) {
|
|
|
+ MethodBind *mb = ClassDB::get_method(gdi.obj_type, getter);
|
|
|
+ if (mb) {
|
|
|
+ PropertyInfo rt = mb->get_return_info();
|
|
|
+ if (rt.usage & PROPERTY_USAGE_CLASS_IS_ENUM) {
|
|
|
+ r_type.enumeration = rt.class_name;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+#endif
|
|
|
+ }
|
|
|
return true;
|
|
|
}
|
|
|
}
|
|
@@ -1436,7 +1480,7 @@ void get_directory_contents(EditorFileSystemDirectory *p_dir, Set<String> &r_lis
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-static void _find_type_arguments(GDCompletionContext &context, const GDParser::Node *p_node, int p_line, const StringName &p_method, const GDCompletionIdentifier &id, int p_argidx, Set<String> &result, String &arghint) {
|
|
|
+static void _find_type_arguments(GDCompletionContext &context, const GDParser::Node *p_node, int p_line, const StringName &p_method, const GDCompletionIdentifier &id, int p_argidx, Set<String> &result, bool &r_forced, String &arghint) {
|
|
|
|
|
|
//print_line("find type arguments?");
|
|
|
if (id.type == Variant::OBJECT && id.obj_type != StringName()) {
|
|
@@ -1642,8 +1686,43 @@ static void _find_type_arguments(GDCompletionContext &context, const GDParser::N
|
|
|
}
|
|
|
|
|
|
} else {
|
|
|
- //regular method
|
|
|
+//regular method
|
|
|
+
|
|
|
+#if defined(DEBUG_METHODS_ENABLED) && defined(TOOLS_ENABLED)
|
|
|
+ if (p_argidx < m->get_argument_count()) {
|
|
|
+ PropertyInfo pi = m->get_argument_info(p_argidx);
|
|
|
+
|
|
|
+ if (pi.usage & PROPERTY_USAGE_CLASS_IS_ENUM) {
|
|
|
+ String enumeration = pi.class_name;
|
|
|
+ if (enumeration.find(".") != -1) {
|
|
|
+ //class constant
|
|
|
+ List<StringName> constants;
|
|
|
+ String cls = enumeration.get_slice(".", 0);
|
|
|
+ String enm = enumeration.get_slice(".", 1);
|
|
|
+
|
|
|
+ ClassDB::get_enum_constants(cls, enm, &constants);
|
|
|
+ //constants.sort_custom<StringName::AlphCompare>();
|
|
|
+ for (List<StringName>::Element *E = constants.front(); E; E = E->next()) {
|
|
|
+ String add = cls + "." + E->get();
|
|
|
+ result.insert(add);
|
|
|
+ r_forced = true;
|
|
|
+ }
|
|
|
+ } else {
|
|
|
|
|
|
+ //global constant
|
|
|
+ StringName current_enum = enumeration;
|
|
|
+
|
|
|
+ for (int i = 0; i < GlobalConstants::get_global_constant_count(); i++) {
|
|
|
+ if (GlobalConstants::get_global_constant_enum(i) == current_enum) {
|
|
|
+ result.insert(GlobalConstants::get_global_constant_name(i));
|
|
|
+ r_forced = true;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ //global
|
|
|
+ }
|
|
|
+ }
|
|
|
+ }
|
|
|
+#endif
|
|
|
if (p_method.operator String() == "connect" || (p_method.operator String() == "emit_signal" && p_argidx == 0)) {
|
|
|
|
|
|
if (p_argidx == 0) {
|
|
@@ -1664,6 +1743,7 @@ static void _find_type_arguments(GDCompletionContext &context, const GDParser::N
|
|
|
|
|
|
for (List<MethodInfo>::Element *E = sigs.front(); E; E = E->next()) {
|
|
|
result.insert("\"" + E->get().name + "\"");
|
|
|
+ r_forced = true;
|
|
|
}
|
|
|
|
|
|
} else if (p_argidx == 2) {
|
|
@@ -1671,6 +1751,7 @@ static void _find_type_arguments(GDCompletionContext &context, const GDParser::N
|
|
|
if (context._class) {
|
|
|
for (int i = 0; i < context._class->functions.size(); i++) {
|
|
|
result.insert("\"" + context._class->functions[i]->name + "\"");
|
|
|
+ r_forced = true;
|
|
|
}
|
|
|
}
|
|
|
}
|
|
@@ -1696,6 +1777,7 @@ static void _find_type_arguments(GDCompletionContext &context, const GDParser::N
|
|
|
//print_line("found "+s);
|
|
|
String name = s.get_slice("/", 1);
|
|
|
result.insert("\"/root/" + name + "\"");
|
|
|
+ r_forced = true;
|
|
|
}
|
|
|
}
|
|
|
|
|
@@ -1707,11 +1789,12 @@ static void _find_type_arguments(GDCompletionContext &context, const GDParser::N
|
|
|
for (List<String>::Element *E = options.front(); E; E = E->next()) {
|
|
|
|
|
|
result.insert(E->get());
|
|
|
+ r_forced = true;
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
|
|
|
- arghint = _get_visual_datatype(m->get_argument_info(-1), false) + " " + p_method.operator String() + String("(");
|
|
|
+ arghint = _get_visual_datatype(m->get_return_info(), false) + " " + p_method.operator String() + String("(");
|
|
|
|
|
|
for (int i = 0; i < m->get_argument_count(); i++) {
|
|
|
if (i > 0)
|
|
@@ -1750,7 +1833,7 @@ static void _find_type_arguments(GDCompletionContext &context, const GDParser::N
|
|
|
}
|
|
|
}
|
|
|
|
|
|
-static void _find_call_arguments(GDCompletionContext &context, const GDParser::Node *p_node, int p_line, int p_argidx, Set<String> &result, String &arghint) {
|
|
|
+static void _find_call_arguments(GDCompletionContext &context, const GDParser::Node *p_node, int p_line, int p_argidx, Set<String> &result, bool &r_forced, String &arghint) {
|
|
|
|
|
|
if (!p_node || p_node->type != GDParser::Node::TYPE_OPERATOR) {
|
|
|
|
|
@@ -1905,7 +1988,7 @@ static void _find_call_arguments(GDCompletionContext &context, const GDParser::N
|
|
|
if (!context._class->owner)
|
|
|
ci.value = context.base;
|
|
|
|
|
|
- _find_type_arguments(context, p_node, p_line, id->name, ci, p_argidx, result, arghint);
|
|
|
+ _find_type_arguments(context, p_node, p_line, id->name, ci, p_argidx, result, r_forced, arghint);
|
|
|
//guess type..
|
|
|
/*
|
|
|
List<MethodInfo> methods;
|
|
@@ -1927,7 +2010,7 @@ static void _find_call_arguments(GDCompletionContext &context, const GDParser::N
|
|
|
GDCompletionIdentifier ci;
|
|
|
if (_guess_expression_type(context, op->arguments[0], p_line, ci)) {
|
|
|
|
|
|
- _find_type_arguments(context, p_node, p_line, id->name, ci, p_argidx, result, arghint);
|
|
|
+ _find_type_arguments(context, p_node, p_line, id->name, ci, p_argidx, result, r_forced, arghint);
|
|
|
return;
|
|
|
}
|
|
|
}
|
|
@@ -2027,14 +2110,14 @@ static void _find_call_arguments(GDCompletionContext &context, const GDParser::N
|
|
|
#endif
|
|
|
}
|
|
|
|
|
|
-Error GDScriptLanguage::complete_code(const String &p_code, const String &p_base_path, Object *p_owner, List<String> *r_options, String &r_call_hint) {
|
|
|
+Error GDScriptLanguage::complete_code(const String &p_code, const String &p_base_path, Object *p_owner, List<String> *r_options, bool &r_forced, String &r_call_hint) {
|
|
|
|
|
|
GDParser p;
|
|
|
|
|
|
p.parse(p_code, p_base_path, false, "", true);
|
|
|
bool isfunction = false;
|
|
|
Set<String> options;
|
|
|
-
|
|
|
+ r_forced = false;
|
|
|
GDCompletionContext context;
|
|
|
context._class = p.get_completion_class();
|
|
|
context.block = p.get_completion_block();
|
|
@@ -2073,6 +2156,7 @@ Error GDScriptLanguage::complete_code(const String &p_code, const String &p_base
|
|
|
|
|
|
String opt = E->get().strip_edges();
|
|
|
if (opt.begins_with("\"") && opt.ends_with("\"")) {
|
|
|
+ r_forced = true;
|
|
|
String idopt = opt.substr(1, opt.length() - 2);
|
|
|
if (idopt.replace("/", "_").is_valid_identifier()) {
|
|
|
options.insert(idopt);
|
|
@@ -2297,7 +2381,7 @@ Error GDScriptLanguage::complete_code(const String &p_code, const String &p_base
|
|
|
} break;
|
|
|
case GDParser::COMPLETION_CALL_ARGUMENTS: {
|
|
|
|
|
|
- _find_call_arguments(context, p.get_completion_node(), p.get_completion_line(), p.get_completion_argument_index(), options, r_call_hint);
|
|
|
+ _find_call_arguments(context, p.get_completion_node(), p.get_completion_line(), p.get_completion_argument_index(), options, r_forced, r_call_hint);
|
|
|
} break;
|
|
|
case GDParser::COMPLETION_VIRTUAL_FUNC: {
|
|
|
|
|
@@ -2344,6 +2428,7 @@ Error GDScriptLanguage::complete_code(const String &p_code, const String &p_base
|
|
|
ClassDB::get_signal_list(t.obj_type, &sigs);
|
|
|
for (List<MethodInfo>::Element *E = sigs.front(); E; E = E->next()) {
|
|
|
options.insert("\"" + E->get().name + "\"");
|
|
|
+ r_forced = true;
|
|
|
}
|
|
|
}
|
|
|
|
|
@@ -2353,6 +2438,42 @@ Error GDScriptLanguage::complete_code(const String &p_code, const String &p_base
|
|
|
if (EditorSettings::get_singleton()->get("text_editor/completion/complete_file_paths"))
|
|
|
get_directory_contents(EditorFileSystem::get_singleton()->get_filesystem(), options);
|
|
|
} break;
|
|
|
+ case GDParser::COMPLETION_ASSIGN: {
|
|
|
+#if defined(DEBUG_METHODS_ENABLED) && defined(TOOLS_ENABLED)
|
|
|
+
|
|
|
+ GDCompletionIdentifier ci;
|
|
|
+ if (_guess_expression_type(context, p.get_completion_node(), p.get_completion_line(), ci)) {
|
|
|
+
|
|
|
+ String enumeration = ci.enumeration;
|
|
|
+ if (enumeration.find(".") != -1) {
|
|
|
+ //class constant
|
|
|
+ List<StringName> constants;
|
|
|
+ String cls = enumeration.get_slice(".", 0);
|
|
|
+ String enm = enumeration.get_slice(".", 1);
|
|
|
+
|
|
|
+ ClassDB::get_enum_constants(cls, enm, &constants);
|
|
|
+ //constants.sort_custom<StringName::AlphCompare>();
|
|
|
+ for (List<StringName>::Element *E = constants.front(); E; E = E->next()) {
|
|
|
+ String add = cls + "." + E->get();
|
|
|
+ r_options->push_back(add);
|
|
|
+ r_forced = true;
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+
|
|
|
+ //global constant
|
|
|
+ StringName current_enum = enumeration;
|
|
|
+
|
|
|
+ for (int i = 0; i < GlobalConstants::get_global_constant_count(); i++) {
|
|
|
+ if (GlobalConstants::get_global_constant_enum(i) == current_enum) {
|
|
|
+ r_options->push_back(GlobalConstants::get_global_constant_name(i));
|
|
|
+ r_forced = true;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ //global
|
|
|
+ }
|
|
|
+ }
|
|
|
+#endif
|
|
|
+ } break;
|
|
|
}
|
|
|
|
|
|
for (Set<String>::Element *E = options.front(); E; E = E->next()) {
|