summaryrefslogtreecommitdiff
path: root/modules/gdscript/gd_editor.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'modules/gdscript/gd_editor.cpp')
-rw-r--r--modules/gdscript/gd_editor.cpp790
1 files changed, 664 insertions, 126 deletions
diff --git a/modules/gdscript/gd_editor.cpp b/modules/gdscript/gd_editor.cpp
index 7e5ff620c9..19472d3d46 100644
--- a/modules/gdscript/gd_editor.cpp
+++ b/modules/gdscript/gd_editor.cpp
@@ -5,7 +5,7 @@
/* GODOT ENGINE */
/* http://www.godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2016 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2007-2017 Juan Linietsky, Ariel Manzur. */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -44,21 +44,26 @@ void GDScriptLanguage::get_string_delimiters(List<String> *p_delimiters) const {
}
-String GDScriptLanguage::get_template(const String& p_class_name, const String& p_base_class_name) const {
+Ref<Script> GDScriptLanguage::get_template(const String& p_class_name, const String& p_base_class_name) const {
String _template = String()+
- "\nextends %BASE%\n\n"+
- "# member variables here, example:\n"+
- "# var a=2\n"+
- "# var b=\"textvar\"\n\n"+
+ "extends %BASE%\n\n"+
+ "# class member variables go here, for example:\n"+
+ "# var a = 2\n"+
+ "# var b = \"textvar\"\n\n"+
"func _ready():\n"+
"\t# Called every time the node is added to the scene.\n"+
"\t# Initialization here\n"+
- "\tpass\n"+
- "\n"+
- "\n";
+ "\tpass\n";
+
+ _template = _template.replace("%BASE%",p_base_class_name);
+
+ Ref<GDScript> script;
+ script.instance();
+ script->set_source_code(_template);
+
+ return script;
- return _template.replace("%BASE%",p_base_class_name);
}
@@ -212,7 +217,7 @@ String GDScriptLanguage::debug_get_stack_level_source(int p_level) const {
ERR_FAIL_INDEX_V(p_level,_debug_call_stack_pos,"");
int l = _debug_call_stack_pos - p_level -1;
- return _call_stack[l].function->get_script()->get_path();
+ return _call_stack[l].function->get_source();
}
void GDScriptLanguage::debug_get_stack_level_locals(int p_level,List<String> *p_locals, List<Variant> *p_values, int p_max_subitems,int p_max_depth) {
@@ -297,7 +302,7 @@ void GDScriptLanguage::get_public_functions(List<MethodInfo> *p_functions) const
}
{
MethodInfo mi;
- mi.name="yield";
+ mi.name="yield:GDFunctionState";
mi.arguments.push_back(PropertyInfo(Variant::OBJECT,"object"));
mi.arguments.push_back(PropertyInfo(Variant::STRING,"signal"));
mi.default_arguments.push_back(Variant::NIL);
@@ -320,7 +325,7 @@ void GDScriptLanguage::get_public_constants(List<Pair<String,Variant> > *p_const
p_constants->push_back(pi);
}
-String GDScriptLanguage::make_function(const String& p_class,const String& p_name,const StringArray& p_args) const {
+String GDScriptLanguage::make_function(const String& p_class,const String& p_name,const PoolStringArray& p_args) const {
String s="func "+p_name+"(";
if (p_args.size()) {
@@ -328,7 +333,7 @@ String GDScriptLanguage::make_function(const String& p_class,const String& p_nam
for(int i=0;i<p_args.size();i++) {
if (i>0)
s+=", ";
- s+=p_args[i];
+ s+=p_args[i].get_slice(":",0);
}
s+=" ";
}
@@ -346,6 +351,7 @@ struct GDCompletionIdentifier {
Ref<GDScript> script;
Variant::Type type;
Variant value; //im case there is a value, also return it
+
};
@@ -358,11 +364,13 @@ static GDCompletionIdentifier _get_type_from_variant(const Variant& p_variant) {
if (p_variant.get_type()==Variant::OBJECT) {
Object *obj = p_variant;
if (obj) {
- //if (obj->cast_to<GDNativeClass>()) {
- // t.obj_type=obj->cast_to<GDNativeClass>()->get_name();
- // t.value=Variant();
- //} else {
- t.obj_type=obj->get_type();
+ /*
+ if (obj->cast_to<GDNativeClass>()) {
+ t.obj_type=obj->cast_to<GDNativeClass>()->get_name();
+ t.value=Variant();
+ } else {
+ */
+ t.obj_type=obj->get_class();
//}
}
}
@@ -449,62 +457,21 @@ static Ref<Reference> _get_parent_class(GDCompletionContext& context) {
}
String base=context._class->extends_class[0];
- const GDParser::ClassNode *p = context._class->owner;
- Ref<GDScript> base_class;
-#if 0
- while(p) {
- if (p->subclasses.has(base)) {
+ if (context._class->extends_class.size()>1) {
- base_class=p->subclasses[base];
- break;
- }
- p=p->_owner;
- }
-#endif
- if (base_class.is_valid()) {
-#if 0
- for(int i=1;i<context._class->extends_class.size();i++) {
-
- String subclass=context._class->extends_class[i];
-
- if (base_class->subclasses.has(subclass)) {
-
- base_class=base_class->subclasses[subclass];
- } else {
-
- //print_line("Could not find subclass: "+subclass);
- return _get_type_from_class(context); //fail please
- }
- }
-
- script=base_class;
-#endif
-
- } else {
-
- if (context._class->extends_class.size()>1) {
-
- return REF();
-
-
- }
- //if not found, try engine classes
- if (!GDScriptLanguage::get_singleton()->get_global_map().has(base)) {
-
- return REF();
- }
-
- int base_idx = GDScriptLanguage::get_singleton()->get_global_map()[base];
- native = GDScriptLanguage::get_singleton()->get_global_array()[base_idx];
- if (!native.is_valid()) {
+ return REF();
- print_line("Global not a class: '"+base+"'");
+ }
+ //if not found, try engine classes
+ if (!GDScriptLanguage::get_singleton()->get_global_map().has(base)) {
- }
- return native;
+ return REF();
}
+ int base_idx = GDScriptLanguage::get_singleton()->get_global_map()[base];
+ native = GDScriptLanguage::get_singleton()->get_global_array()[base_idx];
+ return native;
}
@@ -649,10 +616,10 @@ static bool _guess_expression_type(GDCompletionContext& context,const GDParser::
}
}
- if (ObjectTypeDB::has_method(base.obj_type,id)) {
+ if (ClassDB::has_method(base.obj_type,id)) {
#ifdef TOOLS_ENABLED
- MethodBind *mb = ObjectTypeDB::get_method(base.obj_type,id);
+ MethodBind *mb = ClassDB::get_method(base.obj_type,id);
PropertyInfo pi = mb->get_argument_info(-1);
//try calling the function if constant and all args are constant, should not crash..
@@ -678,14 +645,14 @@ static bool _guess_expression_type(GDCompletionContext& context,const GDParser::
}
}
- if (all_valid && String(id)=="get_node" && ObjectTypeDB::is_type(base.obj_type,"Node") && args.size()) {
+ if (all_valid && String(id)=="get_node" && ClassDB::is_parent_class(base.obj_type,"Node") && args.size()) {
String arg1=args[0];
if (arg1.begins_with("/root/")) {
String which = arg1.get_slice("/",2);
if (which!="") {
List<PropertyInfo> props;
- Globals::get_singleton()->get_property_list(&props);
+ GlobalConfig::get_singleton()->get_property_list(&props);
//print_line("find singleton");
for(List<PropertyInfo>::Element *E=props.front();E;E=E->next()) {
@@ -697,7 +664,7 @@ static bool _guess_expression_type(GDCompletionContext& context,const GDParser::
String name = s.get_slice("/",1);
//print_line("name: "+name+", which: "+which);
if (name==which) {
- String script = Globals::get_singleton()->get(s);
+ String script = GlobalConfig::get_singleton()->get(s);
if (!script.begins_with("res://")) {
script="res://"+script;
@@ -706,7 +673,7 @@ static bool _guess_expression_type(GDCompletionContext& context,const GDParser::
if (!script.ends_with(".gd")) {
//not a script, try find the script anyway,
//may have some success
- script=script.basename()+".gd";
+ script=script.get_basename()+".gd";
}
if (FileAccess::exists(script)) {
@@ -971,9 +938,19 @@ static bool _guess_expression_type(GDCompletionContext& context,const GDParser::
return false;
}
+
static bool _guess_identifier_type_in_block(GDCompletionContext& context,int p_line,const StringName& p_identifier,GDCompletionIdentifier &r_type) {
+ GDCompletionIdentifier gdi = _get_native_class(context);
+ if (gdi.obj_type!=StringName()) {
+ bool valid;
+ Variant::Type t = ClassDB::get_property_type(gdi.obj_type,p_identifier,&valid);
+ if (t!=Variant::NIL && valid) {
+ r_type.type=t;
+ return true;
+ }
+ }
const GDParser::Node *last_assign=NULL;
int last_assign_line=-1;
@@ -1024,7 +1001,7 @@ static bool _guess_identifier_type_in_block(GDCompletionContext& context,int p_l
}
-static bool _guess_identifier_from_assignment_in_function(GDCompletionContext& context,const StringName& p_identifier, const StringName& p_function,GDCompletionIdentifier &r_type) {
+static bool _guess_identifier_from_assignment_in_function(GDCompletionContext& context, int p_src_line, const StringName& p_identifier, const StringName& p_function,GDCompletionIdentifier &r_type) {
const GDParser::FunctionNode* func=NULL;
for(int i=0;i<context._class->functions.size();i++) {
@@ -1039,7 +1016,9 @@ static bool _guess_identifier_from_assignment_in_function(GDCompletionContext& c
for(int i=0;i<func->body->statements.size();i++) {
-
+ if (func->body->statements[i]->line == p_src_line) {
+ break;
+ }
if (func->body->statements[i]->type==GDParser::BlockNode::TYPE_OPERATOR) {
const GDParser::OperatorNode *op = static_cast<const GDParser::OperatorNode *>(func->body->statements[i]);
@@ -1100,7 +1079,7 @@ static bool _guess_identifier_type(GDCompletionContext& context,int p_line,const
//this kinda sucks but meh
List<MethodInfo> vmethods;
- ObjectTypeDB::get_virtual_methods(id.obj_type,&vmethods);
+ ClassDB::get_virtual_methods(id.obj_type,&vmethods);
for (List<MethodInfo>::Element *E=vmethods.front();E;E=E->next()) {
@@ -1160,11 +1139,11 @@ static bool _guess_identifier_type(GDCompletionContext& context,int p_line,const
}
//try to guess from assignment in construtor or _ready
- if (_guess_identifier_from_assignment_in_function(context,p_identifier,"_ready",r_type))
+ if (_guess_identifier_from_assignment_in_function(context,p_line+1,p_identifier,"_ready",r_type))
return true;
- if (_guess_identifier_from_assignment_in_function(context,p_identifier,"_enter_tree",r_type))
+ if (_guess_identifier_from_assignment_in_function(context,p_line+1,p_identifier,"_enter_tree",r_type))
return true;
- if (_guess_identifier_from_assignment_in_function(context,p_identifier,"_init",r_type))
+ if (_guess_identifier_from_assignment_in_function(context,p_line+1,p_identifier,"_init",r_type))
return true;
return false;
@@ -1174,7 +1153,7 @@ static bool _guess_identifier_type(GDCompletionContext& context,int p_line,const
//autoloads as singletons
List<PropertyInfo> props;
- Globals::get_singleton()->get_property_list(&props);
+ GlobalConfig::get_singleton()->get_property_list(&props);
for(List<PropertyInfo>::Element *E=props.front();E;E=E->next()) {
@@ -1184,14 +1163,14 @@ static bool _guess_identifier_type(GDCompletionContext& context,int p_line,const
String name = s.get_slice("/",1);
if (name==String(p_identifier)) {
- String path = Globals::get_singleton()->get(s);
+ String path = GlobalConfig::get_singleton()->get(s);
if (path.begins_with("*")) {
String script =path.substr(1,path.length());
if (!script.ends_with(".gd")) {
//not a script, try find the script anyway,
//may have some success
- script=script.basename()+".gd";
+ script=script.get_basename()+".gd";
}
if (FileAccess::exists(script)) {
@@ -1330,26 +1309,43 @@ static void _find_identifiers_in_class(GDCompletionContext& context,bool p_stati
base=script->get_native();
} else if (nc.is_valid()) {
+ StringName type = nc->get_name();
+
if (!p_only_functions) {
- StringName type = nc->get_name();
+
List<String> constants;
- ObjectTypeDB::get_integer_constant_list(type,&constants);
+ ClassDB::get_integer_constant_list(type,&constants);
for(List<String>::Element *E=constants.front();E;E=E->next()) {
result.insert(E->get());
}
- List<MethodInfo> methods;
- ObjectTypeDB::get_method_list(type,&methods);
- for(List<MethodInfo>::Element *E=methods.front();E;E=E->next()) {
- if (E->get().name.begins_with("_"))
+ List<PropertyInfo> pinfo;
+
+ ClassDB::get_property_list(type,&pinfo);
+
+ for (List<PropertyInfo>::Element *E=pinfo.front();E;E=E->next()) {
+ if (E->get().usage&(PROPERTY_USAGE_GROUP|PROPERTY_USAGE_CATEGORY))
continue;
- if (E->get().arguments.size())
- result.insert(E->get().name+"(");
- else
- result.insert(E->get().name+"()");
+ if (E->get().name.find("/")!=-1)
+ continue;
+ result.insert(E->get().name);
}
+
+ }
+ List<MethodInfo> methods;
+ ClassDB::get_method_list(type,&methods);
+ for(List<MethodInfo>::Element *E=methods.front();E;E=E->next()) {
+ if (E->get().name.begins_with("_"))
+ continue;
+ if (E->get().arguments.size())
+ result.insert(E->get().name+"(");
+ else
+ result.insert(E->get().name+"()");
}
+
+
+
break;
} else
break;
@@ -1399,7 +1395,7 @@ static void _find_identifiers(GDCompletionContext& context,int p_line,bool p_onl
}
static const char*_type_names[Variant::VARIANT_MAX]={
- "null","bool","int","float","String","Vector2","Rect2","Vector3","Matrix32","Plane","Quat","AABB","Matrix3","Transform",
+ "null","bool","int","float","String","Vector2","Rect2","Vector3","Transform2D","Plane","Quat","AABB","Basis","Transform",
"Color","Image","NodePath","RID","Object","InputEvent","Dictionary","Array","RawArray","IntArray","FloatArray","StringArray",
"Vector2Array","Vector3Array","ColorArray"};
@@ -1409,7 +1405,7 @@ static void _find_identifiers(GDCompletionContext& context,int p_line,bool p_onl
//autoload singletons
List<PropertyInfo> props;
- Globals::get_singleton()->get_property_list(&props);
+ GlobalConfig::get_singleton()->get_property_list(&props);
for(List<PropertyInfo>::Element *E=props.front();E;E=E->next()) {
@@ -1417,7 +1413,7 @@ static void _find_identifiers(GDCompletionContext& context,int p_line,bool p_onl
if (!s.begins_with("autoload/"))
continue;
String name = s.get_slice("/",1);
- String path = Globals::get_singleton()->get(s);
+ String path = GlobalConfig::get_singleton()->get(s);
if (path.begins_with("*")) {
result.insert(name);
}
@@ -1495,14 +1491,14 @@ static void _make_function_hint(const GDParser::FunctionNode* p_func,int p_argid
}
-static void _find_type_arguments(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, String& arghint) {
//print_line("find type arguments?");
if (id.type==Variant::INPUT_EVENT && String(p_method)=="is_action" && p_argidx==0) {
List<PropertyInfo> pinfo;
- Globals::get_singleton()->get_property_list(&pinfo);
+ GlobalConfig::get_singleton()->get_property_list(&pinfo);
for(List<PropertyInfo>::Element *E=pinfo.front();E;E=E->next()) {
const PropertyInfo &pi=E->get();
@@ -1518,7 +1514,7 @@ static void _find_type_arguments(const GDParser::Node*p_node,int p_line,const St
} else if (id.type==Variant::OBJECT && id.obj_type!=StringName()) {
- MethodBind *m = ObjectTypeDB::get_method(id.obj_type,p_method);
+ MethodBind *m = ClassDB::get_method(id.obj_type,p_method);
if (!m) {
//not in static method, see script
@@ -1731,10 +1727,32 @@ static void _find_type_arguments(const GDParser::Node*p_node,int p_line,const St
if (p_argidx==0) {
List<MethodInfo> sigs;
- ObjectTypeDB::get_signal_list(id.obj_type,&sigs);
+ ClassDB::get_signal_list(id.obj_type,&sigs);
+
+ if (id.script.is_valid()) {
+ id.script->get_script_signal_list(&sigs);
+ } else if (id.value.get_type()==Variant::OBJECT) {
+ Object *obj = id.value;
+ if (obj && !obj->get_script().is_null()) {
+ Ref<Script> scr=obj->get_script();
+ if (scr.is_valid()) {
+ scr->get_script_signal_list(&sigs);
+ }
+ }
+ }
+
for (List<MethodInfo>::Element *E=sigs.front();E;E=E->next()) {
result.insert("\""+E->get().name+"\"");
}
+
+ } else if (p_argidx==2){
+
+
+ if (context._class) {
+ for(int i=0;i<context._class->functions.size();i++) {
+ result.insert("\""+context._class->functions[i]->name+"\"");
+ }
+ }
}
/*if (p_argidx==2) {
@@ -1745,17 +1763,17 @@ static void _find_type_arguments(const GDParser::Node*p_node,int p_line,const St
}*/
} else {
- if (p_argidx==0 && (String(p_method)=="get_node" || String(p_method)=="has_node") && ObjectTypeDB::is_type(id.obj_type,"Node")) {
+ if (p_argidx==0 && (String(p_method)=="get_node" || String(p_method)=="has_node") && ClassDB::is_parent_class(id.obj_type,"Node")) {
List<PropertyInfo> props;
- Globals::get_singleton()->get_property_list(&props);
+ GlobalConfig::get_singleton()->get_property_list(&props);
for(List<PropertyInfo>::Element *E=props.front();E;E=E->next()) {
String s = E->get().name;
if (!s.begins_with("autoload/"))
continue;
- // print_line("found "+s);
+ //print_line("found "+s);
String name = s.get_slice("/",1);
result.insert("\"/root/"+name+"\"");
}
@@ -1976,16 +1994,16 @@ static void _find_call_arguments(GDCompletionContext& context,const GDParser::No
if (!context._class->owner)
ci.value=context.base;
- _find_type_arguments(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,arghint);
//guess type..
/*
List<MethodInfo> methods;
- ObjectTypeDB::get_method_list(type,&methods);
+ ClassDB::get_method_list(type,&methods);
for(List<MethodInfo>::Element *E=methods.front();E;E=E->next()) {
- //if (E->get().arguments.size())
- // result.insert(E->get().name+"(");
- //else
- // result.insert(E->get().name+"()");
+ if (E->get().arguments.size())
+ result.insert(E->get().name+"(");
+ else
+ result.insert(E->get().name+"()");
}*/
}
break;
@@ -1999,7 +2017,7 @@ static void _find_call_arguments(GDCompletionContext& context,const GDParser::No
GDCompletionIdentifier ci;
if (_guess_expression_type(context,op->arguments[0],p_line,ci)) {
- _find_type_arguments(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,arghint);
return;
}
@@ -2073,13 +2091,13 @@ static void _find_call_arguments(GDCompletionContext& context,const GDParser::No
StringName type = nc->get_name();
List<String> constants;
- ObjectTypeDB::get_integer_constant_list(type,&constants);
+ ClassDB::get_integer_constant_list(type,&constants);
for(List<String>::Element *E=constants.front();E;E=E->next()) {
result.insert(E->get());
}
List<MethodInfo> methods;
- ObjectTypeDB::get_method_list(type,&methods);
+ ClassDB::get_method_list(type,&methods);
for(List<MethodInfo>::Element *E=methods.front();E;E=E->next()) {
if (E->get().arguments.size())
result.insert(E->get().name+"(");
@@ -2103,12 +2121,10 @@ static void _find_call_arguments(GDCompletionContext& context,const GDParser::No
}
Error GDScriptLanguage::complete_code(const String& p_code, const String& p_base_path, Object*p_owner, List<String>* r_options, String &r_call_hint) {
- //print_line( p_code.replace(String::chr(0xFFFF),"<cursor>"));
GDParser p;
- //Error parse(const String& p_code, const String& p_base_path="", bool p_just_validate=false,const String& p_self_path="",bool p_for_completion=false);
- Error err = p.parse(p_code,p_base_path,false,"",true);
+ p.parse(p_code,p_base_path,false,"",true);
bool isfunction=false;
Set<String> options;
@@ -2122,10 +2138,8 @@ Error GDScriptLanguage::complete_code(const String& p_code, const String& p_base
switch(p.get_completion_type()) {
case GDParser::COMPLETION_NONE: {
- print_line("No completion");
} break;
case GDParser::COMPLETION_BUILT_IN_TYPE_CONSTANT: {
- print_line("Built in type constant");
List<StringName> constants;
Variant::get_numeric_constants_for_type(p.get_completion_built_in_constant(),&constants);
for(List<StringName>::Element *E=constants.front();E;E=E->next()) {
@@ -2141,9 +2155,29 @@ Error GDScriptLanguage::complete_code(const String& p_code, const String& p_base
_find_identifiers(context,p.get_completion_line(),isfunction,options);
} break;
case GDParser::COMPLETION_PARENT_FUNCTION: {
- print_line("parent function");
} break;
+ case GDParser::COMPLETION_GET_NODE: {
+
+ if (p_owner) {
+ List<String> opts;
+ p_owner->get_argument_options("get_node",0,&opts);
+
+ for (List<String>::Element *E=opts.front();E;E=E->next()) {
+
+ String opt = E->get().strip_edges();
+ if (opt.begins_with("\"") && opt.ends_with("\"")) {
+ String idopt=opt.substr(1,opt.length()-2);
+ if (idopt.replace("/","_").is_valid_identifier()) {
+ options.insert(idopt);
+ } else {
+ options.insert(opt);
+ }
+ }
+ }
+
+ }
+ } break;
case GDParser::COMPLETION_METHOD:
isfunction=true;
case GDParser::COMPLETION_INDEX: {
@@ -2158,7 +2192,29 @@ Error GDScriptLanguage::complete_code(const String& p_code, const String& p_base
GDCompletionIdentifier t;
if (_guess_expression_type(context,static_cast<const GDParser::OperatorNode *>(node)->arguments[0],p.get_completion_line(),t)) {
- if (t.type==Variant::OBJECT && t.obj_type!=StringName()) {
+ if (t.type==Variant::OBJECT && t.obj_type=="GDNativeClass") {
+ //native enum
+ Ref<GDNativeClass> gdn = t.value;
+ if (gdn.is_valid()) {
+ StringName cn = gdn->get_name();
+ List<String> cnames;
+ ClassDB::get_integer_constant_list(cn,&cnames);
+ for (List<String>::Element *E=cnames.front();E;E=E->next()) {
+ options.insert(E->get());
+ }
+
+ List<PropertyInfo> pinfo;
+ ClassDB::get_property_list(cn,&pinfo);
+
+ for (List<PropertyInfo>::Element *E=pinfo.front();E;E=E->next()) {
+ if (E->get().usage&(PROPERTY_USAGE_GROUP|PROPERTY_USAGE_CATEGORY))
+ continue;
+ if (E->get().name.find("/")!=-1)
+ continue;
+ options.insert(E->get().name);
+ }
+ }
+ } else if (t.type==Variant::OBJECT && t.obj_type!=StringName()) {
Ref<GDScript> on_script;
@@ -2210,7 +2266,6 @@ Error GDScriptLanguage::complete_code(const String& p_code, const String& p_base
if (code!="") {
//if there is code, parse it. This way is slower but updates in real-time
GDParser p;
- //Error parse(const String& p_code, const String& p_base_path="", bool p_just_validate=false,const String& p_self_path="",bool p_for_completion=false);
Error err = p.parse(scr->get_source_code(),scr->get_path().get_base_dir(),true,"",false);
@@ -2293,10 +2348,23 @@ Error GDScriptLanguage::complete_code(const String& p_code, const String& p_base
if (!isfunction) {
- ObjectTypeDB::get_integer_constant_list(t.obj_type,r_options);
+ ClassDB::get_integer_constant_list(t.obj_type,r_options);
+
+ List<PropertyInfo> pinfo;
+ ClassDB::get_property_list(t.obj_type,&pinfo);
+
+ for (List<PropertyInfo>::Element *E=pinfo.front();E;E=E->next()) {
+ if (E->get().usage&(PROPERTY_USAGE_GROUP|PROPERTY_USAGE_CATEGORY))
+ continue;
+ if (E->get().name.find("/")!=-1)
+ continue;
+ r_options->push_back(E->get().name);
+ }
}
+
+
List<MethodInfo> mi;
- ObjectTypeDB::get_method_list(t.obj_type,&mi);
+ ClassDB::get_method_list(t.obj_type,&mi);
for (List<MethodInfo>::Element *E=mi.front();E;E=E->next()) {
if (E->get().name.begins_with("_"))
@@ -2325,8 +2393,8 @@ Error GDScriptLanguage::complete_code(const String& p_code, const String& p_base
"# Key",
"# MouseMotion",
"# MouseButton",
- "# JoystickMotion",
- "# JoystickButton",
+ "# JoypadMotion",
+ "# JoypadButton",
"# ScreenTouch",
"# ScreenDrag",
"# Action"
@@ -2402,7 +2470,7 @@ Error GDScriptLanguage::complete_code(const String& p_code, const String& p_base
if (cid.obj_type!=StringName()) {
List<MethodInfo> vm;
- ObjectTypeDB::get_virtual_methods(cid.obj_type,&vm);
+ ClassDB::get_virtual_methods(cid.obj_type,&vm);
for(List<MethodInfo>::Element *E=vm.front();E;E=E->next()) {
MethodInfo &mi=E->get();
@@ -2427,7 +2495,24 @@ Error GDScriptLanguage::complete_code(const String& p_code, const String& p_base
}
}
} break;
+ case GDParser::COMPLETION_YIELD: {
+ const GDParser::Node *node = p.get_completion_node();
+
+ GDCompletionIdentifier t;
+ if (!_guess_expression_type(context,node,p.get_completion_line(),t))
+ break;
+
+ if (t.type==Variant::OBJECT && t.obj_type!=StringName()) {
+
+ List<MethodInfo> sigs;
+ ClassDB::get_signal_list(t.obj_type,&sigs);
+ for (List<MethodInfo>::Element *E=sigs.front();E;E=E->next()) {
+ options.insert("\""+E->get().name+"\"");
+ }
+ }
+
+ } break;
}
@@ -2512,3 +2597,456 @@ void GDScriptLanguage::auto_indent_code(String& p_code,int p_from_line,int p_to_
}
}
+
+#ifdef TOOLS_ENABLED
+
+Error GDScriptLanguage::lookup_code(const String& p_code, const String& p_symbol,const String& p_base_path, Object*p_owner,LookupResult& r_result) {
+
+
+ //before parsing, try the usual stuff
+ if (ClassDB::class_exists(p_symbol)) {
+ r_result.type=ScriptLanguage::LookupResult::RESULT_CLASS;
+ r_result.class_name=p_symbol;
+ return OK;
+ }
+
+ for(int i=0;i<Variant::VARIANT_MAX;i++) {
+ Variant::Type t = Variant::Type(i);
+ if (Variant::get_type_name(t)==p_symbol) {
+ r_result.type=ScriptLanguage::LookupResult::RESULT_CLASS;
+ r_result.class_name=Variant::get_type_name(t);
+ return OK;
+ }
+ }
+
+ for(int i=0;i<GDFunctions::FUNC_MAX;i++) {
+ if (GDFunctions::get_func_name(GDFunctions::Function(i))==p_symbol) {
+ r_result.type=ScriptLanguage::LookupResult::RESULT_CLASS_METHOD;
+ r_result.class_name="@GDScript";
+ r_result.class_member=p_symbol;
+ return OK;
+ }
+ }
+
+ GDParser p;
+ p.parse(p_code,p_base_path,false,"",true);
+
+ if (p.get_completion_type()==GDParser::COMPLETION_NONE)
+ return ERR_CANT_RESOLVE;
+
+ GDCompletionContext context;
+
+ context._class=p.get_completion_class();
+ context.block=p.get_completion_block();
+ context.function=p.get_completion_function();
+ context.base=p_owner;
+ context.base_path=p_base_path;
+ bool isfunction=false;
+
+ switch(p.get_completion_type()) {
+
+ case GDParser::COMPLETION_NONE: {
+ } break;
+ case GDParser::COMPLETION_BUILT_IN_TYPE_CONSTANT: {
+
+ r_result.type=ScriptLanguage::LookupResult::RESULT_CLASS_CONSTANT;
+ r_result.class_name=Variant::get_type_name(p.get_completion_built_in_constant());
+ r_result.class_member=p_symbol;
+ return OK;
+
+ } break;
+ case GDParser::COMPLETION_FUNCTION: {
+
+
+ if (context._class && context._class->functions.size()) {
+ for(int i=0;i<context._class->functions.size();i++) {
+ if (context._class->functions[i]->name==p_symbol) {
+ r_result.type=ScriptLanguage::LookupResult::RESULT_SCRIPT_LOCATION;
+ r_result.location=context._class->functions[i]->line;
+ return OK;
+ }
+ }
+ }
+
+ Ref<GDScript> parent = _get_parent_class(context);
+ while(parent.is_valid()) {
+ int line = parent->get_member_line(p_symbol);
+ if (line>=0) {
+ r_result.type=ScriptLanguage::LookupResult::RESULT_SCRIPT_LOCATION;
+ r_result.location=line;
+ r_result.script=parent;
+ return OK;
+
+ }
+
+ parent=parent->get_base();
+ }
+
+ GDCompletionIdentifier identifier = _get_native_class(context);
+ print_line("identifier: "+String(identifier.obj_type));
+
+ if (ClassDB::has_method(identifier.obj_type,p_symbol)) {
+
+ r_result.type=ScriptLanguage::LookupResult::RESULT_CLASS_METHOD;
+ r_result.class_name=identifier.obj_type;
+ r_result.class_member=p_symbol;
+ return OK;
+ }
+
+
+ } break;
+ case GDParser::COMPLETION_IDENTIFIER: {
+
+ //check if a function
+ if (p.get_completion_identifier_is_function()) {
+ if (context._class && context._class->functions.size()) {
+ for(int i=0;i<context._class->functions.size();i++) {
+ if (context._class->functions[i]->name==p_symbol) {
+ r_result.type=ScriptLanguage::LookupResult::RESULT_SCRIPT_LOCATION;
+ r_result.location=context._class->functions[i]->line;
+ return OK;
+ }
+ }
+ }
+
+ Ref<GDScript> parent = _get_parent_class(context);
+ while(parent.is_valid()) {
+ int line = parent->get_member_line(p_symbol);
+ if (line>=0) {
+ r_result.type=ScriptLanguage::LookupResult::RESULT_SCRIPT_LOCATION;
+ r_result.location=line;
+ r_result.script=parent;
+ return OK;
+
+ }
+
+ parent=parent->get_base();
+ }
+
+ GDCompletionIdentifier identifier = _get_native_class(context);
+
+
+ if (ClassDB::has_method(identifier.obj_type,p_symbol)) {
+
+ r_result.type=ScriptLanguage::LookupResult::RESULT_CLASS_METHOD;
+ r_result.class_name=identifier.obj_type;
+ r_result.class_member=p_symbol;
+ return OK;
+ }
+ } else {
+
+
+ GDCompletionIdentifier gdi = _get_native_class(context);
+ if (gdi.obj_type!=StringName()) {
+ bool valid;
+ Variant::Type t = ClassDB::get_property_type(gdi.obj_type,p_symbol,&valid);
+ if (t!=Variant::NIL && valid) {
+ r_result.type=ScriptLanguage::LookupResult::RESULT_CLASS_PROPERTY;
+ r_result.class_name=gdi.obj_type;
+ r_result.class_member=p_symbol;
+ return OK;
+
+ }
+ }
+
+ const GDParser::BlockNode *block=context.block;
+ //search in blocks going up (local var?)
+ while(block) {
+
+
+
+ for (int i=0;i<block->statements.size();i++) {
+
+ if (block->statements[i]->line>p.get_completion_line())
+ continue;
+
+
+ if (block->statements[i]->type==GDParser::BlockNode::TYPE_LOCAL_VAR) {
+
+ const GDParser::LocalVarNode *lv=static_cast<const GDParser::LocalVarNode *>(block->statements[i]);
+
+ if (lv->assign && lv->name==p_symbol) {
+
+ r_result.type=ScriptLanguage::LookupResult::RESULT_SCRIPT_LOCATION;
+ r_result.location=block->statements[i]->line;
+ return OK;
+ }
+ }
+ }
+ block=block->parent_block;
+ }
+
+ //guess from function arguments
+ if (context.function && context.function->name!=StringName()) {
+
+ for(int i=0;i<context.function->arguments.size();i++) {
+
+ if (context.function->arguments[i]==p_symbol) {
+ r_result.type=ScriptLanguage::LookupResult::RESULT_SCRIPT_LOCATION;
+ r_result.location=context.function->line;
+ return OK;
+ }
+
+ }
+ }
+
+ //guess in class constants
+
+ for(int i=0;i<context._class->constant_expressions.size();i++) {
+
+ if (context._class->constant_expressions[i].identifier==p_symbol) {
+ r_result.type=ScriptLanguage::LookupResult::RESULT_SCRIPT_LOCATION;
+ r_result.location=context._class->constant_expressions[i].expression->line;
+ return OK;
+ }
+ }
+
+ //guess in class variables
+ if (!(context.function && context.function->_static)) {
+
+ for(int i=0;i<context._class->variables.size();i++) {
+
+ if (context._class->variables[i].identifier==p_symbol) {
+
+ r_result.type=ScriptLanguage::LookupResult::RESULT_SCRIPT_LOCATION;
+ r_result.location=context._class->variables[i].line;
+ return OK;
+ }
+ }
+ }
+
+ //guess in autoloads as singletons
+ List<PropertyInfo> props;
+ GlobalConfig::get_singleton()->get_property_list(&props);
+
+ for(List<PropertyInfo>::Element *E=props.front();E;E=E->next()) {
+
+ String s = E->get().name;
+ if (!s.begins_with("autoload/"))
+ continue;
+ String name = s.get_slice("/",1);
+ if (name==String(p_symbol)) {
+
+ String path = GlobalConfig::get_singleton()->get(s);
+ if (path.begins_with("*")) {
+ String script =path.substr(1,path.length());
+
+ if (!script.ends_with(".gd")) {
+ //not a script, try find the script anyway,
+ //may have some success
+ script=script.get_basename()+".gd";
+ }
+
+ if (FileAccess::exists(script)) {
+
+ r_result.type=ScriptLanguage::LookupResult::RESULT_SCRIPT_LOCATION;
+ r_result.location=0;
+ r_result.script=ResourceLoader::load(script);
+ return OK;
+ }
+ }
+ }
+ }
+
+ //global
+ for(Map<StringName,int>::Element *E=GDScriptLanguage::get_singleton()->get_global_map().front();E;E=E->next()) {
+ if (E->key()==p_symbol) {
+
+ Variant value = GDScriptLanguage::get_singleton()->get_global_array()[E->get()];
+ if (value.get_type()==Variant::OBJECT) {
+ Object *obj = value;
+ if (obj) {
+
+ if (obj->cast_to<GDNativeClass>()) {
+ r_result.type=ScriptLanguage::LookupResult::RESULT_CLASS;
+ r_result.class_name=obj->cast_to<GDNativeClass>()->get_name();
+
+ } else {
+ r_result.type=ScriptLanguage::LookupResult::RESULT_CLASS;
+ r_result.class_name=obj->get_class();
+ }
+ return OK;
+ }
+ } else {
+
+ r_result.type=ScriptLanguage::LookupResult::RESULT_CLASS_CONSTANT;
+ r_result.class_name="@Global Scope";
+ r_result.class_member=p_symbol;
+ return OK;
+ }
+ }
+
+ }
+#if 0
+ GDCompletionIdentifier identifier;
+ if (_guess_identifier_type(context,p.get_completion_line(),p_symbol,identifier)) {
+
+ print_line("var type: "+Variant::get_type_name(identifier.type));
+ if (identifier.script.is_valid()) {
+ print_line("var script: "+identifier.script->get_path());
+ }
+ print_line("obj type: "+String(identifier.obj_type));
+ print_line("value: "+String(identifier.value));
+ }
+#endif
+ }
+
+ } break;
+ case GDParser::COMPLETION_PARENT_FUNCTION: {
+
+ } break;
+ case GDParser::COMPLETION_METHOD:
+ isfunction=true;
+ case GDParser::COMPLETION_INDEX: {
+
+ const GDParser::Node *node = p.get_completion_node();
+ if (node->type!=GDParser::Node::TYPE_OPERATOR)
+ break;
+
+
+
+
+ GDCompletionIdentifier t;
+ if (_guess_expression_type(context,static_cast<const GDParser::OperatorNode *>(node)->arguments[0],p.get_completion_line(),t)) {
+
+ if (t.type==Variant::OBJECT && t.obj_type=="GDNativeClass") {
+ //native enum
+ Ref<GDNativeClass> gdn = t.value;
+ if (gdn.is_valid()) {
+ r_result.type=ScriptLanguage::LookupResult::RESULT_CLASS_CONSTANT;
+ r_result.class_name=gdn->get_name();;
+ r_result.class_member=p_symbol;
+ return OK;
+
+ }
+ } else if (t.type==Variant::OBJECT && t.obj_type!=StringName()) {
+
+ Ref<GDScript> on_script;
+
+ if (t.value.get_type()) {
+ Object *obj=t.value;
+
+
+ if (obj) {
+
+
+ on_script=obj->get_script();
+
+ if (on_script.is_valid()) {
+ int loc = on_script->get_member_line(p_symbol);
+ if (loc>=0) {
+ r_result.script=on_script;
+ r_result.type=ScriptLanguage::LookupResult::RESULT_SCRIPT_LOCATION;
+ r_result.location=loc;
+ return OK;
+ }
+ }
+ }
+ }
+
+ if (ClassDB::has_method(t.obj_type,p_symbol)) {
+
+ r_result.type=ScriptLanguage::LookupResult::RESULT_CLASS_METHOD;
+ r_result.class_name=t.obj_type;
+ r_result.class_member=p_symbol;
+ return OK;
+
+ }
+
+ bool success;
+ ClassDB::get_integer_constant(t.obj_type,p_symbol,&success);
+ if (success) {
+ r_result.type=ScriptLanguage::LookupResult::RESULT_CLASS_CONSTANT;
+ r_result.class_name=t.obj_type;
+ r_result.class_member=p_symbol;
+ return OK;
+ }
+
+
+ ClassDB::get_property_type(t.obj_type,p_symbol,&success);
+
+ if (success) {
+ r_result.type=ScriptLanguage::LookupResult::RESULT_CLASS_PROPERTY;
+ r_result.class_name=t.obj_type;
+ r_result.class_member=p_symbol;
+ return OK;
+ }
+
+
+ } else {
+
+ Variant::CallError ce;
+ Variant v = Variant::construct(t.type,NULL,0,ce);
+
+ bool valid;
+ v.get_numeric_constant_value(t.type,p_symbol,&valid);
+ if (valid) {
+ r_result.type=ScriptLanguage::LookupResult::RESULT_CLASS_CONSTANT;
+ r_result.class_name=Variant::get_type_name(t.type);
+ r_result.class_member=p_symbol;
+ return OK;
+ }
+
+ //todo check all inputevent types for property
+
+ v.get(p_symbol,&valid);
+
+ if (valid) {
+ r_result.type=ScriptLanguage::LookupResult::RESULT_CLASS_PROPERTY;
+ r_result.class_name=Variant::get_type_name(t.type);
+ r_result.class_member=p_symbol;
+ return OK;
+ }
+
+ if (v.has_method(p_symbol)) {
+
+ r_result.type=ScriptLanguage::LookupResult::RESULT_CLASS_METHOD;
+ r_result.class_name=Variant::get_type_name(t.type);
+ r_result.class_member=p_symbol;
+ return OK;
+
+ }
+
+
+ }
+ }
+
+
+ } break;
+ case GDParser::COMPLETION_CALL_ARGUMENTS: {
+
+ return ERR_CANT_RESOLVE;
+ } break;
+ case GDParser::COMPLETION_VIRTUAL_FUNC: {
+
+ GDCompletionIdentifier cid = _get_native_class(context);
+
+ if (cid.obj_type!=StringName()) {
+ List<MethodInfo> vm;
+ ClassDB::get_virtual_methods(cid.obj_type,&vm);
+ for(List<MethodInfo>::Element *E=vm.front();E;E=E->next()) {
+
+ if (p_symbol==E->get().name) {
+
+ r_result.type=ScriptLanguage::LookupResult::RESULT_CLASS_METHOD;
+ r_result.class_name=cid.obj_type;
+ r_result.class_member=p_symbol;
+ return OK;
+
+ }
+ }
+ }
+ } break;
+ case GDParser::COMPLETION_YIELD: {
+
+ return ERR_CANT_RESOLVE;
+
+ } break;
+
+ }
+
+
+ return ERR_CANT_RESOLVE;
+}
+
+#endif