diff options
Diffstat (limited to 'scene/gui/code_edit.cpp')
-rw-r--r-- | scene/gui/code_edit.cpp | 236 |
1 files changed, 211 insertions, 25 deletions
diff --git a/scene/gui/code_edit.cpp b/scene/gui/code_edit.cpp index 6a5fdc3360..f74d7fb906 100644 --- a/scene/gui/code_edit.cpp +++ b/scene/gui/code_edit.cpp @@ -1523,7 +1523,19 @@ void CodeEdit::_fold_gutter_draw_callback(int p_line, int p_gutter, Rect2 p_regi p_region.position += Point2(horizontal_padding, vertical_padding); p_region.size -= Point2(horizontal_padding, vertical_padding) * 2; - if (can_fold_line(p_line)) { + bool can_fold = can_fold_line(p_line); + + if (is_line_code_region_start(p_line)) { + Color region_icon_color = theme_cache.folded_code_region_color; + region_icon_color.a = MAX(region_icon_color.a, 0.4f); + if (can_fold) { + theme_cache.can_fold_code_region_icon->draw_rect(get_canvas_item(), p_region, false, region_icon_color); + } else { + theme_cache.folded_code_region_icon->draw_rect(get_canvas_item(), p_region, false, region_icon_color); + } + return; + } + if (can_fold) { theme_cache.can_fold_icon->draw_rect(get_canvas_item(), p_region, false, theme_cache.code_folding_color); return; } @@ -1554,6 +1566,27 @@ bool CodeEdit::can_fold_line(int p_line) const { return false; } + // Check for code region. + if (is_line_code_region_end(p_line)) { + return false; + } + if (is_line_code_region_start(p_line)) { + int region_level = 0; + // Check if there is a valid end region tag. + for (int next_line = p_line + 1; next_line < get_line_count(); next_line++) { + if (is_line_code_region_end(next_line)) { + region_level -= 1; + if (region_level == -1) { + return true; + } + } + if (is_line_code_region_start(next_line)) { + region_level += 1; + } + } + return false; + } + /* Check for full multiline line or block strings / comments. */ int in_comment = is_in_comment(p_line); int in_string = (in_comment == -1) ? is_in_string(p_line) : -1; @@ -1562,13 +1595,13 @@ bool CodeEdit::can_fold_line(int p_line) const { return false; } - int delimter_end_line = get_delimiter_end_position(p_line, get_line(p_line).size() - 1).y; + int delimiter_end_line = get_delimiter_end_position(p_line, get_line(p_line).size() - 1).y; /* No end line, therefore we have a multiline region over the rest of the file. */ - if (delimter_end_line == -1) { + if (delimiter_end_line == -1) { return true; } /* End line is the same therefore we have a block. */ - if (delimter_end_line == p_line) { + if (delimiter_end_line == p_line) { /* Check we are the start of the block. */ if (p_line - 1 >= 0) { if ((in_string != -1 && is_in_string(p_line - 1) != -1) || (in_comment != -1 && is_in_comment(p_line - 1) != -1)) { @@ -1578,7 +1611,7 @@ bool CodeEdit::can_fold_line(int p_line) const { /* Check it continues for at least one line. */ return ((in_string != -1 && is_in_string(p_line + 1) != -1) || (in_comment != -1 && is_in_comment(p_line + 1) != -1)); } - return ((in_string != -1 && is_in_string(delimter_end_line) != -1) || (in_comment != -1 && is_in_comment(delimter_end_line) != -1)); + return ((in_string != -1 && is_in_string(delimiter_end_line) != -1) || (in_comment != -1 && is_in_comment(delimiter_end_line) != -1)); } /* Otherwise check indent levels. */ @@ -1602,31 +1635,51 @@ void CodeEdit::fold_line(int p_line) { const int line_count = get_line_count() - 1; int end_line = line_count; - int in_comment = is_in_comment(p_line); - int in_string = (in_comment == -1) ? is_in_string(p_line) : -1; - if (in_string != -1 || in_comment != -1) { - end_line = get_delimiter_end_position(p_line, get_line(p_line).size() - 1).y; - /* End line is the same therefore we have a block of single line delimiters. */ - if (end_line == p_line) { - for (int i = p_line + 1; i <= line_count; i++) { - if ((in_string != -1 && is_in_string(i) == -1) || (in_comment != -1 && is_in_comment(i) == -1)) { + // Fold code region. + if (is_line_code_region_start(p_line)) { + int region_level = 0; + for (int endregion_line = p_line + 1; endregion_line < get_line_count(); endregion_line++) { + if (is_line_code_region_start(endregion_line)) { + region_level += 1; + } + if (is_line_code_region_end(endregion_line)) { + region_level -= 1; + if (region_level == -1) { + end_line = endregion_line; break; } - end_line = i; } } - } else { - int start_indent = get_indent_level(p_line); - for (int i = p_line + 1; i <= line_count; i++) { - if (get_line(i).strip_edges().size() == 0) { - continue; - } - if (get_indent_level(i) > start_indent) { - end_line = i; - continue; + set_line_background_color(p_line, theme_cache.folded_code_region_color); + } + + int in_comment = is_in_comment(p_line); + int in_string = (in_comment == -1) ? is_in_string(p_line) : -1; + if (!is_line_code_region_start(p_line)) { + if (in_string != -1 || in_comment != -1) { + end_line = get_delimiter_end_position(p_line, get_line(p_line).size() - 1).y; + // End line is the same therefore we have a block of single line delimiters. + if (end_line == p_line) { + for (int i = p_line + 1; i <= line_count; i++) { + if ((in_string != -1 && is_in_string(i) == -1) || (in_comment != -1 && is_in_comment(i) == -1)) { + break; + } + end_line = i; + } } - if (is_in_string(i) == -1 && is_in_comment(i) == -1) { - break; + } else { + int start_indent = get_indent_level(p_line); + for (int i = p_line + 1; i <= line_count; i++) { + if (get_line(i).strip_edges().size() == 0) { + continue; + } + if (get_indent_level(i) > start_indent) { + end_line = i; + continue; + } + if (is_in_string(i) == -1 && is_in_comment(i) == -1) { + break; + } } } } @@ -1677,6 +1730,9 @@ void CodeEdit::unfold_line(int p_line) { break; } _set_line_as_hidden(i, false); + if (is_line_code_region_start(i - 1)) { + set_line_background_color(i - 1, Color(0.0, 0.0, 0.0, 0.0)); + } } queue_redraw(); } @@ -1716,6 +1772,95 @@ TypedArray<int> CodeEdit::get_folded_lines() const { return folded_lines; } +/* Code region */ +void CodeEdit::create_code_region() { + // Abort if there is no selected text. + if (!has_selection()) { + return; + } + // Check that region tag find a comment delimiter and is valid. + if (code_region_start_string.is_empty()) { + WARN_PRINT_ONCE("Cannot create code region without any one line comment delimiters"); + return; + } + begin_complex_operation(); + // Merge selections if selection starts on the same line the previous one ends. + Vector<int> caret_edit_order = get_caret_index_edit_order(); + Vector<int> carets_to_remove; + for (int i = 1; i < caret_edit_order.size(); i++) { + int current_caret = caret_edit_order[i - 1]; + int next_caret = caret_edit_order[i]; + if (get_selection_from_line(current_caret) == get_selection_to_line(next_caret)) { + select(get_selection_from_line(next_caret), get_selection_from_column(next_caret), get_selection_to_line(current_caret), get_selection_to_column(current_caret), next_caret); + carets_to_remove.append(current_caret); + } + } + // Sort and remove backwards to preserve indices. + carets_to_remove.sort(); + for (int i = carets_to_remove.size() - 1; i >= 0; i--) { + remove_caret(carets_to_remove[i]); + } + + // Adding start and end region tags. + int first_region_start = -1; + for (int caret_idx : get_caret_index_edit_order()) { + if (!has_selection(caret_idx)) { + continue; + } + int from_line = get_selection_from_line(caret_idx); + if (first_region_start == -1 || from_line < first_region_start) { + first_region_start = from_line; + } + int to_line = get_selection_to_line(caret_idx); + set_line(to_line, get_line(to_line) + "\n" + code_region_end_string); + insert_line_at(from_line, code_region_start_string + " " + RTR("New Code Region")); + fold_line(from_line); + } + + // Select name of the first region to allow quick edit. + remove_secondary_carets(); + set_caret_line(first_region_start); + int tag_length = code_region_start_string.length() + RTR("New Code Region").length() + 1; + set_caret_column(tag_length); + select(first_region_start, code_region_start_string.length() + 1, first_region_start, tag_length); + + end_complex_operation(); + queue_redraw(); +} + +String CodeEdit::get_code_region_start_tag() const { + return code_region_start_tag; +} + +String CodeEdit::get_code_region_end_tag() const { + return code_region_end_tag; +} + +void CodeEdit::set_code_region_tags(const String &p_start, const String &p_end) { + ERR_FAIL_COND_MSG(p_start == p_end, "Starting and ending region tags cannot be identical."); + ERR_FAIL_COND_MSG(p_start.is_empty(), "Starting region tag cannot be empty."); + ERR_FAIL_COND_MSG(p_end.is_empty(), "Ending region tag cannot be empty."); + code_region_start_tag = p_start; + code_region_end_tag = p_end; + _update_code_region_tags(); +} + +bool CodeEdit::is_line_code_region_start(int p_line) const { + ERR_FAIL_INDEX_V(p_line, get_line_count(), false); + if (code_region_start_string.is_empty()) { + return false; + } + return get_line(p_line).strip_edges().begins_with(code_region_start_string); +} + +bool CodeEdit::is_line_code_region_end(int p_line) const { + ERR_FAIL_INDEX_V(p_line, get_line_count(), false); + if (code_region_start_string.is_empty()) { + return false; + } + return get_line(p_line).strip_edges().begins_with(code_region_end_string); +} + /* Delimiters */ // Strings void CodeEdit::add_string_delimiter(const String &p_start_key, const String &p_end_key, bool p_line_only) { @@ -2344,6 +2489,14 @@ void CodeEdit::_bind_methods() { ClassDB::bind_method(D_METHOD("is_line_folded", "line"), &CodeEdit::is_line_folded); ClassDB::bind_method(D_METHOD("get_folded_lines"), &CodeEdit::get_folded_lines); + /* Code region */ + ClassDB::bind_method(D_METHOD("create_code_region"), &CodeEdit::create_code_region); + ClassDB::bind_method(D_METHOD("get_code_region_start_tag"), &CodeEdit::get_code_region_start_tag); + ClassDB::bind_method(D_METHOD("get_code_region_end_tag"), &CodeEdit::get_code_region_end_tag); + ClassDB::bind_method(D_METHOD("set_code_region_tags", "start", "end"), &CodeEdit::set_code_region_tags, DEFVAL("region"), DEFVAL("endregion")); + ClassDB::bind_method(D_METHOD("is_line_code_region_start", "line"), &CodeEdit::is_line_code_region_start); + ClassDB::bind_method(D_METHOD("is_line_code_region_end", "line"), &CodeEdit::is_line_code_region_end); + /* Delimiters */ // Strings ClassDB::bind_method(D_METHOD("add_string_delimiter", "start_key", "end_key", "line_only"), &CodeEdit::add_string_delimiter, DEFVAL(false)); @@ -2483,8 +2636,11 @@ void CodeEdit::_bind_methods() { /* Theme items */ /* Gutters */ BIND_THEME_ITEM(Theme::DATA_TYPE_COLOR, CodeEdit, code_folding_color); + BIND_THEME_ITEM(Theme::DATA_TYPE_COLOR, CodeEdit, folded_code_region_color); BIND_THEME_ITEM_CUSTOM(Theme::DATA_TYPE_ICON, CodeEdit, can_fold_icon, "can_fold"); BIND_THEME_ITEM_CUSTOM(Theme::DATA_TYPE_ICON, CodeEdit, folded_icon, "folded"); + BIND_THEME_ITEM_CUSTOM(Theme::DATA_TYPE_ICON, CodeEdit, can_fold_code_region_icon, "can_fold_code_region"); + BIND_THEME_ITEM_CUSTOM(Theme::DATA_TYPE_ICON, CodeEdit, folded_code_region_icon, "folded_code_region"); BIND_THEME_ITEM(Theme::DATA_TYPE_ICON, CodeEdit, folded_eol_icon); BIND_THEME_ITEM(Theme::DATA_TYPE_COLOR, CodeEdit, breakpoint_color); @@ -2628,6 +2784,27 @@ void CodeEdit::_update_gutter_indexes() { } } +/* Code Region */ +void CodeEdit::_update_code_region_tags() { + code_region_start_string = ""; + code_region_end_string = ""; + + if (code_region_start_tag.is_empty() || code_region_end_tag.is_empty()) { + return; + } + + for (int i = 0; i < delimiters.size(); i++) { + if (delimiters[i].type != DelimiterType::TYPE_COMMENT) { + continue; + } + if (delimiters[i].end_key.is_empty() && delimiters[i].line_only == true) { + code_region_start_string = delimiters[i].start_key + code_region_start_tag; + code_region_end_string = delimiters[i].start_key + code_region_end_tag; + return; + } + } +} + /* Delimiters */ void CodeEdit::_update_delimiter_cache(int p_from_line, int p_to_line) { if (delimiters.size() == 0) { @@ -2871,6 +3048,9 @@ void CodeEdit::_add_delimiter(const String &p_start_key, const String &p_end_key delimiter_cache.clear(); _update_delimiter_cache(); } + if (p_type == DelimiterType::TYPE_COMMENT) { + _update_code_region_tags(); + } } void CodeEdit::_remove_delimiter(const String &p_start_key, DelimiterType p_type) { @@ -2888,6 +3068,9 @@ void CodeEdit::_remove_delimiter(const String &p_start_key, DelimiterType p_type delimiter_cache.clear(); _update_delimiter_cache(); } + if (p_type == DelimiterType::TYPE_COMMENT) { + _update_code_region_tags(); + } break; } } @@ -2931,6 +3114,9 @@ void CodeEdit::_clear_delimiters(DelimiterType p_type) { if (!setting_delimiters) { _update_delimiter_cache(); } + if (p_type == DelimiterType::TYPE_COMMENT) { + _update_code_region_tags(); + } } TypedArray<String> CodeEdit::_get_delimiters(DelimiterType p_type) const { |