Skip to content

Commit

Permalink
Merge pull request #81633 from matorin57/code-completion-popup
Browse files Browse the repository at this point in the history
Avoid resetting the code completion popup excessively
  • Loading branch information
akien-mga committed Oct 3, 2023
2 parents 24c166d + 303d099 commit b11309d
Show file tree
Hide file tree
Showing 3 changed files with 97 additions and 10 deletions.
45 changes: 35 additions & 10 deletions scene/gui/code_edit.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3223,7 +3223,7 @@ void CodeEdit::_filter_code_completion_candidates_impl() {
int line_height = get_line_height();

if (GDVIRTUAL_IS_OVERRIDDEN(_filter_code_completion_candidates)) {
code_completion_options.clear();
Vector<ScriptLanguage::CodeCompletionOption> code_completion_options_new;
code_completion_base = "";

/* Build options argument. */
Expand Down Expand Up @@ -3273,11 +3273,15 @@ void CodeEdit::_filter_code_completion_candidates_impl() {
if (theme_cache.font.is_valid()) {
max_width = MAX(max_width, theme_cache.font->get_string_size(option.display, HORIZONTAL_ALIGNMENT_LEFT, -1, theme_cache.font_size).width + offset);
}
code_completion_options.push_back(option);
code_completion_options_new.push_back(option);
}

if (_should_reset_selected_option_for_new_options(code_completion_options_new)) {
code_completion_current_selected = 0;
}
code_completion_options = code_completion_options_new;

code_completion_longest_line = MIN(max_width, theme_cache.code_completion_max_width * theme_cache.font_size);
code_completion_current_selected = 0;
code_completion_force_item_center = -1;
code_completion_active = true;
queue_redraw();
Expand Down Expand Up @@ -3352,7 +3356,7 @@ void CodeEdit::_filter_code_completion_candidates_impl() {
/* For now handle only traditional quoted strings. */
bool single_quote = in_string != -1 && first_quote_col > 0 && delimiters[in_string].start_key == "'";

code_completion_options.clear();
Vector<ScriptLanguage::CodeCompletionOption> code_completion_options_new;
code_completion_base = string_to_complete;

/* Don't autocomplete setting numerical values. */
Expand Down Expand Up @@ -3384,7 +3388,8 @@ void CodeEdit::_filter_code_completion_candidates_impl() {

if (string_to_complete.length() == 0) {
option.get_option_characteristics(string_to_complete);
code_completion_options.push_back(option);
code_completion_options_new.push_back(option);

if (theme_cache.font.is_valid()) {
max_width = MAX(max_width, theme_cache.font->get_string_size(option.display, HORIZONTAL_ALIGNMENT_LEFT, -1, theme_cache.font_size).width + offset);
}
Expand Down Expand Up @@ -3459,34 +3464,54 @@ void CodeEdit::_filter_code_completion_candidates_impl() {
}
}

code_completion_options.push_back(option);
code_completion_options_new.push_back(option);
if (theme_cache.font.is_valid()) {
max_width = MAX(max_width, theme_cache.font->get_string_size(option.display, HORIZONTAL_ALIGNMENT_LEFT, -1, theme_cache.font_size).width + offset);
}
}
}

/* No options to complete, cancel. */
if (code_completion_options.size() == 0) {
if (code_completion_options_new.size() == 0) {
cancel_code_completion();
return;
}

/* A perfect match, stop completion. */
if (code_completion_options.size() == 1 && string_to_complete == code_completion_options[0].display) {
if (code_completion_options_new.size() == 1 && string_to_complete == code_completion_options_new[0].display) {
cancel_code_completion();
return;
}

code_completion_options.sort_custom<CodeCompletionOptionCompare>();
code_completion_options_new.sort_custom<CodeCompletionOptionCompare>();
if (_should_reset_selected_option_for_new_options(code_completion_options_new)) {
code_completion_current_selected = 0;
}
code_completion_options = code_completion_options_new;

code_completion_longest_line = MIN(max_width, theme_cache.code_completion_max_width * theme_cache.font_size);
code_completion_current_selected = 0;
code_completion_force_item_center = -1;
code_completion_active = true;
queue_redraw();
}

// Assumes both the new_options and the code_completion_options are sorted.
bool CodeEdit::_should_reset_selected_option_for_new_options(const Vector<ScriptLanguage::CodeCompletionOption> &p_new_options) {
if (code_completion_current_selected >= p_new_options.size()) {
return true;
}

for (int i = 0; i < code_completion_options.size() && i < p_new_options.size(); i++) {
if (i > code_completion_current_selected) {
return false;
}
if (code_completion_options[i].display != p_new_options[i].display) {
return true;
}
}
return false;
}

void CodeEdit::_lines_edited_from(int p_from_line, int p_to_line) {
_update_delimiter_cache(p_from_line, p_to_line);

Expand Down
1 change: 1 addition & 0 deletions scene/gui/code_edit.h
Original file line number Diff line number Diff line change
Expand Up @@ -222,6 +222,7 @@ class CodeEdit : public TextEdit {

void _update_scroll_selected_line(float p_mouse_y);
void _filter_code_completion_candidates_impl();
bool _should_reset_selected_option_for_new_options(const Vector<ScriptLanguage::CodeCompletionOption> &p_new_options);

/* Line length guidelines */
TypedArray<int> line_length_guideline_columns;
Expand Down
61 changes: 61 additions & 0 deletions tests/scene/test_code_edit.h
Original file line number Diff line number Diff line change
Expand Up @@ -3725,6 +3725,67 @@ TEST_CASE("[SceneTree][CodeEdit] completion") {
CHECK(code_edit->get_line(0) == "sstest");
}

SUBCASE("[CodeEdit] autocomplete currently selected option") {
code_edit->set_code_completion_enabled(true);
REQUIRE(code_edit->is_code_completion_enabled());

// Initially select item 0.
code_edit->insert_text_at_caret("te");
code_edit->set_caret_column(2);
code_edit->add_code_completion_option(CodeEdit::CodeCompletionKind::KIND_VARIABLE, "te1", "te1");
code_edit->add_code_completion_option(CodeEdit::CodeCompletionKind::KIND_VARIABLE, "te3", "te3");
code_edit->update_code_completion_options();
CHECK_MESSAGE(code_edit->get_code_completion_selected_index() == 0, "Initially selected item should be 0.");

// After adding later options shouldn't update selection.
code_edit->add_code_completion_option(CodeEdit::CodeCompletionKind::KIND_VARIABLE, "te1", "te1");
code_edit->add_code_completion_option(CodeEdit::CodeCompletionKind::KIND_VARIABLE, "te3", "te3");
code_edit->add_code_completion_option(CodeEdit::CodeCompletionKind::KIND_VARIABLE, "te4", "te4"); // Added te4.
code_edit->update_code_completion_options();
CHECK_MESSAGE(code_edit->get_code_completion_selected_index() == 0, "Adding later options shouldn't update selection.");

code_edit->set_code_completion_selected_index(2);
code_edit->add_code_completion_option(CodeEdit::CodeCompletionKind::KIND_VARIABLE, "te1", "te1");
code_edit->add_code_completion_option(CodeEdit::CodeCompletionKind::KIND_VARIABLE, "te3", "te3");
code_edit->add_code_completion_option(CodeEdit::CodeCompletionKind::KIND_VARIABLE, "te4", "te4");
code_edit->add_code_completion_option(CodeEdit::CodeCompletionKind::KIND_VARIABLE, "te5", "te5"); // Added te5.
code_edit->add_code_completion_option(CodeEdit::CodeCompletionKind::KIND_VARIABLE, "te6", "te6"); // Added te6.
code_edit->update_code_completion_options();
CHECK_MESSAGE(code_edit->get_code_completion_selected_index() == 2, "Adding later options shouldn't update selection.");

// Removing elements after selected element shouldn't update selection.
code_edit->add_code_completion_option(CodeEdit::CodeCompletionKind::KIND_VARIABLE, "te1", "te1");
code_edit->add_code_completion_option(CodeEdit::CodeCompletionKind::KIND_VARIABLE, "te3", "te3");
code_edit->add_code_completion_option(CodeEdit::CodeCompletionKind::KIND_VARIABLE, "te4", "te4");
code_edit->add_code_completion_option(CodeEdit::CodeCompletionKind::KIND_VARIABLE, "te5", "te5"); // Removed te6.
code_edit->update_code_completion_options();
CHECK_MESSAGE(code_edit->get_code_completion_selected_index() == 2, "Removing elements after selected element shouldn't update selection.");

// Changing elements after selected element shouldn't update selection.
code_edit->add_code_completion_option(CodeEdit::CodeCompletionKind::KIND_VARIABLE, "te1", "te1");
code_edit->add_code_completion_option(CodeEdit::CodeCompletionKind::KIND_VARIABLE, "te3", "te3");
code_edit->add_code_completion_option(CodeEdit::CodeCompletionKind::KIND_VARIABLE, "te4", "te4");
code_edit->add_code_completion_option(CodeEdit::CodeCompletionKind::KIND_VARIABLE, "te6", "te6"); // Changed te5->te6.
code_edit->update_code_completion_options();
CHECK_MESSAGE(code_edit->get_code_completion_selected_index() == 2, "Changing elements after selected element shouldn't update selection.");

// Changing elements before selected element should reset selection.
code_edit->add_code_completion_option(CodeEdit::CodeCompletionKind::KIND_VARIABLE, "te2", "te2"); // Changed te1->te2.
code_edit->add_code_completion_option(CodeEdit::CodeCompletionKind::KIND_VARIABLE, "te3", "te3");
code_edit->add_code_completion_option(CodeEdit::CodeCompletionKind::KIND_VARIABLE, "te4", "te4");
code_edit->add_code_completion_option(CodeEdit::CodeCompletionKind::KIND_VARIABLE, "te6", "te6");
code_edit->update_code_completion_options();
CHECK_MESSAGE(code_edit->get_code_completion_selected_index() == 0, "Changing elements before selected element should reset selection.");

// Removing elements before selected element should reset selection.
code_edit->set_code_completion_selected_index(2);
code_edit->add_code_completion_option(CodeEdit::CodeCompletionKind::KIND_VARIABLE, "te3", "te3"); // Removed te2.
code_edit->add_code_completion_option(CodeEdit::CodeCompletionKind::KIND_VARIABLE, "te4", "te4");
code_edit->add_code_completion_option(CodeEdit::CodeCompletionKind::KIND_VARIABLE, "te6", "te6");
code_edit->update_code_completion_options();
CHECK_MESSAGE(code_edit->get_code_completion_selected_index() == 0, "Removing elements before selected element should reset selection.");
}

memdelete(code_edit);
}

Expand Down

0 comments on commit b11309d

Please sign in to comment.