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:
Juan Linietsky
2014-12-16 22:31:57 -03:00
parent be4e40e90a
commit bcf27feb98
30 changed files with 2245 additions and 929 deletions

View File

@ -359,385 +359,445 @@ void TextEdit::_update_scrollbars() {
void TextEdit::_notification(int p_what) {
switch(p_what) {
case NOTIFICATION_ENTER_TREE: {
switch(p_what) {
case NOTIFICATION_ENTER_TREE: {
_update_caches();
if (cursor_changed_dirty)
MessageQueue::get_singleton()->push_call(this,"_cursor_changed_emit");
if (text_changed_dirty)
MessageQueue::get_singleton()->push_call(this,"_text_changed_emit");
_update_caches();
if (cursor_changed_dirty)
MessageQueue::get_singleton()->push_call(this,"_cursor_changed_emit");
if (text_changed_dirty)
MessageQueue::get_singleton()->push_call(this,"_text_changed_emit");
} break;
case NOTIFICATION_RESIZED: {
} break;
case NOTIFICATION_RESIZED: {
cache.size=get_size();
adjust_viewport_to_cursor();
cache.size=get_size();
adjust_viewport_to_cursor();
} break;
case NOTIFICATION_THEME_CHANGED: {
} break;
case NOTIFICATION_THEME_CHANGED: {
_update_caches();
};
case NOTIFICATION_DRAW: {
_update_caches();
};
case NOTIFICATION_DRAW: {
int line_number_char_count=0;
int line_number_char_count=0;
{
int lc=text.size()+1;
cache.line_number_w=0;
while(lc) {
cache.line_number_w+=1;
lc/=10;
};
{
int lc=text.size()+1;
cache.line_number_w=0;
while(lc) {
cache.line_number_w+=1;
lc/=10;
};
if (line_numbers) {
if (line_numbers) {
line_number_char_count=cache.line_number_w;
cache.line_number_w=(cache.line_number_w+1)*cache.font->get_char_size('0').width;
} else {
cache.line_number_w=0;
}
line_number_char_count=cache.line_number_w;
cache.line_number_w=(cache.line_number_w+1)*cache.font->get_char_size('0').width;
} else {
cache.line_number_w=0;
}
}
_update_scrollbars();
}
_update_scrollbars();
RID ci = get_canvas_item();
int xmargin_beg=cache.style_normal->get_margin(MARGIN_LEFT)+cache.line_number_w;
int xmargin_end=cache.size.width-cache.style_normal->get_margin(MARGIN_RIGHT);
//let's do it easy for now:
cache.style_normal->draw(ci,Rect2(Point2(),cache.size));
if (has_focus())
cache.style_focus->draw(ci,Rect2(Point2(),cache.size));
RID ci = get_canvas_item();
int xmargin_beg=cache.style_normal->get_margin(MARGIN_LEFT)+cache.line_number_w;
int xmargin_end=cache.size.width-cache.style_normal->get_margin(MARGIN_RIGHT);
//let's do it easy for now:
cache.style_normal->draw(ci,Rect2(Point2(),cache.size));
if (has_focus())
cache.style_focus->draw(ci,Rect2(Point2(),cache.size));
int ascent=cache.font->get_ascent();
int ascent=cache.font->get_ascent();
int visible_rows = get_visible_rows();
int visible_rows = get_visible_rows();
int tab_w = cache.font->get_char_size(' ').width*tab_size;
int tab_w = cache.font->get_char_size(' ').width*tab_size;
Color color = cache.font_color;
int in_region=-1;
Color color = cache.font_color;
int in_region=-1;
if (syntax_coloring) {
if (syntax_coloring) {
if (custom_bg_color.a>0.01) {
if (custom_bg_color.a>0.01) {
Point2i ofs = Point2i(cache.style_normal->get_offset())/2.0;
VisualServer::get_singleton()->canvas_item_add_rect(ci,Rect2(ofs, get_size()-cache.style_normal->get_minimum_size()+ofs),custom_bg_color);
}
//compute actual region to start (may be inside say, a comment).
//slow in very large documments :( but ok for source!
Point2i ofs = Point2i(cache.style_normal->get_offset())/2.0;
VisualServer::get_singleton()->canvas_item_add_rect(ci,Rect2(ofs, get_size()-cache.style_normal->get_minimum_size()+ofs),custom_bg_color);
}
//compute actual region to start (may be inside say, a comment).
//slow in very large documments :( but ok for source!
for(int i=0;i<cursor.line_ofs;i++) {
for(int i=0;i<cursor.line_ofs;i++) {
const Map<int,Text::ColorRegionInfo>& cri_map=text.get_color_region_info(i);
const Map<int,Text::ColorRegionInfo>& cri_map=text.get_color_region_info(i);
if (in_region>=0 && color_regions[in_region].line_only) {
in_region=-1; //reset regions that end at end of line
}
if (in_region>=0 && color_regions[in_region].line_only) {
in_region=-1; //reset regions that end at end of line
}
for( const Map<int,Text::ColorRegionInfo>::Element* E= cri_map.front();E;E=E->next() ) {
for( const Map<int,Text::ColorRegionInfo>::Element* E= cri_map.front();E;E=E->next() ) {
const Text::ColorRegionInfo &cri=E->get();
const Text::ColorRegionInfo &cri=E->get();
if (in_region==-1) {
if (in_region==-1) {
if (!cri.end) {
if (!cri.end) {
in_region=cri.region;
}
} else if (in_region==cri.region && !color_regions[cri.region].line_only) { //ignore otherwise
in_region=cri.region;
}
} else if (in_region==cri.region && !color_regions[cri.region].line_only) { //ignore otherwise
if (cri.end || color_regions[cri.region].eq) {
if (cri.end || color_regions[cri.region].eq) {
in_region=-1;
}
}
}
}
}
in_region=-1;
}
}
}
}
}
int deregion=0; //force it to clear inrgion
Point2 cursor_pos;
int deregion=0; //force it to clear inrgion
Point2 cursor_pos;
for (int i=0;i<visible_rows;i++) {
for (int i=0;i<visible_rows;i++) {
int line=i+cursor.line_ofs;
int line=i+cursor.line_ofs;
if (line<0 || line>=(int)text.size())
continue;
if (line<0 || line>=(int)text.size())
continue;
const String &str=text[line];
const String &str=text[line];
int char_margin=xmargin_beg-cursor.x_ofs;
int char_ofs=0;
int ofs_y=i*get_row_height()+cache.line_spacing/2;
bool prev_is_char=false;
bool in_keyword=false;
Color keyword_color;
int char_margin=xmargin_beg-cursor.x_ofs;
int char_ofs=0;
int ofs_y=i*get_row_height()+cache.line_spacing/2;
bool prev_is_char=false;
bool in_keyword=false;
Color keyword_color;
if (cache.line_number_w) {
Color fcol = cache.font_color;
fcol.a*=0.4;
String fc = String::num(line+1);
while (fc.length() < line_number_char_count) {
fc="0"+fc;
}
if (cache.line_number_w) {
Color fcol = cache.font_color;
fcol.a*=0.4;
String fc = String::num(line+1);
while (fc.length() < line_number_char_count) {
fc="0"+fc;
}
cache.font->draw(ci,Point2(cache.style_normal->get_margin(MARGIN_LEFT),ofs_y+cache.font->get_ascent()),fc,fcol);
}
cache.font->draw(ci,Point2(cache.style_normal->get_margin(MARGIN_LEFT),ofs_y+cache.font->get_ascent()),fc,fcol);
}
const Map<int,Text::ColorRegionInfo>& cri_map=text.get_color_region_info(line);
const Map<int,Text::ColorRegionInfo>& cri_map=text.get_color_region_info(line);
if (text.is_marked(line)) {
if (text.is_marked(line)) {
VisualServer::get_singleton()->canvas_item_add_rect(ci,Rect2(xmargin_beg, ofs_y,xmargin_end-xmargin_beg,get_row_height()),cache.mark_color);
}
VisualServer::get_singleton()->canvas_item_add_rect(ci,Rect2(xmargin_beg, ofs_y,xmargin_end-xmargin_beg,get_row_height()),cache.mark_color);
}
if (text.is_breakpoint(line)) {
if (text.is_breakpoint(line)) {
VisualServer::get_singleton()->canvas_item_add_rect(ci,Rect2(xmargin_beg, ofs_y,xmargin_end-xmargin_beg,get_row_height()),cache.breakpoint_color);
}
VisualServer::get_singleton()->canvas_item_add_rect(ci,Rect2(xmargin_beg, ofs_y,xmargin_end-xmargin_beg,get_row_height()),cache.breakpoint_color);
}
if (line==cursor.line) {
if (line==cursor.line) {
VisualServer::get_singleton()->canvas_item_add_rect(ci,Rect2(xmargin_beg, ofs_y,xmargin_end-xmargin_beg,get_row_height()),cache.current_line_color);
VisualServer::get_singleton()->canvas_item_add_rect(ci,Rect2(xmargin_beg, ofs_y,xmargin_end-xmargin_beg,get_row_height()),cache.current_line_color);
}
for (int j=0;j<str.length();j++) {
}
for (int j=0;j<str.length();j++) {
//look for keyword
//look for keyword
if (deregion>0) {
deregion--;
if (deregion==0)
in_region=-1;
}
if (syntax_coloring && deregion==0) {
if (deregion>0) {
deregion--;
if (deregion==0)
in_region=-1;
}
if (syntax_coloring && deregion==0) {
color = cache.font_color; //reset
//find keyword
bool is_char = _is_text_char(str[j]);
bool is_symbol=_is_symbol(str[j]);
color = cache.font_color; //reset
//find keyword
bool is_char = _is_text_char(str[j]);
bool is_symbol=_is_symbol(str[j]);
if (j==0 && in_region>=0 && color_regions[in_region].line_only) {
in_region=-1; //reset regions that end at end of line
}
if (j==0 && in_region>=0 && color_regions[in_region].line_only) {
in_region=-1; //reset regions that end at end of line
}
if (is_symbol && cri_map.has(j)) {
if (is_symbol && cri_map.has(j)) {
const Text::ColorRegionInfo &cri=cri_map[j];
const Text::ColorRegionInfo &cri=cri_map[j];
if (in_region==-1) {
if (in_region==-1) {
if (!cri.end) {
if (!cri.end) {
in_region=cri.region;
}
} else if (in_region==cri.region && !color_regions[cri.region].line_only) { //ignore otherwise
in_region=cri.region;
}
} else if (in_region==cri.region && !color_regions[cri.region].line_only) { //ignore otherwise
if (cri.end || color_regions[cri.region].eq) {
if (cri.end || color_regions[cri.region].eq) {
deregion=color_regions[cri.region].eq?color_regions[cri.region].begin_key.length():color_regions[cri.region].end_key.length();
}
}
}
deregion=color_regions[cri.region].eq?color_regions[cri.region].begin_key.length():color_regions[cri.region].end_key.length();
}
}
}
if (!is_char)
in_keyword=false;
if (!is_char)
in_keyword=false;
if (in_region==-1 && !in_keyword && is_char && !prev_is_char) {
if (in_region==-1 && !in_keyword && is_char && !prev_is_char) {
int to=j;
while(_is_text_char(str[to]) && to<str.length())
to++;
int to=j;
while(_is_text_char(str[to]) && to<str.length())
to++;
uint32_t hash = String::hash(&str[j],to-j);
StrRange range(&str[j],to-j);
uint32_t hash = String::hash(&str[j],to-j);
StrRange range(&str[j],to-j);
const Color *col=keywords.custom_getptr(range,hash);
const Color *col=keywords.custom_getptr(range,hash);
if (col) {
if (col) {
in_keyword=true;
keyword_color=*col;
}
}
in_keyword=true;
keyword_color=*col;
}
}
if (in_region>=0)
color=color_regions[in_region].color;
else if (in_keyword)
color=keyword_color;
else if (is_symbol)
color=symbol_color;
if (in_region>=0)
color=color_regions[in_region].color;
else if (in_keyword)
color=keyword_color;
else if (is_symbol)
color=symbol_color;
prev_is_char=is_char;
prev_is_char=is_char;
}
int char_w;
}
int char_w;
//handle tabulator
//handle tabulator
if (str[j]=='\t') {
int left = char_ofs%tab_w;
if (left==0)
char_w=tab_w;
else
char_w=tab_w-char_ofs%tab_w; // is right...
if (str[j]=='\t') {
int left = char_ofs%tab_w;
if (left==0)
char_w=tab_w;
else
char_w=tab_w-char_ofs%tab_w; // is right...
} else {
char_w=cache.font->get_char_size(str[j],str[j+1]).width;
}
} else {
char_w=cache.font->get_char_size(str[j],str[j+1]).width;
}
if ( (char_ofs+char_margin)<xmargin_beg) {
char_ofs+=char_w;
continue;
}
if ( (char_ofs+char_margin)<xmargin_beg) {
char_ofs+=char_w;
continue;
}
if ( (char_ofs+char_margin+char_w)>=xmargin_end) {
if (syntax_coloring)
continue;
else
break;
}
if ( (char_ofs+char_margin+char_w)>=xmargin_end) {
if (syntax_coloring)
continue;
else
break;
}
bool in_selection = (selection.active && line>=selection.from_line && line<=selection.to_line && (line>selection.from_line || j>=selection.from_column) && (line<selection.to_line || j<selection.to_column));
bool in_selection = (selection.active && line>=selection.from_line && line<=selection.to_line && (line>selection.from_line || j>=selection.from_column) && (line<selection.to_line || j<selection.to_column));
if (in_selection) {
//inside selection!
VisualServer::get_singleton()->canvas_item_add_rect(ci,Rect2(Point2i( char_ofs+char_margin, ofs_y ), Size2i(char_w,get_row_height())),cache.selection_color);
}
if (in_selection) {
//inside selection!
VisualServer::get_singleton()->canvas_item_add_rect(ci,Rect2(Point2i( char_ofs+char_margin, ofs_y ), Size2i(char_w,get_row_height())),cache.selection_color);
}
if (str[j]>=32)
cache.font->draw_char(ci,Point2i( char_ofs+char_margin, ofs_y+ascent),str[j],str[j+1],in_selection?cache.font_selected_color:color);
else if (draw_tabs && str[j]=='\t') {
int yofs= (get_row_height() - cache.tab_icon->get_height())/2;
cache.tab_icon->draw(ci, Point2(char_ofs+char_margin,ofs_y+yofs),in_selection?cache.font_selected_color:color);
}
if (str[j]>=32)
cache.font->draw_char(ci,Point2i( char_ofs+char_margin, ofs_y+ascent),str[j],str[j+1],in_selection?cache.font_selected_color:color);
else if (draw_tabs && str[j]=='\t') {
int yofs= (get_row_height() - cache.tab_icon->get_height())/2;
cache.tab_icon->draw(ci, Point2(char_ofs+char_margin,ofs_y+yofs),in_selection?cache.font_selected_color:color);
}
if (cursor.column==j && cursor.line==line) {
if (cursor.column==j && cursor.line==line) {
cursor_pos = Point2i( char_ofs+char_margin, ofs_y );
VisualServer::get_singleton()->canvas_item_add_rect(ci,Rect2(cursor_pos, Size2i(1,get_row_height())),cache.font_color);
cursor_pos = Point2i( char_ofs+char_margin, ofs_y );
VisualServer::get_singleton()->canvas_item_add_rect(ci,Rect2(cursor_pos, Size2i(1,get_row_height())),cache.font_color);
}
char_ofs+=char_w;
}
char_ofs+=char_w;
}
}
if (cursor.column==str.length() && cursor.line==line) {
if (cursor.column==str.length() && cursor.line==line) {
cursor_pos=Point2i( char_ofs+char_margin, ofs_y );
VisualServer::get_singleton()->canvas_item_add_rect(ci,Rect2(cursor_pos, Size2i(1,get_row_height())),cache.font_color);
cursor_pos=Point2i( char_ofs+char_margin, ofs_y );
VisualServer::get_singleton()->canvas_item_add_rect(ci,Rect2(cursor_pos, Size2i(1,get_row_height())),cache.font_color);
}
}
}
}
if (completion_active) {
// code completion box
Ref<StyleBox> csb = get_stylebox("completion");
Ref<StyleBox> csel = get_stylebox("completion_selected");
int maxlines = get_constant("completion_lines");
int cmax_width = get_constant("completion_max_width")*cache.font->get_char_size('x').x;
Color existing = get_color("completion_existing");
int scrollw = get_constant("completion_scroll_width");
Color scrollc = get_color("completion_scroll_color");
if (completion_active) {
// code completion box
Ref<StyleBox> csb = get_stylebox("completion");
Ref<StyleBox> csel = get_stylebox("completion_selected");
int maxlines = get_constant("completion_lines");
int cmax_width = get_constant("completion_max_width")*cache.font->get_char_size('x').x;
Color existing = get_color("completion_existing");
int scrollw = get_constant("completion_scroll_width");
Color scrollc = get_color("completion_scroll_color");
int lines = MIN(completion_options.size(),maxlines);
int w=0;
int h=lines*get_row_height();
int nofs = cache.font->get_string_size(completion_base).width;
int lines = MIN(completion_options.size(),maxlines);
int w=0;
int h=lines*get_row_height();
int nofs = cache.font->get_string_size(completion_base).width;
if (completion_options.size() < 50) {
for(int i=0;i<completion_options.size();i++) {
int w2=MIN(cache.font->get_string_size(completion_options[i]).x,cmax_width);
if (w2>w)
w=w2;
}
} else {
w=cmax_width;
}
int th = h + csb->get_minimum_size().y;
if (cursor_pos.y+get_row_height()+th > get_size().height) {
completion_rect.pos.y=cursor_pos.y-th;
} else {
completion_rect.pos.y=cursor_pos.y+get_row_height()+csb->get_offset().y;
}
if (completion_options.size() < 50) {
for(int i=0;i<completion_options.size();i++) {
int w2=MIN(cache.font->get_string_size(completion_options[i]).x,cmax_width);
if (w2>w)
w=w2;
}
} else {
w=cmax_width;
}
if (cursor_pos.x-nofs+w+scrollw > get_size().width) {
completion_rect.pos.x=get_size().width-w-scrollw;
} else {
completion_rect.pos.x=cursor_pos.x-nofs;
}
int th = h + csb->get_minimum_size().y;
if (cursor_pos.y+get_row_height()+th > get_size().height) {
completion_rect.pos.y=cursor_pos.y-th;
} else {
completion_rect.pos.y=cursor_pos.y+get_row_height()+csb->get_offset().y;
completion_rect.size.width=w;
completion_rect.size.height=h;
if (completion_options.size()<=maxlines)
scrollw=0;
}
draw_style_box(csb,Rect2(completion_rect.pos-csb->get_offset(),completion_rect.size+csb->get_minimum_size()+Size2(scrollw,0)));
if (cursor_pos.x-nofs+w+scrollw > get_size().width) {
completion_rect.pos.x=get_size().width-w-scrollw;
} else {
completion_rect.pos.x=cursor_pos.x-nofs;
}
completion_rect.size.width=w;
completion_rect.size.height=h;
if (completion_options.size()<=maxlines)
scrollw=0;
int line_from = CLAMP(completion_index - lines/2, 0, completion_options.size() - lines);
draw_style_box(csel,Rect2(Point2(completion_rect.pos.x,completion_rect.pos.y+(completion_index-line_from)*get_row_height()),Size2(completion_rect.size.width,get_row_height())));
draw_style_box(csb,Rect2(completion_rect.pos-csb->get_offset(),completion_rect.size+csb->get_minimum_size()+Size2(scrollw,0)));
draw_rect(Rect2(completion_rect.pos,Size2(nofs,completion_rect.size.height)),existing);
for(int i=0;i<lines;i++) {
int line_from = CLAMP(completion_index - lines/2, 0, completion_options.size() - lines);
draw_style_box(csel,Rect2(Point2(completion_rect.pos.x,completion_rect.pos.y+(completion_index-line_from)*get_row_height()),Size2(completion_rect.size.width,get_row_height())));
int l = line_from + i;
ERR_CONTINUE( l < 0 || l>= completion_options.size());
draw_string(cache.font,Point2(completion_rect.pos.x,completion_rect.pos.y+i*get_row_height()+cache.font->get_ascent()),completion_options[l],cache.font_color,completion_rect.size.width);
}
draw_rect(Rect2(completion_rect.pos,Size2(nofs,completion_rect.size.height)),existing);
if (scrollw) {
//draw a small scroll rectangle to show a position in the options
float r = maxlines / (float)completion_options.size();
float o = line_from / (float)completion_options.size();
draw_rect(Rect2(completion_rect.pos.x+completion_rect.size.width,completion_rect.pos.y+o*completion_rect.size.y,scrollw,completion_rect.size.y*r),scrollc);
}
for(int i=0;i<lines;i++) {
completion_line_ofs=line_from;
int l = line_from + i;
ERR_CONTINUE( l < 0 || l>= completion_options.size());
draw_string(cache.font,Point2(completion_rect.pos.x,completion_rect.pos.y+i*get_row_height()+cache.font->get_ascent()),completion_options[l],cache.font_color,completion_rect.size.width);
}
}
if (scrollw) {
//draw a small scroll rectangle to show a position in the options
float r = maxlines / (float)completion_options.size();
float o = line_from / (float)completion_options.size();
draw_rect(Rect2(completion_rect.pos.x+completion_rect.size.width,completion_rect.pos.y+o*completion_rect.size.y,scrollw,completion_rect.size.y*r),scrollc);
}
completion_line_ofs=line_from;
}
} break;
case NOTIFICATION_FOCUS_ENTER: {
if (completion_hint!="") {
if (OS::get_singleton()->has_virtual_keyboard())
OS::get_singleton()->show_virtual_keyboard(get_text(),get_global_rect());
Ref<StyleBox> sb = get_stylebox("panel","TooltipPanel");
Ref<Font> font = cache.font;
Color font_color = get_color("font_color","TooltipLabel");
} break;
case NOTIFICATION_FOCUS_EXIT: {
if (OS::get_singleton()->has_virtual_keyboard())
OS::get_singleton()->hide_virtual_keyboard();
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++) {
} break;
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;
case NOTIFICATION_FOCUS_ENTER: {
if (OS::get_singleton()->has_virtual_keyboard())
OS::get_singleton()->show_virtual_keyboard(get_text(),get_global_rect());
} break;
case NOTIFICATION_FOCUS_EXIT: {
if (OS::get_singleton()->has_virtual_keyboard())
OS::get_singleton()->hide_virtual_keyboard();
} break;
}
}
void TextEdit::_consume_pair_symbol(CharType ch) {
@ -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;
@ -1318,6 +1381,13 @@ void TextEdit::_input_event(const InputEvent& p_input_event) {
_push_current_op();
} break;
case KEY_ESCAPE: {
if (completion_hint!="") {
completion_hint="";
update();
}
} break;
case KEY_TAB: {
if (readonly)
@ -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,33 +3062,56 @@ 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)
return;
completion_active=false;
completion_active=false;
update();
}
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])) {
s=String::chr(l[cofs-1])+s;
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) {
String l = text[cursor.line];
int ofs = CLAMP(cursor.column,0,l.length());
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"));
}