Merge pull request #28811 from iwek7/editor_remove_spaces_to_closes_indention
Change rules of indenting for spaces
This commit is contained in:
commit
f173d242a2
2 changed files with 84 additions and 44 deletions
|
@ -104,6 +104,13 @@ static CharType _get_right_pair_symbol(CharType c) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int _find_first_non_whitespace_column_of_line(const String &line) {
|
||||
int left = 0;
|
||||
while (left < line.length() && _is_whitespace(line[left]))
|
||||
left++;
|
||||
return left;
|
||||
}
|
||||
|
||||
void TextEdit::Text::set_font(const Ref<Font> &p_font) {
|
||||
|
||||
font = p_font;
|
||||
|
@ -1645,31 +1652,25 @@ void TextEdit::backspace_at_cursor() {
|
|||
_consume_backspace_for_pair_symbol(prev_line, prev_column);
|
||||
} else {
|
||||
// handle space indentation
|
||||
if (cursor.column - indent_size >= 0 && indent_using_spaces) {
|
||||
|
||||
// if there is enough spaces to count as a tab
|
||||
if (cursor.column != 0 && indent_using_spaces) {
|
||||
// check if there are no other chars before cursor, just indentation
|
||||
bool unindent = true;
|
||||
for (int i = 1; i <= indent_size; i++) {
|
||||
if (text[cursor.line][cursor.column - i] != ' ') {
|
||||
unindent = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// and it is before the first character
|
||||
int i = 0;
|
||||
while (i < cursor.column && i < text[cursor.line].length()) {
|
||||
if (text[cursor.line][i] != ' ' && text[cursor.line][i] != '\t') {
|
||||
if (!_is_whitespace(text[cursor.line][i])) {
|
||||
unindent = false;
|
||||
break;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
|
||||
// then we can remove it as a single character.
|
||||
// then we can remove all spaces as a single character.
|
||||
if (unindent) {
|
||||
_remove_text(cursor.line, cursor.column - indent_size, cursor.line, cursor.column);
|
||||
prev_column = cursor.column - indent_size;
|
||||
// we want to remove spaces up to closest indent
|
||||
// or whole indent if cursor is pointing at it
|
||||
int spaces_to_delete = _calculate_spaces_till_next_left_indent(cursor.column);
|
||||
prev_column = cursor.column - spaces_to_delete;
|
||||
_remove_text(cursor.line, prev_column, cursor.line, cursor.column);
|
||||
} else {
|
||||
_remove_text(prev_line, prev_column, cursor.line, cursor.column);
|
||||
}
|
||||
|
@ -1686,6 +1687,10 @@ void TextEdit::indent_right() {
|
|||
|
||||
int start_line;
|
||||
int end_line;
|
||||
|
||||
// this value informs us by how much we changed selection position by indenting right
|
||||
// default is 1 for tab indentation
|
||||
int selection_offset = 1;
|
||||
begin_complex_operation();
|
||||
|
||||
if (is_selection_active()) {
|
||||
|
@ -1704,18 +1709,24 @@ void TextEdit::indent_right() {
|
|||
for (int i = start_line; i <= end_line; i++) {
|
||||
String line_text = get_line(i);
|
||||
if (indent_using_spaces) {
|
||||
line_text = space_indent + line_text;
|
||||
// we don't really care where selection is - we just need to know indentation level at the beginning of the line
|
||||
int left = _find_first_non_whitespace_column_of_line(line_text);
|
||||
int spaces_to_add = _calculate_spaces_till_next_right_indent(left);
|
||||
// since we will add this much spaces we want move whole selection and cursor by this much
|
||||
selection_offset = spaces_to_add;
|
||||
for (int j = 0; j < spaces_to_add; j++)
|
||||
line_text = ' ' + line_text;
|
||||
} else {
|
||||
line_text = '\t' + line_text;
|
||||
}
|
||||
set_line(i, line_text);
|
||||
}
|
||||
|
||||
// fix selection and cursor being off by one on the last line
|
||||
// fix selection and cursor being off after shifting selection right
|
||||
if (is_selection_active()) {
|
||||
select(selection.from_line, selection.from_column + 1, selection.to_line, selection.to_column + 1);
|
||||
select(selection.from_line, selection.from_column + selection_offset, selection.to_line, selection.to_column + selection_offset);
|
||||
}
|
||||
cursor_set_column(cursor.column + 1, false);
|
||||
cursor_set_column(cursor.column + selection_offset, false);
|
||||
end_complex_operation();
|
||||
update();
|
||||
}
|
||||
|
@ -1724,6 +1735,15 @@ void TextEdit::indent_left() {
|
|||
|
||||
int start_line;
|
||||
int end_line;
|
||||
|
||||
// moving cursor and selection after unindenting can get tricky
|
||||
// because changing content of line can move cursor and selection on it's own (if new line ends before previous position of either)
|
||||
// therefore we just remember initial values
|
||||
// and at the end of the operation offset them by number of removed characters
|
||||
int removed_characters = 0;
|
||||
int initial_selection_end_column = selection.to_column;
|
||||
int initial_cursor_column = cursor.column;
|
||||
|
||||
begin_complex_operation();
|
||||
|
||||
if (is_selection_active()) {
|
||||
|
@ -1746,21 +1766,43 @@ void TextEdit::indent_left() {
|
|||
if (line_text.begins_with("\t")) {
|
||||
line_text = line_text.substr(1, line_text.length());
|
||||
set_line(i, line_text);
|
||||
} else if (line_text.begins_with(space_indent)) {
|
||||
line_text = line_text.substr(indent_size, line_text.length());
|
||||
removed_characters = 1;
|
||||
} else if (line_text.begins_with(" ")) {
|
||||
// when unindenting we aim to remove spaces before line that has selection no matter what is selected
|
||||
// so we start of by finding first non whitespace character of line
|
||||
int left = _find_first_non_whitespace_column_of_line(line_text);
|
||||
|
||||
// here we remove only enough spaces to align text to nearest full multiple of indentation_size
|
||||
// in case where selection begins at the start of indentation_size multiple we remove whole indentation level
|
||||
int spaces_to_remove = _calculate_spaces_till_next_left_indent(left);
|
||||
|
||||
line_text = line_text.substr(spaces_to_remove, line_text.length());
|
||||
set_line(i, line_text);
|
||||
removed_characters = spaces_to_remove;
|
||||
}
|
||||
}
|
||||
|
||||
// fix selection and cursor being off by one on the last line
|
||||
if (is_selection_active() && last_line_text != get_line(end_line)) {
|
||||
select(selection.from_line, selection.from_column - 1, selection.to_line, selection.to_column - 1);
|
||||
select(selection.from_line, selection.from_column - removed_characters,
|
||||
selection.to_line, initial_selection_end_column - removed_characters);
|
||||
}
|
||||
cursor_set_column(cursor.column - 1, false);
|
||||
cursor_set_column(initial_cursor_column - removed_characters, false);
|
||||
end_complex_operation();
|
||||
update();
|
||||
}
|
||||
|
||||
int TextEdit::_calculate_spaces_till_next_left_indent(int column) {
|
||||
int spaces_till_indent = column % indent_size;
|
||||
if (spaces_till_indent == 0)
|
||||
spaces_till_indent = indent_size;
|
||||
return spaces_till_indent;
|
||||
}
|
||||
|
||||
int TextEdit::_calculate_spaces_till_next_right_indent(int column) {
|
||||
return indent_size - column % indent_size;
|
||||
}
|
||||
|
||||
void TextEdit::_get_mouse_pos(const Point2i &p_mouse, int &r_row, int &r_col) const {
|
||||
|
||||
float rows = p_mouse.y;
|
||||
|
@ -2517,15 +2559,11 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) {
|
|||
} else {
|
||||
if (k->get_shift()) {
|
||||
|
||||
//simple unindent
|
||||
// simple unindent
|
||||
int cc = cursor.column;
|
||||
|
||||
const int len = text[cursor.line].length();
|
||||
const String &line = text[cursor.line];
|
||||
|
||||
int left = 0; // number of whitespace chars at beginning of line
|
||||
while (left < len && (line[left] == '\t' || line[left] == ' '))
|
||||
left++;
|
||||
int left = _find_first_non_whitespace_column_of_line(line);
|
||||
cc = MIN(cc, left);
|
||||
|
||||
while (cc < indent_size && cc < left && line[cc] == ' ')
|
||||
|
@ -2533,24 +2571,18 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) {
|
|||
|
||||
if (cc > 0 && cc <= text[cursor.line].length()) {
|
||||
if (text[cursor.line][cc - 1] == '\t') {
|
||||
// tabs unindentation
|
||||
_remove_text(cursor.line, cc - 1, cursor.line, cc);
|
||||
if (cursor.column >= left)
|
||||
cursor_set_column(MAX(0, cursor.column - 1));
|
||||
update();
|
||||
} else {
|
||||
int n = 0;
|
||||
|
||||
for (int i = 1; i <= MIN(cc, indent_size); i++) {
|
||||
if (line[cc - i] != ' ') {
|
||||
break;
|
||||
}
|
||||
n++;
|
||||
}
|
||||
|
||||
if (n > 0) {
|
||||
_remove_text(cursor.line, cc - n, cursor.line, cc);
|
||||
if (cursor.column > left - n) // inside text?
|
||||
cursor_set_column(MAX(0, cursor.column - n));
|
||||
// spaces unindentation
|
||||
int spaces_to_remove = _calculate_spaces_till_next_left_indent(cc);
|
||||
if (spaces_to_remove > 0) {
|
||||
_remove_text(cursor.line, cc - spaces_to_remove, cursor.line, cc);
|
||||
if (cursor.column > left - spaces_to_remove) // inside text?
|
||||
cursor_set_column(MAX(0, cursor.column - spaces_to_remove));
|
||||
update();
|
||||
}
|
||||
}
|
||||
|
@ -2559,9 +2591,14 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) {
|
|||
update();
|
||||
}
|
||||
} else {
|
||||
//simple indent
|
||||
// simple indent
|
||||
if (indent_using_spaces) {
|
||||
_insert_text_at_cursor(space_indent);
|
||||
// insert only as much spaces as needed till next indentation level
|
||||
int spaces_to_add = _calculate_spaces_till_next_right_indent(cursor.column);
|
||||
String indent_to_insert = String();
|
||||
for (int i = 0; i < spaces_to_add; i++)
|
||||
indent_to_insert = ' ' + indent_to_insert;
|
||||
_insert_text_at_cursor(indent_to_insert);
|
||||
} else {
|
||||
_insert_text_at_cursor("\t");
|
||||
}
|
||||
|
|
|
@ -437,6 +437,9 @@ private:
|
|||
void _confirm_completion();
|
||||
void _update_completion_candidates();
|
||||
|
||||
int _calculate_spaces_till_next_left_indent(int column);
|
||||
int _calculate_spaces_till_next_right_indent(int column);
|
||||
|
||||
protected:
|
||||
virtual String get_tooltip(const Point2 &p_pos) const;
|
||||
|
||||
|
|
Loading…
Reference in a new issue