Skip to content

Commit

Permalink
Fix crash on Ctrl+X with multiple carets in TextEdit
Browse files Browse the repository at this point in the history
  • Loading branch information
Jordyfel committed Nov 15, 2023
1 parent 4c96e96 commit 4cb66fb
Showing 1 changed file with 63 additions and 16 deletions.
79 changes: 63 additions & 16 deletions scene/gui/text_edit.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6668,6 +6668,7 @@ void TextEdit::_cut_internal(int p_caret) {

begin_complex_operation();
Vector<int> carets_to_remove;
int lines_to_subtract = 0;

StringBuilder clipboard;
// This is the exception and has to edit in reverse order else the string copied to the clipboard will be backwards.
Expand All @@ -6679,9 +6680,6 @@ void TextEdit::_cut_internal(int p_caret) {
}

int cl = get_caret_line(caret_idx);
int cc = get_caret_column(caret_idx);
int indent_level = get_indent_level(cl);
double hscroll = get_h_scroll();

// Check for overlapping carets.
// We don't need to worry about selections as that is caught before this entire section.
Expand All @@ -6692,34 +6690,83 @@ void TextEdit::_cut_internal(int p_caret) {
}
}

// Compensate for lines removed in previous iterations.
set_caret_line(cl - lines_to_subtract, false, false, false, caret_idx);
cl = get_caret_line(caret_idx);

// Store tab indentation in column number, so the visually perceived column can be restored later.
int true_caret_column = get_caret_column(caret_idx);
int line_length = text[cl].size();
for (int i = 0; i < line_length - 1; i++) {
if (text[cl][i] == '\t') {
true_caret_column += text.get_tab_size() - 1;
} else {
break;
}
}
set_caret_column(true_caret_column, caret_idx == 0, caret_idx);

clipboard += text[cl];
if (p_caret == -1 && caret_idx != 0) {
if (p_caret == -1 && i != 0) {
clipboard += "\n";
}

if (cl == 0 && get_line_count() > 1) {
_remove_text(cl, 0, cl + 1, 0);
adjust_carets_after_edit(caret_idx, cl, 0, cl + 1, text[cl].length());
} else {
_remove_text(cl, 0, cl, text[cl].length());
set_caret_column(0, false, caret_idx);
backspace(caret_idx);
set_caret_line(get_caret_line(caret_idx) + 1, caret_idx == 0, 0, 0, caret_idx);
merge_gutters(cl - 1, cl);
_remove_text(cl - 1, text[cl - 1].length(), cl, text[cl].length());
lines_to_subtract += 1;
}
}

// 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]);
}

carets_to_remove.clear();
caret_edit_order = get_caret_index_edit_order();
for (int i = 0; i < caret_edit_order.size(); i++) {
int caret_idx = caret_edit_order[i];

// Clamp carets to last valid line.
int last_valid_line = text.size() - 1;
if (get_caret_line(caret_idx) > last_valid_line) {
set_caret_line(last_valid_line, caret_idx == 0, false, false, caret_idx);
}

// Leave only one caret per line.
if (i != caret_edit_order.size() - 1) {
if (get_caret_line(caret_idx) == get_caret_line(caret_edit_order[i + 1])) {
carets_to_remove.push_back(caret_idx);
continue;
}
}

// Correct the visually perceived caret column taking care of indentation level of the lines.
int diff_indent = indent_level - get_indent_level(get_caret_line(caret_idx));
cc += diff_indent;
if (diff_indent != 0) {
cc += diff_indent > 0 ? -1 : 1;
int cc = get_caret_column(caret_idx);
int cl = get_caret_line(caret_idx);
int line_length = text[cl].size();
for (int j = 0; j < line_length - 1; j++) {
if (text[cl][j] == '\t') {
cc -= text.get_tab_size() - 1;
} else {
break;
}
}

// Restore horizontal scroll and caret column modified by the backspace() call.
set_h_scroll(hscroll);
set_caret_column(cc, caret_idx == 0, caret_idx);
// Restore caret column.
if (cc > line_length) {
set_caret_column(line_length, caret_idx == 0, caret_idx);
} else {
set_caret_column(cc, caret_idx == 0, caret_idx);
}
}

// Sort and remove backwards to preserve indexes.
// 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]);
Expand Down

0 comments on commit 4cb66fb

Please sign in to comment.