mirror of
https://github.com/godotengine/godot
synced 2024-09-05 17:09:44 +00:00
New Code Completion
-=-=-=-=-=-=-=-=-=- -Massive improvement to code completion -Argument hinting for functions If you manage to out-smart the code-completion in a situation where completion should be possible to guess, let me know. Please enter the commit message for your changes. Lines starting
This commit is contained in:
parent
be4e40e90a
commit
bcf27feb98
|
@ -87,7 +87,9 @@ Vector<StringName> MethodBind::get_argument_names() const {
|
|||
|
||||
|
||||
void MethodBind::set_default_arguments(const Vector<Variant>& p_defargs) {
|
||||
default_arguments=p_defargs; default_argument_count=default_arguments.size();
|
||||
default_arguments=p_defargs;
|
||||
default_argument_count=default_arguments.size();
|
||||
|
||||
}
|
||||
|
||||
#ifdef DEBUG_METHODS_ENABLED
|
||||
|
|
|
@ -1694,6 +1694,11 @@ void ObjectDB::debug_objects(DebugFunc p_func) {
|
|||
}
|
||||
|
||||
|
||||
void Object::get_argument_options(const StringName& p_function,int p_idx,List<String>*r_options) const {
|
||||
|
||||
|
||||
}
|
||||
|
||||
int ObjectDB::get_object_count() {
|
||||
|
||||
GLOBAL_LOCK_FUNCTION;
|
||||
|
|
|
@ -583,6 +583,7 @@ public:
|
|||
|
||||
virtual void get_translatable_strings(List<String> *p_strings) const;
|
||||
|
||||
virtual void get_argument_options(const StringName& p_function,int p_idx,List<String>*r_options) const;
|
||||
|
||||
StringName XL_MESSAGE(const StringName& p_message) const; //translate message (internationalization)
|
||||
StringName tr(const StringName& p_message) const; //translate message (alternative)
|
||||
|
|
|
@ -144,7 +144,7 @@ public:
|
|||
virtual bool has_named_classes() const=0;
|
||||
virtual int find_function(const String& p_function,const String& p_code) const=0;
|
||||
virtual String make_function(const String& p_class,const String& p_name,const StringArray& p_args) const=0;
|
||||
virtual Error complete_keyword(const String& p_code, int p_line, const String& p_base_path, const String& p_keyword, List<String>* r_options) { return ERR_UNAVAILABLE; }
|
||||
virtual Error complete_code(const String& p_code, const String& p_base_path, Object*p_owner,List<String>* r_options,String& r_call_hint) { return ERR_UNAVAILABLE; }
|
||||
virtual void auto_indent_code(String& p_code,int p_from_line,int p_to_line) const=0;
|
||||
|
||||
/* DEBUGGER FUNCTIONS */
|
||||
|
|
126
core/variant.cpp
126
core/variant.cpp
|
@ -2631,3 +2631,129 @@ Variant Variant::call(const StringName& p_method,VARIANT_ARG_DECLARE) {
|
|||
return ret;
|
||||
}
|
||||
|
||||
|
||||
String Variant::get_construct_string() const {
|
||||
|
||||
switch( type ) {
|
||||
|
||||
case NIL: return "null";
|
||||
case BOOL: return _data._bool ? "true" : "false";
|
||||
case INT: return String::num(_data._int);
|
||||
case REAL: return String::num(_data._real);
|
||||
case STRING: return "\""+*reinterpret_cast<const String*>(_data._mem)+"\"";
|
||||
case VECTOR2: return "Vector2("+operator Vector2()+")";
|
||||
case RECT2: return "Rect2("+operator Rect2()+")";
|
||||
case MATRIX32: return "Matrix32("+operator Matrix32()+")";
|
||||
case VECTOR3: return "Vector3("+operator Vector3()+")";
|
||||
case PLANE: return "Plane("+operator Plane()+")";
|
||||
//case QUAT:
|
||||
case _AABB: return "AABB("+operator AABB()+")";
|
||||
case QUAT: return "Quat("+operator Quat()+")";
|
||||
case MATRIX3: return "Matrix3("+operator Matrix3()+")";
|
||||
case TRANSFORM: return "Transform("+operator Transform()+")";
|
||||
case NODE_PATH: return "@\""+operator NodePath()+"\"";
|
||||
case INPUT_EVENT: return "InputEvent()";
|
||||
case COLOR: return "Color("+String::num( operator Color().r)+","+String::num( operator Color().g)+","+String::num( operator Color().b)+","+String::num( operator Color().a)+")" ;
|
||||
case DICTIONARY: {
|
||||
|
||||
const Dictionary &d =*reinterpret_cast<const Dictionary*>(_data._mem);
|
||||
//const String *K=NULL;
|
||||
String str="{";
|
||||
List<Variant> keys;
|
||||
d.get_key_list(&keys);
|
||||
|
||||
Vector<_VariantStrPair> pairs;
|
||||
|
||||
for(List<Variant>::Element *E=keys.front();E;E=E->next()) {
|
||||
|
||||
_VariantStrPair sp;
|
||||
sp.key=E->get().get_construct_string();
|
||||
sp.value=d[E->get()].get_construct_string();
|
||||
pairs.push_back(sp);
|
||||
}
|
||||
|
||||
pairs.sort();
|
||||
|
||||
for(int i=0;i<pairs.size();i++) {
|
||||
if (i>0)
|
||||
str+=", ";
|
||||
str+="("+pairs[i].key+":"+pairs[i].value+")";
|
||||
}
|
||||
str+="}";
|
||||
|
||||
return str;
|
||||
} break;
|
||||
case VECTOR3_ARRAY: {
|
||||
|
||||
DVector<Vector3> vec = operator DVector<Vector3>();
|
||||
String str="[";
|
||||
for(int i=0;i<vec.size();i++) {
|
||||
|
||||
if (i>0)
|
||||
str+=", ";
|
||||
str+=Variant( vec[i] ).get_construct_string();
|
||||
}
|
||||
return str+"]";
|
||||
} break;
|
||||
case STRING_ARRAY: {
|
||||
|
||||
DVector<String> vec = operator DVector<String>();
|
||||
String str="[";
|
||||
for(int i=0;i<vec.size();i++) {
|
||||
|
||||
if (i>0)
|
||||
str+=", ";
|
||||
str=str+=Variant( vec[i] ).get_construct_string();
|
||||
}
|
||||
return str+"]";
|
||||
} break;
|
||||
case INT_ARRAY: {
|
||||
|
||||
DVector<int> vec = operator DVector<int>();
|
||||
String str="[";
|
||||
for(int i=0;i<vec.size();i++) {
|
||||
|
||||
if (i>0)
|
||||
str+=", ";
|
||||
str=str+itos(vec[i]);
|
||||
}
|
||||
return str+"]";
|
||||
} break;
|
||||
case REAL_ARRAY: {
|
||||
|
||||
DVector<real_t> vec = operator DVector<real_t>();
|
||||
String str="[";
|
||||
for(int i=0;i<vec.size();i++) {
|
||||
|
||||
if (i>0)
|
||||
str+=", ";
|
||||
str=str+rtos(vec[i]);
|
||||
}
|
||||
return str+"]";
|
||||
} break;
|
||||
case ARRAY: {
|
||||
|
||||
Array arr = operator Array();
|
||||
String str="[";
|
||||
for (int i=0; i<arr.size(); i++) {
|
||||
if (i)
|
||||
str+=", ";
|
||||
str += arr[i].get_construct_string();
|
||||
};
|
||||
return str+"]";
|
||||
|
||||
} break;
|
||||
case OBJECT: {
|
||||
|
||||
if (_get_obj().obj)
|
||||
return _get_obj().obj->get_type()+".new()";
|
||||
else
|
||||
return "null";
|
||||
|
||||
} break;
|
||||
default: {
|
||||
return "["+get_type_name(type)+"]";
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -415,6 +415,8 @@ public:
|
|||
static bool has_numeric_constant(Variant::Type p_type, const StringName& p_value);
|
||||
static int get_numeric_constant_value(Variant::Type p_type, const StringName& p_value);
|
||||
|
||||
String get_construct_string() const;
|
||||
|
||||
void operator=(const Variant& p_variant); // only this is enough for all the other types
|
||||
Variant(const Variant& p_variant);
|
||||
_FORCE_INLINE_ Variant() { type=NIL; }
|
||||
|
|
|
@ -332,6 +332,12 @@ Error OS_Unix::execute(const String& p_path, const List<String>& p_arguments,boo
|
|||
Error OS_Unix::kill(const ProcessID& p_pid) {
|
||||
|
||||
int ret = ::kill(p_pid,SIGKILL);
|
||||
if (!ret) {
|
||||
//avoid zombie process
|
||||
int st;
|
||||
::waitpid(p_pid,&st,0);
|
||||
|
||||
}
|
||||
return ret?ERR_INVALID_PARAMETER:OK;
|
||||
}
|
||||
|
||||
|
|
30
makefile
30
makefile
|
@ -1,30 +0,0 @@
|
|||
#*************************************************************************/
|
||||
#* This file is part of: */
|
||||
#* GODOT ENGINE */
|
||||
#* http://www.godotengine.org */
|
||||
#*************************************************************************/
|
||||
# Simple makefile to give support for external C/C++ IDEs */
|
||||
#*************************************************************************/
|
||||
|
||||
# Default build
|
||||
all: debug
|
||||
|
||||
# Release Build
|
||||
release:
|
||||
scons target="release" bin/godot
|
||||
|
||||
# Profile Build
|
||||
profile:
|
||||
scons target="profile" bin/godot
|
||||
|
||||
# Debug Build
|
||||
debug:
|
||||
# Debug information (code size gets severely affected):
|
||||
# g: Default (same as g2)
|
||||
# g0: no debug info
|
||||
# g1: minimal info
|
||||
# g3: maximal info
|
||||
scons target="debug" CCFLAGS="-g" bin/godot
|
||||
|
||||
clean:
|
||||
scons -c bin/godot
|
|
@ -1168,6 +1168,7 @@ Error GDCompiler::_parse_function(GDScript *p_script,const GDParser::ClassNode *
|
|||
codegen.current_line=0;
|
||||
codegen.call_max=0;
|
||||
codegen.debug_stack=ScriptDebugger::get_singleton()!=NULL;
|
||||
Vector<StringName> argnames;
|
||||
|
||||
int stack_level=0;
|
||||
|
||||
|
@ -1175,6 +1176,9 @@ Error GDCompiler::_parse_function(GDScript *p_script,const GDParser::ClassNode *
|
|||
for(int i=0;i<p_func->arguments.size();i++) {
|
||||
int idx = i;
|
||||
codegen.add_stack_identifier(p_func->arguments[i],i);
|
||||
#ifdef TOOLS_ENABLED
|
||||
argnames.push_back(p_func->arguments[i]);
|
||||
#endif
|
||||
}
|
||||
stack_level=p_func->arguments.size();
|
||||
}
|
||||
|
@ -1249,6 +1253,9 @@ Error GDCompiler::_parse_function(GDScript *p_script,const GDParser::ClassNode *
|
|||
if (p_func)
|
||||
gdfunc->_static=p_func->_static;
|
||||
|
||||
#ifdef TOOLS_ENABLED
|
||||
gdfunc->arg_names=argnames;
|
||||
#endif
|
||||
//constants
|
||||
if (codegen.constant_map.size()) {
|
||||
gdfunc->_constant_count=codegen.constant_map.size();
|
||||
|
|
File diff suppressed because it is too large
Load diff
|
@ -30,19 +30,6 @@
|
|||
#include "print_string.h"
|
||||
#include "io/resource_loader.h"
|
||||
#include "os/file_access.h"
|
||||
/* TODO:
|
||||
|
||||
*Property reduce constant expressions
|
||||
*Implement missing operators in variant?
|
||||
*constructor
|
||||
*/
|
||||
|
||||
/*
|
||||
todo:
|
||||
fix post ++,--
|
||||
make sure ++,-- don't work on constant expressions
|
||||
seems passing parent node as param is not needed
|
||||
*/
|
||||
|
||||
template<class T>
|
||||
T* GDParser::alloc_node() {
|
||||
|
@ -116,14 +103,20 @@ bool GDParser::_enter_indent_block(BlockNode* p_block) {
|
|||
}
|
||||
}
|
||||
|
||||
bool GDParser::_parse_arguments(Node* p_parent,Vector<Node*>& p_args,bool p_static) {
|
||||
bool GDParser::_parse_arguments(Node* p_parent,Vector<Node*>& p_args,bool p_static,bool p_can_codecomplete) {
|
||||
|
||||
if (tokenizer->get_token()==GDTokenizer::TK_PARENTHESIS_CLOSE) {
|
||||
tokenizer->advance();
|
||||
} else {
|
||||
|
||||
int argidx=0;
|
||||
|
||||
while(true) {
|
||||
|
||||
if (tokenizer->get_token()==GDTokenizer::TK_CURSOR) {
|
||||
_make_completable_call(argidx);
|
||||
completion_node=p_parent;
|
||||
}
|
||||
|
||||
Node*arg = _parse_expression(p_parent,p_static);
|
||||
if (!arg)
|
||||
|
@ -144,6 +137,7 @@ bool GDParser::_parse_arguments(Node* p_parent,Vector<Node*>& p_args,bool p_stat
|
|||
}
|
||||
|
||||
tokenizer->advance();
|
||||
argidx++;
|
||||
} else {
|
||||
// something is broken
|
||||
_set_error("Expected ',' or ')'");
|
||||
|
@ -158,6 +152,48 @@ bool GDParser::_parse_arguments(Node* p_parent,Vector<Node*>& p_args,bool p_stat
|
|||
}
|
||||
|
||||
|
||||
void GDParser::_make_completable_call(int p_arg) {
|
||||
|
||||
completion_cursor=StringName();
|
||||
completion_type=COMPLETION_CALL_ARGUMENTS;
|
||||
completion_class=current_class;
|
||||
completion_function=current_function;
|
||||
completion_line=tokenizer->get_token_line();
|
||||
completion_argument=p_arg;
|
||||
completion_block=current_block;
|
||||
tokenizer->advance();
|
||||
|
||||
}
|
||||
|
||||
|
||||
bool GDParser::_get_completable_identifier(CompletionType p_type,StringName& identifier) {
|
||||
|
||||
identifier=StringName();
|
||||
if (tokenizer->get_token()==GDTokenizer::TK_IDENTIFIER) {
|
||||
identifier=tokenizer->get_token_identifier();
|
||||
tokenizer->advance();
|
||||
}
|
||||
if (tokenizer->get_token()==GDTokenizer::TK_CURSOR) {
|
||||
|
||||
completion_cursor=identifier;
|
||||
completion_type=p_type;
|
||||
completion_class=current_class;
|
||||
completion_function=current_function;
|
||||
completion_line=tokenizer->get_token_line();
|
||||
completion_block=current_block;
|
||||
tokenizer->advance();
|
||||
|
||||
if (tokenizer->get_token()==GDTokenizer::TK_IDENTIFIER) {
|
||||
identifier=identifier.operator String() + tokenizer->get_token_identifier().operator String();
|
||||
tokenizer->advance();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
GDParser::Node* GDParser::_parse_expression(Node *p_parent,bool p_static,bool p_allow_assign) {
|
||||
|
||||
|
@ -199,6 +235,9 @@ GDParser::Node* GDParser::_parse_expression(Node *p_parent,bool p_static,bool p_
|
|||
|
||||
tokenizer->advance();
|
||||
expr=subexpr;
|
||||
} else if (tokenizer->get_token()==GDTokenizer::TK_CURSOR) {
|
||||
tokenizer->advance();
|
||||
continue; //no point in cursor in the middle of expression
|
||||
|
||||
} else if (tokenizer->get_token()==GDTokenizer::TK_CONSTANT) {
|
||||
|
||||
|
@ -327,12 +366,19 @@ GDParser::Node* GDParser::_parse_expression(Node *p_parent,bool p_static,bool p_
|
|||
|
||||
Variant::Type bi_type = tokenizer->get_token_type();
|
||||
tokenizer->advance(2);
|
||||
if (tokenizer->get_token()!=GDTokenizer::TK_IDENTIFIER) {
|
||||
|
||||
StringName identifier;
|
||||
|
||||
if (_get_completable_identifier(COMPLETION_BUILT_IN_TYPE_CONSTANT,identifier)) {
|
||||
|
||||
completion_built_in_constant=bi_type;
|
||||
}
|
||||
|
||||
if (identifier!=StringName()) {
|
||||
|
||||
_set_error("Built-in type constant expected after '.'");
|
||||
return NULL;
|
||||
}
|
||||
StringName identifier = tokenizer->get_token_identifier();
|
||||
if (!Variant::has_numeric_constant(bi_type,identifier)) {
|
||||
|
||||
_set_error("Static constant '"+identifier.operator String()+"' not present in built-in type "+Variant::get_type_name(bi_type)+".");
|
||||
|
@ -342,7 +388,7 @@ GDParser::Node* GDParser::_parse_expression(Node *p_parent,bool p_static,bool p_
|
|||
ConstantNode *cn = alloc_node<ConstantNode>();
|
||||
cn->value=Variant::get_numeric_constant_value(bi_type,identifier);
|
||||
expr=cn;
|
||||
tokenizer->advance();
|
||||
|
||||
|
||||
} else if (tokenizer->get_token(1)==GDTokenizer::TK_PARENTHESIS_OPEN && (tokenizer->get_token()==GDTokenizer::TK_BUILT_IN_TYPE || tokenizer->get_token()==GDTokenizer::TK_IDENTIFIER || tokenizer->get_token()==GDTokenizer::TK_BUILT_IN_FUNC)) {
|
||||
//function or constructor
|
||||
|
@ -355,23 +401,35 @@ GDParser::Node* GDParser::_parse_expression(Node *p_parent,bool p_static,bool p_
|
|||
TypeNode *tn = alloc_node<TypeNode>();
|
||||
tn->vtype=tokenizer->get_token_type();
|
||||
op->arguments.push_back(tn);
|
||||
tokenizer->advance(2);
|
||||
} else if (tokenizer->get_token()==GDTokenizer::TK_BUILT_IN_FUNC) {
|
||||
|
||||
BuiltInFunctionNode *bn = alloc_node<BuiltInFunctionNode>();
|
||||
bn->function=tokenizer->get_token_built_in_func();
|
||||
op->arguments.push_back(bn);
|
||||
tokenizer->advance(2);
|
||||
} else {
|
||||
|
||||
SelfNode *self = alloc_node<SelfNode>();
|
||||
op->arguments.push_back(self);
|
||||
|
||||
IdentifierNode* id = alloc_node<IdentifierNode>();
|
||||
id->name=tokenizer->get_token_identifier();
|
||||
op->arguments.push_back(id);
|
||||
StringName identifier;
|
||||
if (_get_completable_identifier(COMPLETION_FUNCTION,identifier)) {
|
||||
|
||||
}
|
||||
|
||||
tokenizer->advance(2);
|
||||
if (!_parse_arguments(op,op->arguments,p_static))
|
||||
IdentifierNode* id = alloc_node<IdentifierNode>();
|
||||
id->name=identifier;
|
||||
op->arguments.push_back(id);
|
||||
tokenizer->advance(1);
|
||||
}
|
||||
|
||||
if (tokenizer->get_token()==GDTokenizer::TK_CURSOR) {
|
||||
_make_completable_call(0);
|
||||
completion_node=op;
|
||||
|
||||
}
|
||||
if (!_parse_arguments(op,op->arguments,p_static,true))
|
||||
return NULL;
|
||||
|
||||
expr=op;
|
||||
|
@ -381,22 +439,24 @@ GDParser::Node* GDParser::_parse_expression(Node *p_parent,bool p_static,bool p_
|
|||
|
||||
const ClassNode* cln = static_cast<const ClassNode*>(get_parse_tree());
|
||||
bool bfn = false;
|
||||
StringName idn( tokenizer->get_token_identifier() );
|
||||
StringName identifier;
|
||||
if (_get_completable_identifier(COMPLETION_IDENTIFIER,identifier)) {
|
||||
|
||||
}
|
||||
|
||||
for( int i=0; i<cln->constant_expressions.size(); ++i ) {
|
||||
|
||||
if( cln->constant_expressions[i].identifier == idn ) {
|
||||
tokenizer->advance();
|
||||
if( cln->constant_expressions[i].identifier == identifier ) {
|
||||
|
||||
expr = cln->constant_expressions[i].expression;
|
||||
bfn = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if( !bfn ) {
|
||||
if ( !bfn ) {
|
||||
IdentifierNode *id = alloc_node<IdentifierNode>();
|
||||
id->name = idn;
|
||||
tokenizer->advance();
|
||||
id->name = identifier;
|
||||
expr = id;
|
||||
}
|
||||
|
||||
|
@ -600,7 +660,7 @@ GDParser::Node* GDParser::_parse_expression(Node *p_parent,bool p_static,bool p_
|
|||
|
||||
expr=dict;
|
||||
|
||||
} else if (tokenizer->get_token()==GDTokenizer::TK_PERIOD && tokenizer->get_token(1)==GDTokenizer::TK_IDENTIFIER && tokenizer->get_token(2)==GDTokenizer::TK_PARENTHESIS_OPEN) {
|
||||
} else if (tokenizer->get_token()==GDTokenizer::TK_PERIOD && (tokenizer->get_token(1)==GDTokenizer::TK_IDENTIFIER || tokenizer->get_token(1)==GDTokenizer::TK_CURSOR) && tokenizer->get_token(2)==GDTokenizer::TK_PARENTHESIS_OPEN) {
|
||||
// parent call
|
||||
|
||||
tokenizer->advance(); //goto identifier
|
||||
|
@ -611,12 +671,16 @@ GDParser::Node* GDParser::_parse_expression(Node *p_parent,bool p_static,bool p_
|
|||
/*SelfNode *self = alloc_node<SelfNode>();
|
||||
op->arguments.push_back(self);
|
||||
forbidden for now */
|
||||
StringName identifier;
|
||||
if (_get_completable_identifier(COMPLETION_PARENT_FUNCTION,identifier)) {
|
||||
//indexing stuff
|
||||
}
|
||||
|
||||
IdentifierNode* id = alloc_node<IdentifierNode>();
|
||||
id->name=tokenizer->get_token_identifier();
|
||||
IdentifierNode *id = alloc_node<IdentifierNode>();
|
||||
id->name=identifier;
|
||||
op->arguments.push_back(id);
|
||||
|
||||
tokenizer->advance(2);
|
||||
tokenizer->advance(1);
|
||||
if (!_parse_arguments(op,op->arguments,p_static))
|
||||
return NULL;
|
||||
|
||||
|
@ -651,7 +715,7 @@ GDParser::Node* GDParser::_parse_expression(Node *p_parent,bool p_static,bool p_
|
|||
|
||||
//indexing using "."
|
||||
|
||||
if (tokenizer->get_token(1)!=GDTokenizer::TK_IDENTIFIER && tokenizer->get_token(1)!=GDTokenizer::TK_BUILT_IN_FUNC ) {
|
||||
if (tokenizer->get_token(1)!=GDTokenizer::TK_CURSOR && tokenizer->get_token(1)!=GDTokenizer::TK_IDENTIFIER && tokenizer->get_token(1)!=GDTokenizer::TK_BUILT_IN_FUNC ) {
|
||||
_set_error("Expected identifier as member");
|
||||
return NULL;
|
||||
} else if (tokenizer->get_token(2)==GDTokenizer::TK_PARENTHESIS_OPEN) {
|
||||
|
@ -659,37 +723,67 @@ GDParser::Node* GDParser::_parse_expression(Node *p_parent,bool p_static,bool p_
|
|||
OperatorNode * op = alloc_node<OperatorNode>();
|
||||
op->op=OperatorNode::OP_CALL;
|
||||
|
||||
tokenizer->advance();
|
||||
|
||||
IdentifierNode * id = alloc_node<IdentifierNode>();
|
||||
if (tokenizer->get_token(1)==GDTokenizer::TK_BUILT_IN_FUNC ) {
|
||||
if (tokenizer->get_token()==GDTokenizer::TK_BUILT_IN_FUNC ) {
|
||||
//small hack so built in funcs don't obfuscate methods
|
||||
|
||||
id->name=GDFunctions::get_func_name(tokenizer->get_token_built_in_func(1));
|
||||
id->name=GDFunctions::get_func_name(tokenizer->get_token_built_in_func());
|
||||
tokenizer->advance();
|
||||
|
||||
} else {
|
||||
id->name=tokenizer->get_token_identifier(1);
|
||||
StringName identifier;
|
||||
if (_get_completable_identifier(COMPLETION_METHOD,identifier)) {
|
||||
completion_node=op;
|
||||
//indexing stuff
|
||||
}
|
||||
|
||||
id->name=identifier;
|
||||
}
|
||||
|
||||
op->arguments.push_back(expr); // call what
|
||||
op->arguments.push_back(id); // call func
|
||||
//get arguments
|
||||
tokenizer->advance(3);
|
||||
if (!_parse_arguments(op,op->arguments,p_static))
|
||||
tokenizer->advance(1);
|
||||
if (tokenizer->get_token()==GDTokenizer::TK_CURSOR) {
|
||||
_make_completable_call(0);
|
||||
completion_node=op;
|
||||
|
||||
}
|
||||
if (!_parse_arguments(op,op->arguments,p_static,true))
|
||||
return NULL;
|
||||
expr=op;
|
||||
|
||||
} else {
|
||||
//simple indexing!
|
||||
|
||||
|
||||
OperatorNode * op = alloc_node<OperatorNode>();
|
||||
op->op=OperatorNode::OP_INDEX_NAMED;
|
||||
tokenizer->advance();
|
||||
|
||||
|
||||
StringName identifier;
|
||||
if (_get_completable_identifier(COMPLETION_INDEX,identifier)) {
|
||||
|
||||
if (identifier==StringName()) {
|
||||
identifier="@temp"; //so it parses allright
|
||||
}
|
||||
completion_node=op;
|
||||
|
||||
//indexing stuff
|
||||
}
|
||||
|
||||
IdentifierNode * id = alloc_node<IdentifierNode>();
|
||||
id->name=tokenizer->get_token_identifier(1);
|
||||
id->name=identifier;
|
||||
|
||||
op->arguments.push_back(expr);
|
||||
op->arguments.push_back(id);
|
||||
|
||||
expr=op;
|
||||
|
||||
tokenizer->advance(2);
|
||||
|
||||
}
|
||||
|
||||
} else if (tokenizer->get_token()==GDTokenizer::TK_BRACKET_OPEN) {
|
||||
|
@ -1442,6 +1536,7 @@ void GDParser::_parse_block(BlockNode *p_block,bool p_static) {
|
|||
cf_if->arguments.push_back(condition);
|
||||
|
||||
cf_if->body = alloc_node<BlockNode>();
|
||||
cf_if->body->parent_block=p_block;
|
||||
p_block->sub_blocks.push_back(cf_if->body);
|
||||
|
||||
if (!_enter_indent_block(cf_if->body)) {
|
||||
|
@ -1449,7 +1544,10 @@ void GDParser::_parse_block(BlockNode *p_block,bool p_static) {
|
|||
return;
|
||||
}
|
||||
|
||||
current_block=cf_if->body;
|
||||
_parse_block(cf_if->body,p_static);
|
||||
current_block=p_block;
|
||||
|
||||
if (error_set)
|
||||
return;
|
||||
p_block->statements.push_back(cf_if);
|
||||
|
@ -1476,6 +1574,7 @@ void GDParser::_parse_block(BlockNode *p_block,bool p_static) {
|
|||
tokenizer->advance();
|
||||
|
||||
cf_if->body_else=alloc_node<BlockNode>();
|
||||
cf_if->body_else->parent_block=p_block;
|
||||
p_block->sub_blocks.push_back(cf_if->body_else);
|
||||
|
||||
ControlFlowNode *cf_else = alloc_node<ControlFlowNode>();
|
||||
|
@ -1491,6 +1590,7 @@ void GDParser::_parse_block(BlockNode *p_block,bool p_static) {
|
|||
cf_if->body_else->statements.push_back(cf_else);
|
||||
cf_if=cf_else;
|
||||
cf_if->body=alloc_node<BlockNode>();
|
||||
cf_if->body->parent_block=p_block;
|
||||
p_block->sub_blocks.push_back(cf_if->body);
|
||||
|
||||
|
||||
|
@ -1499,7 +1599,9 @@ void GDParser::_parse_block(BlockNode *p_block,bool p_static) {
|
|||
return;
|
||||
}
|
||||
|
||||
current_block=cf_else->body;
|
||||
_parse_block(cf_else->body,p_static);
|
||||
current_block=p_block;
|
||||
if (error_set)
|
||||
return;
|
||||
|
||||
|
@ -1515,13 +1617,16 @@ void GDParser::_parse_block(BlockNode *p_block,bool p_static) {
|
|||
|
||||
tokenizer->advance();
|
||||
cf_if->body_else=alloc_node<BlockNode>();
|
||||
cf_if->body_else->parent_block=p_block;
|
||||
p_block->sub_blocks.push_back(cf_if->body_else);
|
||||
|
||||
if (!_enter_indent_block(cf_if->body_else)) {
|
||||
p_block->end_line=tokenizer->get_token_line();
|
||||
return;
|
||||
}
|
||||
current_block=cf_if->body_else;
|
||||
_parse_block(cf_if->body_else,p_static);
|
||||
current_block=p_block;
|
||||
if (error_set)
|
||||
return;
|
||||
|
||||
|
@ -1548,6 +1653,7 @@ void GDParser::_parse_block(BlockNode *p_block,bool p_static) {
|
|||
cf_while->arguments.push_back(condition);
|
||||
|
||||
cf_while->body = alloc_node<BlockNode>();
|
||||
cf_while->body->parent_block=p_block;
|
||||
p_block->sub_blocks.push_back(cf_while->body);
|
||||
|
||||
if (!_enter_indent_block(cf_while->body)) {
|
||||
|
@ -1555,7 +1661,9 @@ void GDParser::_parse_block(BlockNode *p_block,bool p_static) {
|
|||
return;
|
||||
}
|
||||
|
||||
current_block=cf_while->body;
|
||||
_parse_block(cf_while->body,p_static);
|
||||
current_block=p_block;
|
||||
if (error_set)
|
||||
return;
|
||||
p_block->statements.push_back(cf_while);
|
||||
|
@ -1592,6 +1700,7 @@ void GDParser::_parse_block(BlockNode *p_block,bool p_static) {
|
|||
cf_for->arguments.push_back(container);
|
||||
|
||||
cf_for->body = alloc_node<BlockNode>();
|
||||
cf_for->body->parent_block=p_block;
|
||||
p_block->sub_blocks.push_back(cf_for->body);
|
||||
|
||||
if (!_enter_indent_block(cf_for->body)) {
|
||||
|
@ -1599,7 +1708,10 @@ void GDParser::_parse_block(BlockNode *p_block,bool p_static) {
|
|||
return;
|
||||
}
|
||||
|
||||
current_block=cf_for->body;
|
||||
_parse_block(cf_for->body,p_static);
|
||||
current_block=p_block;
|
||||
|
||||
if (error_set)
|
||||
return;
|
||||
p_block->statements.push_back(cf_for);
|
||||
|
@ -1865,7 +1977,9 @@ void GDParser::_parse_class(ClassNode *p_class) {
|
|||
|
||||
ClassNode *newclass = alloc_node<ClassNode>();
|
||||
newclass->initializer = alloc_node<BlockNode>();
|
||||
newclass->initializer->parent_class=newclass;
|
||||
newclass->name=name;
|
||||
newclass->owner=p_class;
|
||||
|
||||
p_class->subclasses.push_back(newclass);
|
||||
|
||||
|
@ -1882,7 +1996,9 @@ void GDParser::_parse_class(ClassNode *p_class) {
|
|||
_set_error("Indented block expected.");
|
||||
return;
|
||||
}
|
||||
current_class=newclass;
|
||||
_parse_class(newclass);
|
||||
current_class=p_class;
|
||||
|
||||
} break;
|
||||
/* this is for functions....
|
||||
|
@ -2020,6 +2136,7 @@ void GDParser::_parse_class(ClassNode *p_class) {
|
|||
tokenizer->advance();
|
||||
|
||||
BlockNode *block = alloc_node<BlockNode>();
|
||||
block->parent_class=p_class;
|
||||
|
||||
if (name=="_init") {
|
||||
|
||||
|
@ -2095,8 +2212,12 @@ void GDParser::_parse_class(ClassNode *p_class) {
|
|||
p_class->functions.push_back(function);
|
||||
|
||||
|
||||
_parse_block(block,_static);
|
||||
current_function=function;
|
||||
function->body=block;
|
||||
current_block=block;
|
||||
_parse_block(block,_static);
|
||||
current_block=NULL;
|
||||
|
||||
//arguments
|
||||
} break;
|
||||
case GDTokenizer::TK_PR_EXPORT: {
|
||||
|
@ -2401,7 +2522,9 @@ void GDParser::_parse_class(ClassNode *p_class) {
|
|||
}
|
||||
|
||||
member.identifier=tokenizer->get_token_identifier();
|
||||
member.expression=NULL;
|
||||
member._export.name=member.identifier;
|
||||
member.line=tokenizer->get_token_line();
|
||||
tokenizer->advance();
|
||||
|
||||
if (tokenizer->get_token()==GDTokenizer::TK_OP_ASSIGN) {
|
||||
|
@ -2417,6 +2540,8 @@ void GDParser::_parse_class(ClassNode *p_class) {
|
|||
if (!subexpr)
|
||||
return;
|
||||
|
||||
member.expression=subexpr;
|
||||
|
||||
if (autoexport) {
|
||||
if (subexpr->type==Node::TYPE_ARRAY) {
|
||||
|
||||
|
@ -2608,6 +2733,8 @@ Error GDParser::_parse(const String& p_base_path) {
|
|||
//assume class
|
||||
ClassNode *main_class = alloc_node<ClassNode>();
|
||||
main_class->initializer = alloc_node<BlockNode>();
|
||||
main_class->initializer->parent_class=main_class;
|
||||
current_class=main_class;
|
||||
|
||||
_parse_class(main_class);
|
||||
|
||||
|
@ -2625,6 +2752,12 @@ Error GDParser::_parse(const String& p_base_path) {
|
|||
|
||||
Error GDParser::parse_bytecode(const Vector<uint8_t> &p_bytecode,const String& p_base_path, const String &p_self_path) {
|
||||
|
||||
completion_type=COMPLETION_NONE;
|
||||
completion_node=NULL;
|
||||
completion_class=NULL;
|
||||
completion_function=NULL;
|
||||
completion_block=NULL;
|
||||
|
||||
self_path=p_self_path;
|
||||
GDTokenizerBuffer *tb = memnew( GDTokenizerBuffer );
|
||||
tb->set_code_buffer(p_bytecode);
|
||||
|
@ -2638,6 +2771,12 @@ Error GDParser::parse_bytecode(const Vector<uint8_t> &p_bytecode,const String& p
|
|||
|
||||
Error GDParser::parse(const String& p_code, const String& p_base_path, bool p_just_validate, const String &p_self_path) {
|
||||
|
||||
completion_type=COMPLETION_NONE;
|
||||
completion_node=NULL;
|
||||
completion_class=NULL;
|
||||
completion_function=NULL;
|
||||
completion_block=NULL;
|
||||
|
||||
self_path=p_self_path;
|
||||
GDTokenizerText *tt = memnew( GDTokenizerText );
|
||||
tt->set_code(p_code);
|
||||
|
@ -2667,6 +2806,12 @@ void GDParser::clear() {
|
|||
head=NULL;
|
||||
list=NULL;
|
||||
|
||||
completion_type=COMPLETION_NONE;
|
||||
completion_node=NULL;
|
||||
completion_class=NULL;
|
||||
completion_function=NULL;
|
||||
completion_block=NULL;
|
||||
|
||||
validating=false;
|
||||
error_set=false;
|
||||
tab_level.clear();
|
||||
|
@ -2680,6 +2825,52 @@ void GDParser::clear() {
|
|||
|
||||
}
|
||||
|
||||
|
||||
GDParser::CompletionType GDParser::get_completion_type() {
|
||||
|
||||
return completion_type;
|
||||
}
|
||||
|
||||
StringName GDParser::get_completion_cursor() {
|
||||
|
||||
return completion_cursor;
|
||||
}
|
||||
|
||||
int GDParser::get_completion_line() {
|
||||
|
||||
return completion_line;
|
||||
}
|
||||
|
||||
Variant::Type GDParser::get_completion_built_in_constant(){
|
||||
|
||||
return completion_built_in_constant;
|
||||
}
|
||||
|
||||
GDParser::Node *GDParser::get_completion_node(){
|
||||
|
||||
return completion_node;
|
||||
}
|
||||
|
||||
GDParser::BlockNode *GDParser::get_completion_block() {
|
||||
|
||||
return completion_block;
|
||||
}
|
||||
|
||||
GDParser::ClassNode *GDParser::get_completion_class(){
|
||||
|
||||
return completion_class;
|
||||
}
|
||||
|
||||
GDParser::FunctionNode *GDParser::get_completion_function(){
|
||||
|
||||
return completion_function;
|
||||
}
|
||||
|
||||
int GDParser::get_completion_argument_index() {
|
||||
|
||||
return completion_argument;
|
||||
}
|
||||
|
||||
GDParser::GDParser() {
|
||||
|
||||
head=NULL;
|
||||
|
|
|
@ -84,6 +84,8 @@ public:
|
|||
StringName identifier;
|
||||
StringName setter;
|
||||
StringName getter;
|
||||
int line;
|
||||
Node *expression;
|
||||
};
|
||||
struct Constant {
|
||||
StringName identifier;
|
||||
|
@ -96,10 +98,11 @@ public:
|
|||
Vector<FunctionNode*> functions;
|
||||
Vector<FunctionNode*> static_functions;
|
||||
BlockNode *initializer;
|
||||
ClassNode *owner;
|
||||
//Vector<Node*> initializers;
|
||||
int end_line;
|
||||
|
||||
ClassNode() { tool=false; type=TYPE_CLASS; extends_used=false; end_line=-1;}
|
||||
ClassNode() { tool=false; type=TYPE_CLASS; extends_used=false; end_line=-1; owner=NULL;}
|
||||
};
|
||||
|
||||
|
||||
|
@ -118,6 +121,8 @@ public:
|
|||
|
||||
struct BlockNode : public Node {
|
||||
|
||||
ClassNode *parent_class=NULL;
|
||||
BlockNode *parent_block=NULL;
|
||||
Map<StringName,int> locals;
|
||||
List<Node*> statements;
|
||||
Vector<StringName> variables;
|
||||
|
@ -126,7 +131,7 @@ public:
|
|||
//the following is useful for code completion
|
||||
List<BlockNode*> sub_blocks;
|
||||
int end_line;
|
||||
BlockNode() { type=TYPE_BLOCK; end_line=-1;}
|
||||
BlockNode() { type=TYPE_BLOCK; end_line=-1; parent_block=NULL; parent_class=NULL; }
|
||||
};
|
||||
|
||||
struct TypeNode : public Node {
|
||||
|
@ -349,6 +354,18 @@ public:
|
|||
};
|
||||
*/
|
||||
|
||||
enum CompletionType {
|
||||
COMPLETION_NONE,
|
||||
COMPLETION_BUILT_IN_TYPE_CONSTANT,
|
||||
COMPLETION_FUNCTION,
|
||||
COMPLETION_IDENTIFIER,
|
||||
COMPLETION_PARENT_FUNCTION,
|
||||
COMPLETION_METHOD,
|
||||
COMPLETION_CALL_ARGUMENTS,
|
||||
COMPLETION_INDEX,
|
||||
};
|
||||
|
||||
|
||||
|
||||
private:
|
||||
|
||||
|
@ -375,12 +392,31 @@ private:
|
|||
String base_path;
|
||||
String self_path;
|
||||
|
||||
|
||||
ClassNode *current_class;
|
||||
FunctionNode *current_function;
|
||||
BlockNode *current_block;
|
||||
|
||||
bool _get_completable_identifier(CompletionType p_type,StringName& identifier);
|
||||
void _make_completable_call(int p_arg);
|
||||
|
||||
CompletionType completion_type;
|
||||
StringName completion_cursor;
|
||||
bool completion_static;
|
||||
Variant::Type completion_built_in_constant;
|
||||
Node *completion_node;
|
||||
ClassNode *completion_class;
|
||||
FunctionNode *completion_function;
|
||||
BlockNode *completion_block;
|
||||
int completion_line;
|
||||
int completion_argument;
|
||||
|
||||
PropertyInfo current_export;
|
||||
|
||||
void _set_error(const String& p_error, int p_line=-1, int p_column=-1);
|
||||
|
||||
|
||||
bool _parse_arguments(Node* p_parent,Vector<Node*>& p_args,bool p_static);
|
||||
bool _parse_arguments(Node* p_parent, Vector<Node*>& p_args, bool p_static, bool p_can_codecomplete=false);
|
||||
bool _enter_indent_block(BlockNode *p_block=NULL);
|
||||
bool _parse_newline();
|
||||
Node* _parse_expression(Node *p_parent,bool p_static,bool p_allow_assign=false);
|
||||
|
@ -404,6 +440,19 @@ public:
|
|||
|
||||
const Node *get_parse_tree() const;
|
||||
|
||||
//completion info
|
||||
|
||||
CompletionType get_completion_type();
|
||||
StringName get_completion_cursor();
|
||||
int get_completion_line();
|
||||
Variant::Type get_completion_built_in_constant();
|
||||
Node *get_completion_node();
|
||||
ClassNode *get_completion_class();
|
||||
BlockNode *get_completion_block();
|
||||
FunctionNode *get_completion_function();
|
||||
int get_completion_argument_index();
|
||||
|
||||
|
||||
void clear();
|
||||
GDParser();
|
||||
~GDParser();
|
||||
|
|
|
@ -129,6 +129,10 @@ friend class GDCompiler;
|
|||
const char*_func_cname;
|
||||
#endif
|
||||
|
||||
#ifdef TOOLS_ENABLED
|
||||
Vector<StringName> arg_names;
|
||||
#endif
|
||||
|
||||
List<StackDebug> stack_debug;
|
||||
|
||||
_FORCE_INLINE_ Variant *_get_variant(int p_address,GDInstance *p_instance,GDScript *p_script,Variant &self,Variant *p_stack,String& r_error) const;
|
||||
|
@ -169,6 +173,19 @@ public:
|
|||
_FORCE_INLINE_ bool is_empty() const { return _code_size==0; }
|
||||
|
||||
int get_argument_count() const { return _argument_count; }
|
||||
StringName get_argument_name(int p_idx) const {
|
||||
#ifdef TOOLS_ENABLED
|
||||
ERR_FAIL_INDEX_V(p_idx,arg_names.size(),StringName());
|
||||
return arg_names[p_idx];
|
||||
#endif
|
||||
return StringName();
|
||||
|
||||
}
|
||||
Variant get_default_argument(int p_idx) const {
|
||||
ERR_FAIL_INDEX_V(p_idx,default_arguments.size(),Variant());
|
||||
return default_arguments[p_idx];
|
||||
}
|
||||
|
||||
Variant call(GDInstance *p_instance,const Variant **p_args, int p_argcount,Variant::CallError& r_err,CallState *p_state=NULL);
|
||||
|
||||
GDFunction();
|
||||
|
@ -293,6 +310,7 @@ protected:
|
|||
static void _bind_methods();
|
||||
public:
|
||||
|
||||
bool is_valid() const { return valid; }
|
||||
|
||||
const Map<StringName,Ref<GDScript> >& get_subclasses() const { return subclasses; }
|
||||
const Map<StringName,Variant >& get_constants() const { return constants; }
|
||||
|
@ -488,7 +506,7 @@ public:
|
|||
virtual bool has_named_classes() const;
|
||||
virtual int find_function(const String& p_function,const String& p_code) const;
|
||||
virtual String make_function(const String& p_class,const String& p_name,const StringArray& p_args) const;
|
||||
virtual Error complete_keyword(const String& p_code, int p_line, const String& p_base_path,const String& p_keyword, List<String>* r_options);
|
||||
virtual Error complete_code(const String& p_code, const String& p_base_path, Object*p_owner,List<String>* r_options,String& r_call_hint);
|
||||
virtual void auto_indent_code(String& p_code,int p_from_line,int p_to_line) const;
|
||||
|
||||
/* DEBUGGER FUNCTIONS */
|
||||
|
|
|
@ -110,7 +110,8 @@ const char* GDTokenizer::token_names[TK_MAX]={
|
|||
"':'",
|
||||
"'\\n'",
|
||||
"Error",
|
||||
"EOF"};
|
||||
"EOF",
|
||||
"Cursor"};
|
||||
|
||||
const char *GDTokenizer::get_token_name(Token p_token) {
|
||||
|
||||
|
@ -648,6 +649,9 @@ void GDTokenizerText::_advance() {
|
|||
}
|
||||
|
||||
} break;
|
||||
case 0xFFFF: {
|
||||
_make_token(TK_CURSOR);
|
||||
} break;
|
||||
default: {
|
||||
|
||||
if (_is_number(GETCHAR(0)) || (GETCHAR(0)=='.' && _is_number(GETCHAR(1)))) {
|
||||
|
|
|
@ -118,6 +118,7 @@ public:
|
|||
TK_NEWLINE,
|
||||
TK_ERROR,
|
||||
TK_EOF,
|
||||
TK_CURSOR, //used for code completion
|
||||
TK_MAX
|
||||
};
|
||||
|
||||
|
|
|
@ -1398,6 +1398,7 @@ void OS_Windows::set_video_mode(const VideoMode& p_video_mode,int p_screen) {
|
|||
|
||||
|
||||
}
|
||||
|
||||
OS::VideoMode OS_Windows::get_video_mode(int p_screen) const {
|
||||
|
||||
return video_mode;
|
||||
|
|
|
@ -1178,6 +1178,19 @@ NodePath AnimationPlayer::get_root() const {
|
|||
return root;
|
||||
}
|
||||
|
||||
void AnimationPlayer::get_argument_options(const StringName& p_function,int p_idx,List<String>*r_options) const {
|
||||
|
||||
String pf = p_function;
|
||||
if (p_function=="play" || p_function=="remove_animation" || p_function=="has_animation" || p_function=="queue") {
|
||||
List<StringName> al;
|
||||
get_animation_list(&al);
|
||||
for (List<StringName>::Element *E=al.front();E;E=E->next()) {
|
||||
|
||||
r_options->push_back("\""+String(E->get())+"\"");
|
||||
}
|
||||
}
|
||||
Node::get_argument_options(p_function,p_idx,r_options);
|
||||
}
|
||||
|
||||
void AnimationPlayer::_bind_methods() {
|
||||
|
||||
|
|
|
@ -290,6 +290,9 @@ public:
|
|||
|
||||
void clear_caches(); ///< must be called by hand if an animation was modified after added
|
||||
|
||||
void get_argument_options(const StringName& p_function,int p_idx,List<String>*r_options) const;
|
||||
|
||||
|
||||
AnimationPlayer();
|
||||
~AnimationPlayer();
|
||||
|
||||
|
|
|
@ -1325,9 +1325,12 @@ Size2 Control::get_minimum_size() const {
|
|||
|
||||
Ref<Texture> Control::get_icon(const StringName& p_name,const StringName& p_type) const {
|
||||
|
||||
if (p_type==StringName()) {
|
||||
|
||||
const Ref<Texture>* tex = data.icon_override.getptr(p_name);
|
||||
if (tex)
|
||||
return *tex;
|
||||
}
|
||||
|
||||
StringName type = p_type?p_type:get_type_name();
|
||||
|
||||
|
@ -1353,12 +1356,11 @@ Ref<Texture> Control::get_icon(const StringName& p_name,const StringName& p_type
|
|||
|
||||
Ref<StyleBox> Control::get_stylebox(const StringName& p_name,const StringName& p_type) const {
|
||||
|
||||
|
||||
if (p_type==StringName()) {
|
||||
const Ref<StyleBox>* style = data.style_override.getptr(p_name);
|
||||
|
||||
|
||||
if (style)
|
||||
return *style;
|
||||
}
|
||||
|
||||
StringName type = p_type?p_type:get_type_name();
|
||||
|
||||
|
@ -1382,9 +1384,11 @@ Ref<StyleBox> Control::get_stylebox(const StringName& p_name,const StringName& p
|
|||
}
|
||||
Ref<Font> Control::get_font(const StringName& p_name,const StringName& p_type) const {
|
||||
|
||||
if (p_type==StringName()) {
|
||||
const Ref<Font>* font = data.font_override.getptr(p_name);
|
||||
if (font)
|
||||
return *font;
|
||||
}
|
||||
|
||||
StringName type = p_type?p_type:get_type_name();
|
||||
|
||||
|
@ -1411,9 +1415,11 @@ Ref<Font> Control::get_font(const StringName& p_name,const StringName& p_type) c
|
|||
}
|
||||
Color Control::get_color(const StringName& p_name,const StringName& p_type) const {
|
||||
|
||||
if (p_type==StringName()) {
|
||||
const Color* color = data.color_override.getptr(p_name);
|
||||
if (color)
|
||||
return *color;
|
||||
}
|
||||
|
||||
StringName type = p_type?p_type:get_type_name();
|
||||
// try with custom themes
|
||||
|
@ -1438,9 +1444,11 @@ Color Control::get_color(const StringName& p_name,const StringName& p_type) cons
|
|||
|
||||
int Control::get_constant(const StringName& p_name,const StringName& p_type) const {
|
||||
|
||||
if (p_type==StringName()) {
|
||||
const int* constant = data.constant_override.getptr(p_name);
|
||||
if (constant)
|
||||
return *constant;
|
||||
}
|
||||
|
||||
StringName type = p_type?p_type:get_type_name();
|
||||
// try with custom themes
|
||||
|
@ -1467,9 +1475,11 @@ int Control::get_constant(const StringName& p_name,const StringName& p_type) con
|
|||
|
||||
bool Control::has_icon(const StringName& p_name,const StringName& p_type) const {
|
||||
|
||||
if (p_type==StringName()) {
|
||||
const Ref<Texture>* tex = data.icon_override.getptr(p_name);
|
||||
if (tex)
|
||||
return true;
|
||||
}
|
||||
|
||||
StringName type = p_type?p_type:get_type_name();
|
||||
|
||||
|
@ -1494,11 +1504,12 @@ bool Control::has_icon(const StringName& p_name,const StringName& p_type) const
|
|||
}
|
||||
bool Control::has_stylebox(const StringName& p_name,const StringName& p_type) const {
|
||||
|
||||
|
||||
if (p_type==StringName()) {
|
||||
const Ref<StyleBox>* style = data.style_override.getptr(p_name);
|
||||
|
||||
if (style)
|
||||
return true;
|
||||
}
|
||||
|
||||
StringName type = p_type?p_type:get_type_name();
|
||||
|
||||
|
@ -1523,9 +1534,11 @@ bool Control::has_stylebox(const StringName& p_name,const StringName& p_type) co
|
|||
}
|
||||
bool Control::has_font(const StringName& p_name,const StringName& p_type) const {
|
||||
|
||||
if (p_type==StringName()) {
|
||||
const Ref<Font>* font = data.font_override.getptr(p_name);
|
||||
if (font)
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
StringName type = p_type?p_type:get_type_name();
|
||||
|
@ -1551,9 +1564,11 @@ bool Control::has_font(const StringName& p_name,const StringName& p_type) const
|
|||
}
|
||||
bool Control::has_color(const StringName& p_name,const StringName& p_type) const {
|
||||
|
||||
if (p_type==StringName()) {
|
||||
const Color* color = data.color_override.getptr(p_name);
|
||||
if (color)
|
||||
return true;
|
||||
}
|
||||
|
||||
StringName type = p_type?p_type:get_type_name();
|
||||
|
||||
|
@ -1579,9 +1594,12 @@ bool Control::has_color(const StringName& p_name,const StringName& p_type) const
|
|||
|
||||
bool Control::has_constant(const StringName& p_name,const StringName& p_type) const {
|
||||
|
||||
if (p_type==StringName()) {
|
||||
|
||||
const int* constant = data.constant_override.getptr(p_name);
|
||||
if (constant)
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
StringName type = p_type?p_type:get_type_name();
|
||||
|
|
|
@ -649,6 +649,7 @@ void TextEdit::_notification(int p_what) {
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
if (completion_active) {
|
||||
// code completion box
|
||||
Ref<StyleBox> csb = get_stylebox("completion");
|
||||
|
@ -682,6 +683,7 @@ void TextEdit::_notification(int p_what) {
|
|||
completion_rect.pos.y=cursor_pos.y-th;
|
||||
} else {
|
||||
completion_rect.pos.y=cursor_pos.y+get_row_height()+csb->get_offset().y;
|
||||
|
||||
}
|
||||
|
||||
if (cursor_pos.x-nofs+w+scrollw > get_size().width) {
|
||||
|
@ -721,6 +723,64 @@ void TextEdit::_notification(int p_what) {
|
|||
|
||||
}
|
||||
|
||||
if (completion_hint!="") {
|
||||
|
||||
Ref<StyleBox> sb = get_stylebox("panel","TooltipPanel");
|
||||
Ref<Font> font = cache.font;
|
||||
Color font_color = get_color("font_color","TooltipLabel");
|
||||
|
||||
|
||||
int max_w=0;
|
||||
int sc = completion_hint.get_slice_count("\n");
|
||||
int offset=0;
|
||||
int spacing=0;
|
||||
for(int i=0;i<sc;i++) {
|
||||
|
||||
String l = completion_hint.get_slice("\n",i);
|
||||
int len = font->get_string_size(l).x;
|
||||
max_w = MAX(len,max_w);
|
||||
if (i==0) {
|
||||
offset = font->get_string_size(l.substr(0,l.find(String::chr(0xFFFF)))).x;
|
||||
} else {
|
||||
spacing+=cache.line_spacing;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
|
||||
Size2 size = Size2(max_w,sc*font->get_height()+spacing);
|
||||
Size2 minsize = size+sb->get_minimum_size();
|
||||
|
||||
|
||||
if (completion_hint_offset==-0xFFFF) {
|
||||
completion_hint_offset=cursor_pos.x-offset;
|
||||
}
|
||||
|
||||
|
||||
Point2 hint_ofs = Vector2(completion_hint_offset,cursor_pos.y-minsize.y);
|
||||
draw_style_box(sb,Rect2(hint_ofs,minsize));
|
||||
|
||||
spacing=0;
|
||||
for(int i=0;i<sc;i++) {
|
||||
int begin=0;
|
||||
int end=0;
|
||||
String l = completion_hint.get_slice("\n",i);
|
||||
|
||||
if (l.find(String::chr(0xFFFF))!=-1) {
|
||||
begin = font->get_string_size(l.substr(0,l.find(String::chr(0xFFFF)))).x;
|
||||
end = font->get_string_size(l.substr(0,l.rfind(String::chr(0xFFFF)))).x;
|
||||
}
|
||||
|
||||
draw_string(font,hint_ofs+sb->get_offset()+Vector2(0,font->get_ascent()+font->get_height()*i+spacing),l.replace(String::chr(0xFFFF),""),font_color);
|
||||
if (end>0) {
|
||||
Vector2 b = hint_ofs+sb->get_offset()+Vector2(begin,font->get_height()+font->get_height()*i+spacing-1);
|
||||
draw_line(b,b+Vector2(end-begin,0),font_color);
|
||||
}
|
||||
spacing+=cache.line_spacing;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
} break;
|
||||
|
@ -918,6 +978,7 @@ void TextEdit::_input_event(const InputEvent& p_input_event) {
|
|||
return;
|
||||
} else {
|
||||
_cancel_completion();
|
||||
_cancel_code_hint();
|
||||
}
|
||||
|
||||
if (mb.pressed) {
|
||||
|
@ -1172,6 +1233,7 @@ void TextEdit::_input_event(const InputEvent& p_input_event) {
|
|||
}
|
||||
|
||||
_cancel_completion();
|
||||
|
||||
}
|
||||
|
||||
/* TEST CONTROL FIRST!! */
|
||||
|
@ -1268,6 +1330,7 @@ void TextEdit::_input_event(const InputEvent& p_input_event) {
|
|||
break;
|
||||
unselect=true;
|
||||
break;
|
||||
|
||||
default:
|
||||
if (k.unicode>=32 && !k.mod.command && !k.mod.alt && !k.mod.meta)
|
||||
clear=true;
|
||||
|
@ -1317,6 +1380,13 @@ void TextEdit::_input_event(const InputEvent& p_input_event) {
|
|||
_insert_text_at_cursor(ins);
|
||||
_push_current_op();
|
||||
|
||||
} break;
|
||||
case KEY_ESCAPE: {
|
||||
if (completion_hint!="") {
|
||||
completion_hint="";
|
||||
update();
|
||||
|
||||
}
|
||||
} break;
|
||||
case KEY_TAB: {
|
||||
|
||||
|
@ -1454,6 +1524,7 @@ void TextEdit::_input_event(const InputEvent& p_input_event) {
|
|||
|
||||
if (k.mod.shift)
|
||||
_post_shift_selection();
|
||||
_cancel_code_hint();
|
||||
|
||||
} break;
|
||||
case KEY_DOWN: {
|
||||
|
@ -1473,6 +1544,7 @@ void TextEdit::_input_event(const InputEvent& p_input_event) {
|
|||
|
||||
if (k.mod.shift)
|
||||
_post_shift_selection();
|
||||
_cancel_code_hint();
|
||||
|
||||
} break;
|
||||
|
||||
|
@ -2333,6 +2405,30 @@ String TextEdit::get_text() {
|
|||
|
||||
};
|
||||
|
||||
String TextEdit::get_text_for_completion() {
|
||||
|
||||
String longthing;
|
||||
int len = text.size();
|
||||
for (int i=0;i<len;i++) {
|
||||
|
||||
if (i==cursor.line) {
|
||||
longthing+=text[i].substr(0,cursor.column);
|
||||
longthing+=String::chr(0xFFFF); //not unicode, represents the cursor
|
||||
longthing+=text[i].substr(cursor.column,text[i].size());
|
||||
} else {
|
||||
|
||||
longthing+=text[i];
|
||||
}
|
||||
|
||||
|
||||
if (i!=len-1)
|
||||
longthing+="\n";
|
||||
}
|
||||
|
||||
return longthing;
|
||||
|
||||
};
|
||||
|
||||
|
||||
String TextEdit::get_line(int line) const {
|
||||
|
||||
|
@ -2966,12 +3062,23 @@ void TextEdit::_confirm_completion() {
|
|||
|
||||
if (same)
|
||||
cursor_set_column(cursor.column+remaining.length());
|
||||
else
|
||||
else {
|
||||
insert_text_at_cursor(remaining);
|
||||
if (remaining.ends_with("(") && auto_brace_completion_enabled) {
|
||||
insert_text_at_cursor(")");
|
||||
cursor.column--;
|
||||
}
|
||||
}
|
||||
|
||||
_cancel_completion();
|
||||
}
|
||||
|
||||
|
||||
void TextEdit::_cancel_code_hint() {
|
||||
completion_hint="";
|
||||
update();
|
||||
}
|
||||
|
||||
void TextEdit::_cancel_completion() {
|
||||
|
||||
if (!completion_active)
|
||||
|
@ -2982,17 +3089,29 @@ void TextEdit::_cancel_completion() {
|
|||
|
||||
}
|
||||
|
||||
static bool _is_completable(CharType c) {
|
||||
|
||||
return !_is_symbol(c) || c=='"' || c=='\'';
|
||||
}
|
||||
|
||||
|
||||
void TextEdit::_update_completion_candidates() {
|
||||
|
||||
String l = text[cursor.line];
|
||||
int cofs = CLAMP(cursor.column,0,l.length());
|
||||
|
||||
|
||||
String s;
|
||||
while(cofs>0 && l[cofs-1]>32 && !_is_symbol(l[cofs-1])) {
|
||||
|
||||
while(cofs>0 && l[cofs-1]>32 && _is_completable(l[cofs-1])) {
|
||||
s=String::chr(l[cofs-1])+s;
|
||||
if (l[cofs-1]=='\'' || l[cofs-1]=='"')
|
||||
break;
|
||||
|
||||
cofs--;
|
||||
}
|
||||
|
||||
|
||||
update();
|
||||
|
||||
if (s=="" && (cofs==0 || !completion_prefixes.has(String::chr(l[cofs-1])))) {
|
||||
|
@ -3055,36 +3174,24 @@ void TextEdit::_update_completion_candidates() {
|
|||
completion_enabled=true;
|
||||
}
|
||||
|
||||
|
||||
|
||||
void TextEdit::query_code_comple() {
|
||||
|
||||
String l = text[cursor.line];
|
||||
int ofs = CLAMP(cursor.column,0,l.length());
|
||||
String cs;
|
||||
while(ofs>0 && l[ofs-1]>32) {
|
||||
|
||||
if (_is_symbol(l[ofs-1])) {
|
||||
String s;
|
||||
while(ofs>0 && l[ofs-1]>32 && _is_symbol(l[ofs-1])) {
|
||||
s=String::chr(l[ofs-1])+s;
|
||||
ofs--;
|
||||
}
|
||||
if (completion_prefixes.has(s))
|
||||
cs=s+cs;
|
||||
else
|
||||
break;
|
||||
} else {
|
||||
if (ofs>0 && (_is_completable(l[ofs-1]) || completion_prefixes.has(String::chr(l[ofs-1]))))
|
||||
emit_signal("request_completion");
|
||||
|
||||
cs=String::chr(l[ofs-1])+cs;
|
||||
ofs--;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if (cs!="") {
|
||||
emit_signal("request_completion",cs,cursor.line);
|
||||
|
||||
}
|
||||
void TextEdit::set_code_hint(const String& p_hint) {
|
||||
|
||||
completion_hint=p_hint;
|
||||
completion_hint_offset=-0xFFFF;
|
||||
update();
|
||||
}
|
||||
|
||||
void TextEdit::code_complete(const Vector<String> &p_strings) {
|
||||
|
@ -3236,7 +3343,7 @@ void TextEdit::_bind_methods() {
|
|||
|
||||
ADD_SIGNAL(MethodInfo("cursor_changed"));
|
||||
ADD_SIGNAL(MethodInfo("text_changed"));
|
||||
ADD_SIGNAL(MethodInfo("request_completion",PropertyInfo(Variant::STRING,"keyword"),PropertyInfo(Variant::INT,"line")));
|
||||
ADD_SIGNAL(MethodInfo("request_completion"));
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -185,6 +185,8 @@ class TextEdit : public Control {
|
|||
int completion_index;
|
||||
Rect2i completion_rect;
|
||||
int completion_line_ofs;
|
||||
String completion_hint;
|
||||
int completion_hint_offset;
|
||||
|
||||
bool setting_text;
|
||||
|
||||
|
@ -261,6 +263,7 @@ class TextEdit : public Control {
|
|||
|
||||
void _clear();
|
||||
void _cancel_completion();
|
||||
void _cancel_code_hint();
|
||||
void _confirm_completion();
|
||||
void _update_completion_candidates();
|
||||
|
||||
|
@ -378,8 +381,11 @@ public:
|
|||
|
||||
void set_completion(bool p_enabled,const Vector<String>& p_prefixes);
|
||||
void code_complete(const Vector<String> &p_strings);
|
||||
void set_code_hint(const String& p_hint);
|
||||
void query_code_comple();
|
||||
|
||||
String get_text_for_completion();
|
||||
|
||||
TextEdit();
|
||||
~TextEdit();
|
||||
};
|
||||
|
|
|
@ -1731,6 +1731,26 @@ NodePath Node::get_import_path() const {
|
|||
|
||||
#endif
|
||||
|
||||
static void _add_nodes_to_options(const Node *p_base,const Node *p_node,List<String>*r_options) {
|
||||
|
||||
if (p_node!=p_base && !p_node->get_owner())
|
||||
return;
|
||||
String n = p_base->get_path_to(p_node);
|
||||
r_options->push_back("\""+n+"\"");
|
||||
for(int i=0;i<p_node->get_child_count();i++) {
|
||||
_add_nodes_to_options(p_base,p_node->get_child(i),r_options);
|
||||
}
|
||||
}
|
||||
|
||||
void Node::get_argument_options(const StringName& p_function,int p_idx,List<String>*r_options) const {
|
||||
|
||||
String pf=p_function;
|
||||
if ((pf=="has_node" || pf=="get_node") && p_idx==0) {
|
||||
|
||||
_add_nodes_to_options(this,this,r_options);
|
||||
}
|
||||
Object::get_argument_options(p_function,p_idx,r_options);
|
||||
}
|
||||
|
||||
void Node::_bind_methods() {
|
||||
|
||||
|
|
|
@ -284,6 +284,7 @@ public:
|
|||
NodePath get_import_path() const;
|
||||
#endif
|
||||
|
||||
void get_argument_options(const StringName& p_function,int p_idx,List<String>*r_options) const;
|
||||
|
||||
_FORCE_INLINE_ Viewport *get_viewport() const { return data.viewport; }
|
||||
|
||||
|
|
|
@ -458,6 +458,8 @@ FixedMaterial::~FixedMaterial() {
|
|||
}
|
||||
|
||||
|
||||
|
||||
|
||||
bool ShaderMaterial::_set(const StringName& p_name, const Variant& p_value) {
|
||||
|
||||
if (p_name==SceneStringNames::get_singleton()->shader_shader) {
|
||||
|
@ -558,7 +560,21 @@ void ShaderMaterial::_bind_methods() {
|
|||
}
|
||||
|
||||
|
||||
void ShaderMaterial::get_argument_options(const StringName& p_function,int p_idx,List<String>*r_options) const {
|
||||
|
||||
String f = p_function.operator String();
|
||||
if ((f=="get_shader_param" || f=="set_shader_param") && p_idx==0) {
|
||||
|
||||
if (shader.is_valid()) {
|
||||
List<PropertyInfo> pl;
|
||||
shader->get_param_list(&pl);
|
||||
for (List<PropertyInfo>::Element *E=pl.front();E;E=E->next()) {
|
||||
r_options->push_back(E->get().name);
|
||||
}
|
||||
}
|
||||
}
|
||||
Material::get_argument_options(p_function,p_idx,r_options);
|
||||
}
|
||||
|
||||
ShaderMaterial::ShaderMaterial() :Material(VisualServer::get_singleton()->material_create()){
|
||||
|
||||
|
|
|
@ -243,6 +243,7 @@ public:
|
|||
void set_shader_param(const StringName& p_param,const Variant& p_value);
|
||||
Variant get_shader_param(const StringName& p_param) const;
|
||||
|
||||
void get_argument_options(const StringName& p_function,int p_idx,List<String>*r_options) const;
|
||||
|
||||
ShaderMaterial();
|
||||
};
|
||||
|
|
|
@ -487,6 +487,7 @@ FindReplaceDialog::FindReplaceDialog() {
|
|||
|
||||
vb->add_child(error_label);
|
||||
|
||||
|
||||
set_hide_on_ok(false);
|
||||
|
||||
}
|
||||
|
@ -507,15 +508,19 @@ void CodeTextEditor::_text_changed() {
|
|||
}
|
||||
|
||||
void CodeTextEditor::_code_complete_timer_timeout() {
|
||||
if (!is_visible())
|
||||
return;
|
||||
if (enable_complete_timer)
|
||||
text_editor->query_code_comple();
|
||||
}
|
||||
|
||||
void CodeTextEditor::_complete_request(const String& p_request, int p_line) {
|
||||
void CodeTextEditor::_complete_request() {
|
||||
|
||||
List<String> entries;
|
||||
_code_complete_script(text_editor->get_text(),p_request,p_line,&entries);
|
||||
_code_complete_script(text_editor->get_text_for_completion(),&entries);
|
||||
// print_line("COMPLETE: "+p_request);
|
||||
if (entries.size()==0)
|
||||
return;
|
||||
Vector<String> strs;
|
||||
strs.resize(entries.size());
|
||||
int i=0;
|
||||
|
@ -555,7 +560,7 @@ void CodeTextEditor::_on_settings_change() {
|
|||
|
||||
// AUTO BRACE COMPLETION
|
||||
text_editor->set_auto_brace_completion(
|
||||
EDITOR_DEF("text_editor/auto_brace_complete", false)
|
||||
EDITOR_DEF("text_editor/auto_brace_complete", true)
|
||||
);
|
||||
|
||||
code_complete_timer->set_wait_time(
|
||||
|
@ -632,6 +637,8 @@ CodeTextEditor::CodeTextEditor() {
|
|||
text_editor->connect("request_completion", this,"_complete_request");
|
||||
Vector<String> cs;
|
||||
cs.push_back(".");
|
||||
cs.push_back(",");
|
||||
cs.push_back("(");
|
||||
text_editor->set_completion(true,cs);
|
||||
idle->connect("timeout", this,"_text_changed_idle_timeout");
|
||||
|
||||
|
|
|
@ -135,7 +135,7 @@ class CodeTextEditor : public Control {
|
|||
|
||||
void _on_settings_change();
|
||||
|
||||
void _complete_request(const String& p_request,int p_line);
|
||||
void _complete_request();
|
||||
protected:
|
||||
|
||||
void set_error(const String& p_error);
|
||||
|
@ -143,7 +143,7 @@ protected:
|
|||
|
||||
virtual void _load_theme_settings() {}
|
||||
virtual void _validate_script()=0;
|
||||
virtual void _code_complete_script(const String& p_code, const String& p_keyword,int p_line, List<String>* r_options) {};
|
||||
virtual void _code_complete_script(const String& p_code, List<String>* r_options) {};
|
||||
|
||||
|
||||
void _text_changed_idle_timeout();
|
||||
|
|
|
@ -120,6 +120,8 @@ void CollisionPolygonEditor::_wip_close() {
|
|||
|
||||
bool CollisionPolygonEditor::forward_spatial_input_event(Camera* p_camera,const InputEvent& p_event) {
|
||||
|
||||
if (!node)
|
||||
return false;
|
||||
|
||||
Transform gt = node->get_global_transform();
|
||||
float depth = node->get_depth()*0.5;
|
||||
|
|
|
@ -384,9 +384,35 @@ void ScriptTextEditor::_validate_script() {
|
|||
_update_name();
|
||||
}
|
||||
|
||||
void ScriptTextEditor::_code_complete_script(const String& p_code, const String& p_keyword,int p_line, List<String>* r_options) {
|
||||
|
||||
Error err = script->get_language()->complete_keyword(p_code,p_line,script->get_path().get_base_dir(),p_keyword,r_options);
|
||||
static Node* _find_node_for_script(Node* p_base, Node*p_current, const Ref<Script>& p_script) {
|
||||
|
||||
if (p_current->get_owner()!=p_base && p_base!=p_current)
|
||||
return NULL;
|
||||
Ref<Script> c = p_current->get_script();
|
||||
if (c==p_script)
|
||||
return p_current;
|
||||
for(int i=0;i<p_current->get_child_count();i++) {
|
||||
Node *found = _find_node_for_script(p_base,p_current->get_child(i),p_script);
|
||||
if (found)
|
||||
return found;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void ScriptTextEditor::_code_complete_script(const String& p_code, List<String>* r_options) {
|
||||
|
||||
Node *base = get_tree()->get_edited_scene_root();
|
||||
if (base) {
|
||||
base = _find_node_for_script(base,base,script);
|
||||
}
|
||||
String hint;
|
||||
Error err = script->get_language()->complete_code(p_code,script->get_path().get_base_dir(),base,r_options,hint);
|
||||
if (hint!="") {
|
||||
get_text_edit()->set_code_hint(hint);
|
||||
print_line("hint: "+hint.replace(String::chr(0xFFFF),"|"));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
|
|
|
@ -85,7 +85,7 @@ protected:
|
|||
|
||||
|
||||
virtual void _validate_script();
|
||||
virtual void _code_complete_script(const String& p_code,const String& p_keyword, int p_line, List<String>* r_options);
|
||||
virtual void _code_complete_script(const String& p_code, List<String>* r_options);
|
||||
virtual void _load_theme_settings();
|
||||
void _notification(int p_what);
|
||||
|
||||
|
|
Loading…
Reference in a new issue