Merge pull request #49665 from Paulb23/code_edit_indent
Move indentation into CodeEdit
This commit is contained in:
commit
9da7f06900
10 changed files with 762 additions and 477 deletions
|
@ -143,6 +143,20 @@
|
|||
Inserts the selected entry into the text. If [code]replace[/code] is true, any existing text is replaced rather then merged.
|
||||
</description>
|
||||
</method>
|
||||
<method name="do_indent">
|
||||
<return type="void">
|
||||
</return>
|
||||
<description>
|
||||
Perform an indent as if the user activated the "ui_text_indent" action.
|
||||
</description>
|
||||
</method>
|
||||
<method name="do_unindent">
|
||||
<return type="void">
|
||||
</return>
|
||||
<description>
|
||||
Perform an unindent as if the user activated the "ui_text_unindent" action.
|
||||
</description>
|
||||
</method>
|
||||
<method name="fold_all_lines">
|
||||
<return type="void">
|
||||
</return>
|
||||
|
@ -278,6 +292,13 @@
|
|||
Returns [code]true[/code] if string [code]start_key[/code] exists.
|
||||
</description>
|
||||
</method>
|
||||
<method name="indent_lines">
|
||||
<return type="void">
|
||||
</return>
|
||||
<description>
|
||||
Indents selected lines, or in the case of no selection the caret line by one.
|
||||
</description>
|
||||
</method>
|
||||
<method name="is_in_comment" qualifiers="const">
|
||||
<return type="int">
|
||||
</return>
|
||||
|
@ -441,6 +462,13 @@
|
|||
Unfolds all lines that were previously folded.
|
||||
</description>
|
||||
</method>
|
||||
<method name="unindent_lines">
|
||||
<return type="void">
|
||||
</return>
|
||||
<description>
|
||||
Unindents selected lines, or in the case of no selection the caret line by one.
|
||||
</description>
|
||||
</method>
|
||||
<method name="update_code_completion_options">
|
||||
<return type="void">
|
||||
</return>
|
||||
|
@ -475,6 +503,18 @@
|
|||
</member>
|
||||
<member name="draw_line_numbers" type="bool" setter="set_draw_line_numbers" getter="is_draw_line_numbers_enabled" default="false">
|
||||
</member>
|
||||
<member name="indent_automatic" type="bool" setter="set_auto_indent_enabled" getter="is_auto_indent_enabled" default="false">
|
||||
Sets whether automatic indent are enabled, this will add an extra indent if a prefix or brace is found.
|
||||
</member>
|
||||
<member name="indent_automatic_prefixes" type="String[]" setter="set_auto_indent_prefixes" getter="get_auto_indent_prefixes" default="["(", ":", "[", "{"]">
|
||||
Prefixes to trigger an automatic indent.
|
||||
</member>
|
||||
<member name="indent_size" type="int" setter="set_indent_size" getter="get_indent_size" default="4">
|
||||
Size of tabs, if [code]indent_use_spaces[/code] is enabled the amount of spaces to use.
|
||||
</member>
|
||||
<member name="indent_use_spaces" type="bool" setter="set_indent_using_spaces" getter="is_indent_using_spaces" default="false">
|
||||
Use spaces instead of tabs for indentation.
|
||||
</member>
|
||||
<member name="layout_direction" type="int" setter="set_layout_direction" getter="get_layout_direction" override="true" enum="Control.LayoutDirection" default="2" />
|
||||
<member name="line_folding" type="bool" setter="set_line_folding_enabled" getter="is_line_folding_enabled" default="true">
|
||||
Sets whether line folding is allowed.
|
||||
|
|
|
@ -10,6 +10,12 @@
|
|||
<tutorials>
|
||||
</tutorials>
|
||||
<methods>
|
||||
<method name="_backspace" qualifiers="virtual">
|
||||
<return type="void">
|
||||
</return>
|
||||
<description>
|
||||
</description>
|
||||
</method>
|
||||
<method name="add_gutter">
|
||||
<return type="void">
|
||||
</return>
|
||||
|
@ -18,6 +24,12 @@
|
|||
<description>
|
||||
</description>
|
||||
</method>
|
||||
<method name="backspace">
|
||||
<return type="void">
|
||||
</return>
|
||||
<description>
|
||||
</description>
|
||||
</method>
|
||||
<method name="center_viewport_to_cursor">
|
||||
<return type="void">
|
||||
</return>
|
||||
|
@ -96,6 +108,12 @@
|
|||
Cut's the current selection.
|
||||
</description>
|
||||
</method>
|
||||
<method name="delete_selection">
|
||||
<return type="void">
|
||||
</return>
|
||||
<description>
|
||||
</description>
|
||||
</method>
|
||||
<method name="deselect">
|
||||
<return type="void">
|
||||
</return>
|
||||
|
@ -110,6 +128,14 @@
|
|||
Gets the caret pixel draw poistion.
|
||||
</description>
|
||||
</method>
|
||||
<method name="get_first_non_whitespace_column" qualifiers="const">
|
||||
<return type="int">
|
||||
</return>
|
||||
<argument index="0" name="line" type="int">
|
||||
</argument>
|
||||
<description>
|
||||
</description>
|
||||
</method>
|
||||
<method name="get_gutter_count" qualifiers="const">
|
||||
<return type="int">
|
||||
</return>
|
||||
|
@ -140,6 +166,14 @@
|
|||
<description>
|
||||
</description>
|
||||
</method>
|
||||
<method name="get_indent_level" qualifiers="const">
|
||||
<return type="int">
|
||||
</return>
|
||||
<argument index="0" name="line" type="int">
|
||||
</argument>
|
||||
<description>
|
||||
</description>
|
||||
</method>
|
||||
<method name="get_line" qualifiers="const">
|
||||
<return type="String">
|
||||
</return>
|
||||
|
@ -274,6 +308,12 @@
|
|||
Returns the selection end line.
|
||||
</description>
|
||||
</method>
|
||||
<method name="get_tab_size" qualifiers="const">
|
||||
<return type="int">
|
||||
</return>
|
||||
<description>
|
||||
</description>
|
||||
</method>
|
||||
<method name="get_visible_line_count" qualifiers="const">
|
||||
<return type="int">
|
||||
</return>
|
||||
|
@ -354,6 +394,16 @@
|
|||
Triggers a right-click menu action by the specified index. See [enum MenuItems] for a list of available indexes.
|
||||
</description>
|
||||
</method>
|
||||
<method name="merge_gutters">
|
||||
<return type="void">
|
||||
</return>
|
||||
<argument index="0" name="from_line" type="int">
|
||||
</argument>
|
||||
<argument index="1" name="to_line" type="int">
|
||||
</argument>
|
||||
<description>
|
||||
</description>
|
||||
</method>
|
||||
<method name="paste">
|
||||
<return type="void">
|
||||
</return>
|
||||
|
@ -611,6 +661,14 @@
|
|||
<description>
|
||||
</description>
|
||||
</method>
|
||||
<method name="set_tab_size">
|
||||
<return type="void">
|
||||
</return>
|
||||
<argument index="0" name="size" type="int">
|
||||
</argument>
|
||||
<description>
|
||||
</description>
|
||||
</method>
|
||||
<method name="undo">
|
||||
<return type="void">
|
||||
</return>
|
||||
|
|
|
@ -930,7 +930,7 @@ void CodeTextEditor::update_editor_settings() {
|
|||
text_editor->set_highlight_current_line(EditorSettings::get_singleton()->get("text_editor/highlighting/highlight_current_line"));
|
||||
text_editor->set_indent_using_spaces(EditorSettings::get_singleton()->get("text_editor/indent/type"));
|
||||
text_editor->set_indent_size(EditorSettings::get_singleton()->get("text_editor/indent/size"));
|
||||
text_editor->set_auto_indent(EditorSettings::get_singleton()->get("text_editor/indent/auto_indent"));
|
||||
text_editor->set_auto_indent_enabled(EditorSettings::get_singleton()->get("text_editor/indent/auto_indent"));
|
||||
text_editor->set_draw_tabs(EditorSettings::get_singleton()->get("text_editor/indent/draw_tabs"));
|
||||
text_editor->set_draw_spaces(EditorSettings::get_singleton()->get("text_editor/indent/draw_spaces"));
|
||||
text_editor->set_smooth_scroll_enabled(EditorSettings::get_singleton()->get("text_editor/navigation/smooth_scrolling"));
|
||||
|
@ -1255,7 +1255,7 @@ void CodeTextEditor::_delete_line(int p_line) {
|
|||
text_editor->cursor_set_line(1);
|
||||
text_editor->cursor_set_column(0);
|
||||
}
|
||||
text_editor->backspace_at_cursor();
|
||||
text_editor->backspace();
|
||||
text_editor->unfold_line(p_line);
|
||||
text_editor->cursor_set_line(p_line);
|
||||
}
|
||||
|
@ -1809,7 +1809,7 @@ CodeTextEditor::CodeTextEditor() {
|
|||
|
||||
text_editor->set_draw_line_numbers(true);
|
||||
text_editor->set_brace_matching(true);
|
||||
text_editor->set_auto_indent(true);
|
||||
text_editor->set_auto_indent_enabled(true);
|
||||
|
||||
status_bar = memnew(HBoxContainer);
|
||||
add_child(status_bar);
|
||||
|
|
|
@ -524,7 +524,7 @@ void ScriptTextEditor::_validate_script() {
|
|||
if (safe_lines.has(i + 1)) {
|
||||
te->set_line_gutter_item_color(i, line_number_gutter, safe_line_number_color);
|
||||
last_is_safe = true;
|
||||
} else if (last_is_safe && (te->is_line_comment(i) || te->get_line(i).strip_edges().is_empty())) {
|
||||
} else if (last_is_safe && (te->is_in_comment(i) != -1 || te->get_line(i).strip_edges().is_empty())) {
|
||||
te->set_line_gutter_item_color(i, line_number_gutter, safe_line_number_color);
|
||||
} else {
|
||||
te->set_line_gutter_item_color(i, line_number_gutter, default_line_number_color);
|
||||
|
@ -1038,7 +1038,7 @@ void ScriptTextEditor::_edit_option(int p_op) {
|
|||
return;
|
||||
}
|
||||
|
||||
tx->indent_selected_lines_left();
|
||||
tx->unindent_lines();
|
||||
} break;
|
||||
case EDIT_INDENT_RIGHT: {
|
||||
Ref<Script> scr = script;
|
||||
|
@ -1046,7 +1046,7 @@ void ScriptTextEditor::_edit_option(int p_op) {
|
|||
return;
|
||||
}
|
||||
|
||||
tx->indent_selected_lines_right();
|
||||
tx->indent_lines();
|
||||
} break;
|
||||
case EDIT_DELETE_LINE: {
|
||||
code_editor->delete_lines();
|
||||
|
|
|
@ -323,19 +323,13 @@ void ShaderEditor::_menu_option(int p_option) {
|
|||
if (shader.is_null()) {
|
||||
return;
|
||||
}
|
||||
|
||||
CodeEdit *tx = shader_editor->get_text_editor();
|
||||
tx->indent_selected_lines_left();
|
||||
|
||||
shader_editor->get_text_editor()->unindent_lines();
|
||||
} break;
|
||||
case EDIT_INDENT_RIGHT: {
|
||||
if (shader.is_null()) {
|
||||
return;
|
||||
}
|
||||
|
||||
CodeEdit *tx = shader_editor->get_text_editor();
|
||||
tx->indent_selected_lines_right();
|
||||
|
||||
shader_editor->get_text_editor()->indent_lines();
|
||||
} break;
|
||||
case EDIT_DELETE_LINE: {
|
||||
shader_editor->delete_lines();
|
||||
|
|
|
@ -320,10 +320,10 @@ void TextEditor::_edit_option(int p_op) {
|
|||
code_editor->move_lines_down();
|
||||
} break;
|
||||
case EDIT_INDENT_LEFT: {
|
||||
tx->indent_selected_lines_left();
|
||||
tx->unindent_lines();
|
||||
} break;
|
||||
case EDIT_INDENT_RIGHT: {
|
||||
tx->indent_selected_lines_right();
|
||||
tx->indent_lines();
|
||||
} break;
|
||||
case EDIT_DELETE_LINE: {
|
||||
code_editor->delete_lines();
|
||||
|
|
|
@ -360,7 +360,7 @@ void CodeEdit::_gui_input(const Ref<InputEvent> &p_gui_input) {
|
|||
return;
|
||||
}
|
||||
if (k->is_action("ui_text_backspace", true)) {
|
||||
backspace_at_cursor();
|
||||
backspace();
|
||||
_filter_code_completion_candidates();
|
||||
accept_event();
|
||||
return;
|
||||
|
@ -387,14 +387,34 @@ void CodeEdit::_gui_input(const Ref<InputEvent> &p_gui_input) {
|
|||
set_code_hint("");
|
||||
}
|
||||
|
||||
/* Override input to unfold lines where needed. */
|
||||
if (!is_readonly()) {
|
||||
if (k->is_action("ui_text_newline_above", true) || k->is_action("ui_text_newline_blank", true) || k->is_action("ui_text_newline", true)) {
|
||||
unfold_line(cursor_get_line());
|
||||
}
|
||||
if (cursor_get_line() > 0 && k->is_action("ui_text_backspace", true)) {
|
||||
unfold_line(cursor_get_line() - 1);
|
||||
}
|
||||
/* Indentation */
|
||||
if (k->is_action("ui_text_indent", true)) {
|
||||
do_indent();
|
||||
accept_event();
|
||||
return;
|
||||
}
|
||||
|
||||
if (k->is_action("ui_text_dedent", true)) {
|
||||
do_unindent();
|
||||
accept_event();
|
||||
return;
|
||||
}
|
||||
|
||||
// Override new line actions, for auto indent
|
||||
if (k->is_action("ui_text_newline_above", true)) {
|
||||
_new_line(false, true);
|
||||
accept_event();
|
||||
return;
|
||||
}
|
||||
if (k->is_action("ui_text_newline_blank", true)) {
|
||||
_new_line(false);
|
||||
accept_event();
|
||||
return;
|
||||
}
|
||||
if (k->is_action("ui_text_newline", true)) {
|
||||
_new_line();
|
||||
accept_event();
|
||||
return;
|
||||
}
|
||||
|
||||
/* Remove shift otherwise actions will not match. */
|
||||
|
@ -439,6 +459,443 @@ Control::CursorShape CodeEdit::get_cursor_shape(const Point2 &p_pos) const {
|
|||
return TextEdit::get_cursor_shape(p_pos);
|
||||
}
|
||||
|
||||
/* Indent management */
|
||||
void CodeEdit::set_indent_size(const int p_size) {
|
||||
ERR_FAIL_COND_MSG(p_size <= 0, "Indend size must be greater than 0.");
|
||||
if (indent_size == p_size) {
|
||||
return;
|
||||
}
|
||||
|
||||
indent_size = p_size;
|
||||
if (indent_using_spaces) {
|
||||
indent_text = String(" ").repeat(p_size);
|
||||
} else {
|
||||
indent_text = "\t";
|
||||
}
|
||||
set_tab_size(p_size);
|
||||
}
|
||||
|
||||
int CodeEdit::get_indent_size() const {
|
||||
return indent_size;
|
||||
}
|
||||
|
||||
void CodeEdit::set_indent_using_spaces(const bool p_use_spaces) {
|
||||
indent_using_spaces = p_use_spaces;
|
||||
if (indent_using_spaces) {
|
||||
indent_text = String(" ").repeat(indent_size);
|
||||
} else {
|
||||
indent_text = "\t";
|
||||
}
|
||||
}
|
||||
|
||||
bool CodeEdit::is_indent_using_spaces() const {
|
||||
return indent_using_spaces;
|
||||
}
|
||||
|
||||
void CodeEdit::set_auto_indent_enabled(bool p_enabled) {
|
||||
auto_indent = p_enabled;
|
||||
}
|
||||
|
||||
bool CodeEdit::is_auto_indent_enabled() const {
|
||||
return auto_indent;
|
||||
}
|
||||
|
||||
void CodeEdit::set_auto_indent_prefixes(const TypedArray<String> &p_prefixes) {
|
||||
auto_indent_prefixes.clear();
|
||||
for (int i = 0; i < p_prefixes.size(); i++) {
|
||||
const String prefix = p_prefixes[i];
|
||||
auto_indent_prefixes.insert(prefix[0]);
|
||||
}
|
||||
}
|
||||
|
||||
TypedArray<String> CodeEdit::get_auto_indent_prefixes() const {
|
||||
TypedArray<String> prefixes;
|
||||
for (const Set<char32_t>::Element *E = auto_indent_prefixes.front(); E; E = E->next()) {
|
||||
prefixes.push_back(String::chr(E->get()));
|
||||
}
|
||||
return prefixes;
|
||||
}
|
||||
|
||||
void CodeEdit::do_indent() {
|
||||
if (is_readonly()) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (is_selection_active()) {
|
||||
indent_lines();
|
||||
return;
|
||||
}
|
||||
|
||||
if (!indent_using_spaces) {
|
||||
_insert_text_at_cursor("\t");
|
||||
return;
|
||||
}
|
||||
|
||||
int spaces_to_add = _calculate_spaces_till_next_right_indent(cursor_get_column());
|
||||
if (spaces_to_add > 0) {
|
||||
_insert_text_at_cursor(String(" ").repeat(spaces_to_add));
|
||||
}
|
||||
}
|
||||
|
||||
void CodeEdit::indent_lines() {
|
||||
if (is_readonly()) {
|
||||
return;
|
||||
}
|
||||
|
||||
begin_complex_operation();
|
||||
|
||||
/* This value informs us by how much we changed selection position by indenting right. */
|
||||
/* Default is 1 for tab indentation. */
|
||||
int selection_offset = 1;
|
||||
|
||||
int start_line = cursor_get_line();
|
||||
int end_line = start_line;
|
||||
if (is_selection_active()) {
|
||||
start_line = get_selection_from_line();
|
||||
end_line = get_selection_to_line();
|
||||
|
||||
/* Ignore the last line if the selection is not past the first column. */
|
||||
if (get_selection_to_column() == 0) {
|
||||
selection_offset = 0;
|
||||
end_line--;
|
||||
}
|
||||
}
|
||||
|
||||
for (int i = start_line; i <= end_line; i++) {
|
||||
const String line_text = get_line(i);
|
||||
if (line_text.size() == 0 && is_selection_active()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!indent_using_spaces) {
|
||||
set_line(i, '\t' + line_text);
|
||||
continue;
|
||||
}
|
||||
|
||||
/* We don't really care where selection is - we just need to know indentation level at the beginning of the line. */
|
||||
/* Since we will add this many spaces, we want to move the whole selection and caret by this much. */
|
||||
int spaces_to_add = _calculate_spaces_till_next_right_indent(get_first_non_whitespace_column(i));
|
||||
set_line(i, String(" ").repeat(spaces_to_add) + line_text);
|
||||
selection_offset = spaces_to_add;
|
||||
}
|
||||
|
||||
/* Fix selection and caret being off after shifting selection right.*/
|
||||
if (is_selection_active()) {
|
||||
select(start_line, get_selection_from_column() + selection_offset, get_selection_to_line(), get_selection_to_column() + selection_offset);
|
||||
}
|
||||
cursor_set_column(cursor_get_column() + selection_offset, false);
|
||||
|
||||
end_complex_operation();
|
||||
}
|
||||
|
||||
void CodeEdit::do_unindent() {
|
||||
if (is_readonly()) {
|
||||
return;
|
||||
}
|
||||
|
||||
int cc = cursor_get_column();
|
||||
|
||||
if (is_selection_active() || cc <= 0) {
|
||||
unindent_lines();
|
||||
return;
|
||||
}
|
||||
|
||||
int cl = cursor_get_line();
|
||||
const String &line = get_line(cl);
|
||||
|
||||
if (line[cc - 1] == '\t') {
|
||||
_remove_text(cl, cc - 1, cl, cc);
|
||||
cursor_set_column(MAX(0, cc - 1));
|
||||
return;
|
||||
}
|
||||
|
||||
if (line[cc - 1] != ' ') {
|
||||
return;
|
||||
}
|
||||
|
||||
int spaces_to_remove = _calculate_spaces_till_next_left_indent(cc);
|
||||
if (spaces_to_remove > 0) {
|
||||
for (int i = 1; i <= spaces_to_remove; i++) {
|
||||
if (line[cc - i] != ' ') {
|
||||
spaces_to_remove = i - 1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
_remove_text(cl, cc - spaces_to_remove, cl, cc);
|
||||
cursor_set_column(MAX(0, cc - spaces_to_remove));
|
||||
}
|
||||
}
|
||||
|
||||
void CodeEdit::unindent_lines() {
|
||||
if (is_readonly()) {
|
||||
return;
|
||||
}
|
||||
|
||||
begin_complex_operation();
|
||||
|
||||
/* Moving caret and selection after unindenting can get tricky because */
|
||||
/* changing content of line can move caret and selection on its 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 = 0;
|
||||
int initial_cursor_column = cursor_get_column();
|
||||
|
||||
int start_line = cursor_get_line();
|
||||
int end_line = start_line;
|
||||
if (is_selection_active()) {
|
||||
start_line = get_selection_from_line();
|
||||
end_line = get_selection_to_line();
|
||||
|
||||
/* Ignore the last line if the selection is not past the first column. */
|
||||
initial_selection_end_column = get_selection_to_column();
|
||||
if (initial_selection_end_column == 0) {
|
||||
end_line--;
|
||||
}
|
||||
}
|
||||
|
||||
bool first_line_edited = false;
|
||||
bool last_line_edited = false;
|
||||
|
||||
for (int i = start_line; i <= end_line; i++) {
|
||||
String line_text = get_line(i);
|
||||
|
||||
if (line_text.begins_with("\t")) {
|
||||
line_text = line_text.substr(1, line_text.length());
|
||||
|
||||
set_line(i, line_text);
|
||||
removed_characters = 1;
|
||||
|
||||
first_line_edited = (i == start_line) ? true : first_line_edited;
|
||||
last_line_edited = (i == end_line) ? true : last_line_edited;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (line_text.begins_with(" ")) {
|
||||
/* When unindenting we aim to remove spaces before line that has selection no matter what is selected, */
|
||||
/* 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(get_first_non_whitespace_column(i));
|
||||
line_text = line_text.substr(spaces_to_remove, line_text.length());
|
||||
|
||||
set_line(i, line_text);
|
||||
removed_characters = spaces_to_remove;
|
||||
|
||||
first_line_edited = (i == start_line) ? true : first_line_edited;
|
||||
last_line_edited = (i == end_line) ? true : last_line_edited;
|
||||
}
|
||||
}
|
||||
|
||||
if (is_selection_active()) {
|
||||
/* Fix selection being off by one on the first line. */
|
||||
if (first_line_edited) {
|
||||
select(get_selection_from_line(), get_selection_from_column() - removed_characters, get_selection_to_line(), initial_selection_end_column);
|
||||
}
|
||||
|
||||
/* Fix selection being off by one on the last line. */
|
||||
if (last_line_edited) {
|
||||
select(get_selection_from_line(), get_selection_from_column(), get_selection_to_line(), initial_selection_end_column - removed_characters);
|
||||
}
|
||||
}
|
||||
cursor_set_column(initial_cursor_column - removed_characters, false);
|
||||
|
||||
end_complex_operation();
|
||||
}
|
||||
|
||||
int CodeEdit::_calculate_spaces_till_next_left_indent(int p_column) const {
|
||||
int spaces_till_indent = p_column % indent_size;
|
||||
if (spaces_till_indent == 0) {
|
||||
spaces_till_indent = indent_size;
|
||||
}
|
||||
return spaces_till_indent;
|
||||
}
|
||||
|
||||
int CodeEdit::_calculate_spaces_till_next_right_indent(int p_column) const {
|
||||
return indent_size - p_column % indent_size;
|
||||
}
|
||||
|
||||
/* TODO: remove once brace completion is refactored. */
|
||||
static char32_t _get_right_pair_symbol(char32_t c) {
|
||||
if (c == '"') {
|
||||
return '"';
|
||||
}
|
||||
if (c == '\'') {
|
||||
return '\'';
|
||||
}
|
||||
if (c == '(') {
|
||||
return ')';
|
||||
}
|
||||
if (c == '[') {
|
||||
return ']';
|
||||
}
|
||||
if (c == '{') {
|
||||
return '}';
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static bool _is_pair_left_symbol(char32_t c) {
|
||||
return c == '"' ||
|
||||
c == '\'' ||
|
||||
c == '(' ||
|
||||
c == '[' ||
|
||||
c == '{';
|
||||
}
|
||||
|
||||
void CodeEdit::_new_line(bool p_split_current_line, bool p_above) {
|
||||
if (is_readonly()) {
|
||||
return;
|
||||
}
|
||||
|
||||
const int cc = cursor_get_column();
|
||||
const int cl = cursor_get_line();
|
||||
const String line = get_line(cl);
|
||||
|
||||
String ins = "\n";
|
||||
|
||||
/* Append current indentation. */
|
||||
int space_count = 0;
|
||||
int line_col = 0;
|
||||
for (; line_col < cc; line_col++) {
|
||||
if (line[line_col] == '\t') {
|
||||
ins += indent_text;
|
||||
space_count = 0;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (line[line_col] == ' ') {
|
||||
space_count++;
|
||||
|
||||
if (space_count == indent_size) {
|
||||
ins += indent_text;
|
||||
space_count = 0;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
if (is_line_folded(cl)) {
|
||||
unfold_line(cl);
|
||||
}
|
||||
|
||||
/* Indent once again if the previous line needs it, ie ':'. */
|
||||
/* Then add an addition new line for any closing pairs aka '()'. */
|
||||
/* Skip this in comments or if we are going above. */
|
||||
bool brace_indent = false;
|
||||
if (auto_indent && !p_above && cc > 0 && is_in_comment(cl) == -1) {
|
||||
bool should_indent = false;
|
||||
char32_t indent_char = ' ';
|
||||
|
||||
for (; line_col < cc; line_col++) {
|
||||
char32_t c = line[line_col];
|
||||
if (auto_indent_prefixes.has(c)) {
|
||||
should_indent = true;
|
||||
indent_char = c;
|
||||
continue;
|
||||
}
|
||||
|
||||
/* Make sure this is the last char, trailing whitespace or comments are okay. */
|
||||
if (should_indent && (!_is_whitespace(c) && is_in_comment(cl, cc) == -1)) {
|
||||
should_indent = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (should_indent) {
|
||||
ins += indent_text;
|
||||
|
||||
/* TODO: Change when brace completion is refactored. */
|
||||
char32_t closing_char = _get_right_pair_symbol(indent_char);
|
||||
if (closing_char != 0 && closing_char == line[cc]) {
|
||||
/* No need to move the brace below if we are not taking the text with us. */
|
||||
if (p_split_current_line) {
|
||||
brace_indent = true;
|
||||
ins += "\n" + ins.substr(1, ins.length() - 2);
|
||||
} else {
|
||||
brace_indent = false;
|
||||
ins = "\n" + ins.substr(1, ins.length() - 2);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
begin_complex_operation();
|
||||
|
||||
bool first_line = false;
|
||||
if (!p_split_current_line) {
|
||||
if (p_above) {
|
||||
if (cl > 0) {
|
||||
cursor_set_line(cl - 1, false);
|
||||
cursor_set_column(get_line(cursor_get_line()).length());
|
||||
} else {
|
||||
cursor_set_column(0);
|
||||
first_line = true;
|
||||
}
|
||||
} else {
|
||||
cursor_set_column(line.length());
|
||||
}
|
||||
}
|
||||
|
||||
insert_text_at_cursor(ins);
|
||||
|
||||
if (first_line) {
|
||||
cursor_set_line(0);
|
||||
} else if (brace_indent) {
|
||||
cursor_set_line(cursor_get_line() - 1, false);
|
||||
cursor_set_column(get_line(cursor_get_line()).length());
|
||||
}
|
||||
|
||||
end_complex_operation();
|
||||
}
|
||||
|
||||
void CodeEdit::backspace() {
|
||||
if (is_readonly()) {
|
||||
return;
|
||||
}
|
||||
|
||||
int cc = cursor_get_column();
|
||||
int cl = cursor_get_line();
|
||||
|
||||
if (cc == 0 && cl == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (is_selection_active()) {
|
||||
delete_selection();
|
||||
return;
|
||||
}
|
||||
|
||||
if (cl > 0 && is_line_hidden(cl - 1)) {
|
||||
unfold_line(cursor_get_line() - 1);
|
||||
}
|
||||
|
||||
int prev_line = cc ? cl : cl - 1;
|
||||
int prev_column = cc ? (cc - 1) : (get_line(cl - 1).length());
|
||||
|
||||
merge_gutters(cl, prev_line);
|
||||
|
||||
/* TODO: Change when brace completion is refactored. */
|
||||
if (auto_brace_completion_enabled && cc > 0 && _is_pair_left_symbol(get_line(cl)[cc - 1])) {
|
||||
_consume_backspace_for_pair_symbol(prev_line, prev_column);
|
||||
cursor_set_line(prev_line, false, true);
|
||||
cursor_set_column(prev_column);
|
||||
return;
|
||||
}
|
||||
|
||||
/* For space indentation we need to do a simple unindent if there are no chars to the left, acting in the */
|
||||
/* same way as tabs. */
|
||||
if (indent_using_spaces && cc != 0) {
|
||||
if (get_first_non_whitespace_column(cl) > cc) {
|
||||
prev_column = cc - _calculate_spaces_till_next_left_indent(cc);
|
||||
prev_line = cl;
|
||||
}
|
||||
}
|
||||
|
||||
_remove_text(prev_line, prev_column, cl, cc);
|
||||
|
||||
cursor_set_line(prev_line, false, true);
|
||||
cursor_set_column(prev_column);
|
||||
}
|
||||
|
||||
/* Main Gutter */
|
||||
void CodeEdit::_update_draw_main_gutter() {
|
||||
set_gutter_draw(main_gutter, draw_breakpoints || draw_bookmarks || draw_executing_lines);
|
||||
|
@ -1286,6 +1743,25 @@ void CodeEdit::cancel_code_completion() {
|
|||
}
|
||||
|
||||
void CodeEdit::_bind_methods() {
|
||||
/* Indent management */
|
||||
ClassDB::bind_method(D_METHOD("set_indent_size", "size"), &CodeEdit::set_indent_size);
|
||||
ClassDB::bind_method(D_METHOD("get_indent_size"), &CodeEdit::get_indent_size);
|
||||
|
||||
ClassDB::bind_method(D_METHOD("set_indent_using_spaces", "use_spaces"), &CodeEdit::set_indent_using_spaces);
|
||||
ClassDB::bind_method(D_METHOD("is_indent_using_spaces"), &CodeEdit::is_indent_using_spaces);
|
||||
|
||||
ClassDB::bind_method(D_METHOD("set_auto_indent_enabled", "enable"), &CodeEdit::set_auto_indent_enabled);
|
||||
ClassDB::bind_method(D_METHOD("is_auto_indent_enabled"), &CodeEdit::is_auto_indent_enabled);
|
||||
|
||||
ClassDB::bind_method(D_METHOD("set_auto_indent_prefixes", "prefixes"), &CodeEdit::set_auto_indent_prefixes);
|
||||
ClassDB::bind_method(D_METHOD("get_auto_indent_prefixes"), &CodeEdit::get_auto_indent_prefixes);
|
||||
|
||||
ClassDB::bind_method(D_METHOD("do_indent"), &CodeEdit::do_indent);
|
||||
ClassDB::bind_method(D_METHOD("do_unindent"), &CodeEdit::do_unindent);
|
||||
|
||||
ClassDB::bind_method(D_METHOD("indent_lines"), &CodeEdit::indent_lines);
|
||||
ClassDB::bind_method(D_METHOD("unindent_lines"), &CodeEdit::unindent_lines);
|
||||
|
||||
/* Main Gutter */
|
||||
ClassDB::bind_method(D_METHOD("_main_gutter_draw_callback"), &CodeEdit::_main_gutter_draw_callback);
|
||||
|
||||
|
@ -1436,6 +1912,12 @@ void CodeEdit::_bind_methods() {
|
|||
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "code_completion_enabled"), "set_code_completion_enabled", "is_code_completion_enabled");
|
||||
ADD_PROPERTY(PropertyInfo(Variant::PACKED_STRING_ARRAY, "code_completion_prefixes"), "set_code_completion_prefixes", "get_code_comletion_prefixes");
|
||||
|
||||
ADD_GROUP("Indentation", "indent_");
|
||||
ADD_PROPERTY(PropertyInfo(Variant::INT, "indent_size"), "set_indent_size", "get_indent_size");
|
||||
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "indent_use_spaces"), "set_indent_using_spaces", "is_indent_using_spaces");
|
||||
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "indent_automatic"), "set_auto_indent_enabled", "is_auto_indent_enabled");
|
||||
ADD_PROPERTY(PropertyInfo(Variant::PACKED_STRING_ARRAY, "indent_automatic_prefixes"), "set_auto_indent_prefixes", "get_auto_indent_prefixes");
|
||||
|
||||
/* Signals */
|
||||
ADD_SIGNAL(MethodInfo("breakpoint_toggled", PropertyInfo(Variant::INT, "line")));
|
||||
ADD_SIGNAL(MethodInfo("request_code_completion"));
|
||||
|
@ -2062,6 +2544,12 @@ void CodeEdit::_lines_edited_from(int p_from_line, int p_to_line) {
|
|||
}
|
||||
|
||||
CodeEdit::CodeEdit() {
|
||||
/* Indent management */
|
||||
auto_indent_prefixes.insert(':');
|
||||
auto_indent_prefixes.insert('{');
|
||||
auto_indent_prefixes.insert('[');
|
||||
auto_indent_prefixes.insert('(');
|
||||
|
||||
/* Text Direction */
|
||||
set_layout_direction(LAYOUT_DIRECTION_LTR);
|
||||
set_text_direction(TEXT_DIRECTION_LTR);
|
||||
|
|
|
@ -53,6 +53,19 @@ public:
|
|||
};
|
||||
|
||||
private:
|
||||
/* Indent management */
|
||||
int indent_size = 4;
|
||||
String indent_text = "\t";
|
||||
|
||||
bool auto_indent = false;
|
||||
Set<char32_t> auto_indent_prefixes;
|
||||
|
||||
bool indent_using_spaces = false;
|
||||
int _calculate_spaces_till_next_left_indent(int p_column) const;
|
||||
int _calculate_spaces_till_next_right_indent(int p_column) const;
|
||||
|
||||
void _new_line(bool p_split_current_line = true, bool p_above = false);
|
||||
|
||||
/* Main Gutter */
|
||||
enum MainGutterType {
|
||||
MAIN_GUTTER_BREAKPOINT = 0x01,
|
||||
|
@ -206,6 +219,27 @@ protected:
|
|||
public:
|
||||
virtual CursorShape get_cursor_shape(const Point2 &p_pos = Point2i()) const override;
|
||||
|
||||
/* Indent management */
|
||||
void set_indent_size(const int p_size);
|
||||
int get_indent_size() const;
|
||||
|
||||
void set_indent_using_spaces(const bool p_use_spaces);
|
||||
bool is_indent_using_spaces() const;
|
||||
|
||||
void set_auto_indent_enabled(bool p_enabled);
|
||||
bool is_auto_indent_enabled() const;
|
||||
|
||||
void set_auto_indent_prefixes(const TypedArray<String> &p_prefixes);
|
||||
TypedArray<String> get_auto_indent_prefixes() const;
|
||||
|
||||
void do_indent();
|
||||
void do_unindent();
|
||||
|
||||
void indent_lines();
|
||||
void unindent_lines();
|
||||
|
||||
virtual void backspace() override;
|
||||
|
||||
/* Main Gutter */
|
||||
void set_draw_breakpoints_gutter(bool p_draw);
|
||||
bool is_drawing_breakpoints_gutter() const;
|
||||
|
|
|
@ -102,14 +102,6 @@ static char32_t _get_right_pair_symbol(char32_t 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) {
|
||||
|
@ -120,8 +112,12 @@ void TextEdit::Text::set_font_size(int p_font_size) {
|
|||
font_size = p_font_size;
|
||||
}
|
||||
|
||||
void TextEdit::Text::set_indent_size(int p_indent_size) {
|
||||
indent_size = p_indent_size;
|
||||
void TextEdit::Text::set_tab_size(int p_tab_size) {
|
||||
tab_size = p_tab_size;
|
||||
}
|
||||
|
||||
int TextEdit::Text::get_tab_size() const {
|
||||
return tab_size;
|
||||
}
|
||||
|
||||
void TextEdit::Text::set_font_features(const Dictionary &p_features) {
|
||||
|
@ -204,9 +200,9 @@ void TextEdit::Text::invalidate_cache(int p_line, int p_column, const String &p_
|
|||
}
|
||||
|
||||
// Apply tab align.
|
||||
if (indent_size > 0) {
|
||||
if (tab_size > 0) {
|
||||
Vector<float> tabs;
|
||||
tabs.push_back(font->get_char_size(' ', 0, font_size).width * indent_size);
|
||||
tabs.push_back(font->get_char_size(' ', 0, font_size).width * tab_size);
|
||||
text.write[p_line].data_buf->tab_align(tabs);
|
||||
}
|
||||
}
|
||||
|
@ -214,9 +210,9 @@ void TextEdit::Text::invalidate_cache(int p_line, int p_column, const String &p_
|
|||
void TextEdit::Text::invalidate_all_lines() {
|
||||
for (int i = 0; i < text.size(); i++) {
|
||||
text.write[i].data_buf->set_width(width);
|
||||
if (indent_size > 0) {
|
||||
if (tab_size > 0) {
|
||||
Vector<float> tabs;
|
||||
tabs.push_back(font->get_char_size(' ', 0, font_size).width * indent_size);
|
||||
tabs.push_back(font->get_char_size(' ', 0, font_size).width * tab_size);
|
||||
text.write[i].data_buf->tab_align(tabs);
|
||||
}
|
||||
}
|
||||
|
@ -822,7 +818,7 @@ void TextEdit::_notification(int p_what) {
|
|||
if (draw_minimap) {
|
||||
int minimap_visible_lines = _get_minimap_visible_rows();
|
||||
int minimap_line_height = (minimap_char_size.y + minimap_line_spacing);
|
||||
int minimap_tab_size = minimap_char_size.x * indent_size;
|
||||
int minimap_tab_size = minimap_char_size.x * text.get_tab_size();
|
||||
|
||||
// calculate viewport size and y offset
|
||||
int viewport_height = (draw_amount - 1) * minimap_line_height;
|
||||
|
@ -1695,7 +1691,13 @@ void TextEdit::_consume_backspace_for_pair_symbol(int prev_line, int prev_column
|
|||
}
|
||||
}
|
||||
|
||||
void TextEdit::backspace_at_cursor() {
|
||||
void TextEdit::backspace() {
|
||||
ScriptInstance *si = get_script_instance();
|
||||
if (si && si->has_method("_backspace")) {
|
||||
si->call("_backspace");
|
||||
return;
|
||||
}
|
||||
|
||||
if (readonly) {
|
||||
return;
|
||||
}
|
||||
|
@ -1704,34 +1706,15 @@ void TextEdit::backspace_at_cursor() {
|
|||
return;
|
||||
}
|
||||
|
||||
if (is_selection_active()) {
|
||||
delete_selection();
|
||||
return;
|
||||
}
|
||||
|
||||
int prev_line = cursor.column ? cursor.line : cursor.line - 1;
|
||||
int prev_column = cursor.column ? (cursor.column - 1) : (text[cursor.line - 1].length());
|
||||
|
||||
if (cursor.line != prev_line) {
|
||||
for (int i = 0; i < gutters.size(); i++) {
|
||||
if (!gutters[i].overwritable) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (text.get_line_gutter_text(cursor.line, i) != "") {
|
||||
text.set_line_gutter_text(prev_line, i, text.get_line_gutter_text(cursor.line, i));
|
||||
text.set_line_gutter_item_color(prev_line, i, text.get_line_gutter_item_color(cursor.line, i));
|
||||
}
|
||||
|
||||
if (text.get_line_gutter_icon(cursor.line, i).is_valid()) {
|
||||
text.set_line_gutter_icon(prev_line, i, text.get_line_gutter_icon(cursor.line, i));
|
||||
text.set_line_gutter_item_color(prev_line, i, text.get_line_gutter_item_color(cursor.line, i));
|
||||
}
|
||||
|
||||
if (text.get_line_gutter_metadata(cursor.line, i) != "") {
|
||||
text.set_line_gutter_metadata(prev_line, i, text.get_line_gutter_metadata(cursor.line, i));
|
||||
}
|
||||
|
||||
if (text.is_line_gutter_clickable(cursor.line, i)) {
|
||||
text.set_line_gutter_clickable(prev_line, i, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
merge_gutters(cursor.line, prev_line);
|
||||
|
||||
if (is_line_hidden(cursor.line)) {
|
||||
set_line_as_hidden(prev_line, true);
|
||||
|
@ -1742,168 +1725,13 @@ void TextEdit::backspace_at_cursor() {
|
|||
_is_pair_left_symbol(text[cursor.line][cursor.column - 1])) {
|
||||
_consume_backspace_for_pair_symbol(prev_line, prev_column);
|
||||
} else {
|
||||
// Handle space indentation.
|
||||
if (cursor.column != 0 && indent_using_spaces) {
|
||||
// Check if there are no other chars before cursor, just indentation.
|
||||
bool unindent = true;
|
||||
int i = 0;
|
||||
while (i < cursor.column && i < text[cursor.line].length()) {
|
||||
if (!_is_whitespace(text[cursor.line][i])) {
|
||||
unindent = false;
|
||||
break;
|
||||
}
|
||||
i++;
|
||||
}
|
||||
|
||||
// Then we can remove all spaces as a single character.
|
||||
if (unindent) {
|
||||
// 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);
|
||||
}
|
||||
} else {
|
||||
_remove_text(prev_line, prev_column, cursor.line, cursor.column);
|
||||
}
|
||||
_remove_text(prev_line, prev_column, cursor.line, cursor.column);
|
||||
}
|
||||
|
||||
cursor_set_line(prev_line, false, true);
|
||||
cursor_set_column(prev_column);
|
||||
}
|
||||
|
||||
void TextEdit::indent_selected_lines_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()) {
|
||||
start_line = get_selection_from_line();
|
||||
end_line = get_selection_to_line();
|
||||
} else {
|
||||
start_line = cursor.line;
|
||||
end_line = start_line;
|
||||
}
|
||||
|
||||
// Ignore if the cursor is not past the first column.
|
||||
if (is_selection_active() && get_selection_to_column() == 0) {
|
||||
selection_offset = 0;
|
||||
end_line--;
|
||||
}
|
||||
|
||||
for (int i = start_line; i <= end_line; i++) {
|
||||
String line_text = get_line(i);
|
||||
if (line_text.size() == 0 && is_selection_active()) {
|
||||
continue;
|
||||
}
|
||||
if (indent_using_spaces) {
|
||||
// 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 these many spaces, we want to move the 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 after shifting selection right.
|
||||
if (is_selection_active()) {
|
||||
select(selection.from_line, selection.from_column + selection_offset, selection.to_line, selection.to_column + selection_offset);
|
||||
}
|
||||
cursor_set_column(cursor.column + selection_offset, false);
|
||||
end_complex_operation();
|
||||
update();
|
||||
}
|
||||
|
||||
void TextEdit::indent_selected_lines_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 its 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()) {
|
||||
start_line = get_selection_from_line();
|
||||
end_line = get_selection_to_line();
|
||||
} else {
|
||||
start_line = cursor.line;
|
||||
end_line = start_line;
|
||||
}
|
||||
|
||||
// Ignore if the cursor is not past the first column.
|
||||
if (is_selection_active() && get_selection_to_column() == 0) {
|
||||
end_line--;
|
||||
}
|
||||
String first_line_text = get_line(start_line);
|
||||
String last_line_text = get_line(end_line);
|
||||
|
||||
for (int i = start_line; i <= end_line; i++) {
|
||||
String line_text = get_line(i);
|
||||
|
||||
if (line_text.begins_with("\t")) {
|
||||
line_text = line_text.substr(1, line_text.length());
|
||||
set_line(i, line_text);
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
if (is_selection_active()) {
|
||||
// Fix selection being off by one on the first line.
|
||||
if (first_line_text != get_line(start_line)) {
|
||||
select(selection.from_line, selection.from_column - removed_characters,
|
||||
selection.to_line, initial_selection_end_column);
|
||||
}
|
||||
// Fix selection being off by one on the last line.
|
||||
if (last_line_text != get_line(end_line)) {
|
||||
select(selection.from_line, selection.from_column,
|
||||
selection.to_line, initial_selection_end_column - removed_characters);
|
||||
}
|
||||
}
|
||||
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::_swap_current_input_direction() {
|
||||
if (input_direction == TEXT_DIRECTION_LTR) {
|
||||
input_direction = TEXT_DIRECTION_RTL;
|
||||
|
@ -1919,90 +1747,8 @@ void TextEdit::_new_line(bool p_split_current_line, bool p_above) {
|
|||
return;
|
||||
}
|
||||
|
||||
String ins = "\n";
|
||||
|
||||
// Keep indentation.
|
||||
int space_count = 0;
|
||||
for (int i = 0; i < cursor.column; i++) {
|
||||
if (text[cursor.line][i] == '\t') {
|
||||
if (indent_using_spaces) {
|
||||
ins += space_indent;
|
||||
} else {
|
||||
ins += "\t";
|
||||
}
|
||||
space_count = 0;
|
||||
} else if (text[cursor.line][i] == ' ') {
|
||||
space_count++;
|
||||
|
||||
if (space_count == indent_size) {
|
||||
if (indent_using_spaces) {
|
||||
ins += space_indent;
|
||||
} else {
|
||||
ins += "\t";
|
||||
}
|
||||
space_count = 0;
|
||||
}
|
||||
} else {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
bool brace_indent = false;
|
||||
|
||||
// No need to indent if we are going upwards.
|
||||
if (auto_indent && !p_above) {
|
||||
// Indent once again if previous line will end with ':','{','[','(' and the line is not a comment
|
||||
// (i.e. colon/brace precedes current cursor position).
|
||||
if (cursor.column > 0) {
|
||||
bool indent_char_found = false;
|
||||
bool should_indent = false;
|
||||
char indent_char = ':';
|
||||
char c = text[cursor.line][cursor.column];
|
||||
|
||||
for (int i = 0; i < cursor.column; i++) {
|
||||
c = text[cursor.line][i];
|
||||
switch (c) {
|
||||
case ':':
|
||||
case '{':
|
||||
case '[':
|
||||
case '(':
|
||||
indent_char_found = true;
|
||||
should_indent = true;
|
||||
indent_char = c;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (indent_char_found && is_line_comment(cursor.line)) {
|
||||
should_indent = true;
|
||||
break;
|
||||
} else if (indent_char_found && !_is_whitespace(c)) {
|
||||
should_indent = false;
|
||||
indent_char_found = false;
|
||||
}
|
||||
}
|
||||
|
||||
if (!is_line_comment(cursor.line) && should_indent) {
|
||||
if (indent_using_spaces) {
|
||||
ins += space_indent;
|
||||
} else {
|
||||
ins += "\t";
|
||||
}
|
||||
|
||||
// No need to move the brace below if we are not taking the text with us.
|
||||
char32_t closing_char = _get_right_pair_symbol(indent_char);
|
||||
if ((closing_char != 0) && (closing_char == text[cursor.line][cursor.column])) {
|
||||
if (p_split_current_line) {
|
||||
brace_indent = true;
|
||||
ins += "\n" + ins.substr(1, ins.length() - 2);
|
||||
} else {
|
||||
brace_indent = false;
|
||||
ins = "\n" + ins.substr(1, ins.length() - 2);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
begin_complex_operation();
|
||||
|
||||
bool first_line = false;
|
||||
if (!p_split_current_line) {
|
||||
if (p_above) {
|
||||
|
@ -2018,85 +1764,15 @@ void TextEdit::_new_line(bool p_split_current_line, bool p_above) {
|
|||
}
|
||||
}
|
||||
|
||||
insert_text_at_cursor(ins);
|
||||
insert_text_at_cursor("\n");
|
||||
|
||||
if (first_line) {
|
||||
cursor_set_line(0);
|
||||
} else if (brace_indent) {
|
||||
cursor_set_line(cursor.line - 1, false);
|
||||
cursor_set_column(text[cursor.line].length());
|
||||
}
|
||||
|
||||
end_complex_operation();
|
||||
}
|
||||
|
||||
void TextEdit::_indent_right() {
|
||||
if (readonly) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (is_selection_active()) {
|
||||
indent_selected_lines_right();
|
||||
} else {
|
||||
// Simple indent.
|
||||
if (indent_using_spaces) {
|
||||
// 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");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void TextEdit::_indent_left() {
|
||||
if (readonly) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (is_selection_active()) {
|
||||
indent_selected_lines_left();
|
||||
} else {
|
||||
// Simple unindent.
|
||||
int cc = cursor.column;
|
||||
const String &line = text[cursor.line];
|
||||
|
||||
int left = _find_first_non_whitespace_column_of_line(line);
|
||||
cc = MIN(cc, left);
|
||||
|
||||
while (cc < indent_size && cc < left && line[cc] == ' ') {
|
||||
cc++;
|
||||
}
|
||||
|
||||
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 {
|
||||
// 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();
|
||||
}
|
||||
}
|
||||
} else if (cc == 0 && line.length() > 0 && line[0] == '\t') {
|
||||
_remove_text(cursor.line, 0, cursor.line, 1);
|
||||
update();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void TextEdit::_move_cursor_left(bool p_select, bool p_move_by_word) {
|
||||
// Handle selection
|
||||
if (p_select) {
|
||||
|
@ -2331,20 +2007,24 @@ void TextEdit::_move_cursor_page_down(bool p_select) {
|
|||
}
|
||||
}
|
||||
|
||||
void TextEdit::_backspace(bool p_word, bool p_all_to_left) {
|
||||
void TextEdit::_do_backspace(bool p_word, bool p_all_to_left) {
|
||||
if (readonly) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (is_selection_active()) {
|
||||
_delete_selection();
|
||||
if (is_selection_active() || (!p_all_to_left && !p_word)) {
|
||||
backspace();
|
||||
return;
|
||||
}
|
||||
|
||||
if (p_all_to_left) {
|
||||
int cursor_current_column = cursor.column;
|
||||
cursor.column = 0;
|
||||
_remove_text(cursor.line, 0, cursor.line, cursor_current_column);
|
||||
} else if (p_word) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (p_word) {
|
||||
int line = cursor.line;
|
||||
int column = cursor.column;
|
||||
|
||||
|
@ -2360,8 +2040,7 @@ void TextEdit::_backspace(bool p_word, bool p_all_to_left) {
|
|||
|
||||
cursor_set_line(line, false);
|
||||
cursor_set_column(column);
|
||||
} else {
|
||||
backspace_at_cursor();
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -2371,7 +2050,7 @@ void TextEdit::_delete(bool p_word, bool p_all_to_right) {
|
|||
}
|
||||
|
||||
if (is_selection_active()) {
|
||||
_delete_selection();
|
||||
delete_selection();
|
||||
return;
|
||||
}
|
||||
int curline_len = text[cursor.line].length();
|
||||
|
@ -2416,15 +2095,16 @@ void TextEdit::_delete(bool p_word, bool p_all_to_right) {
|
|||
update();
|
||||
}
|
||||
|
||||
void TextEdit::_delete_selection() {
|
||||
if (is_selection_active()) {
|
||||
selection.active = false;
|
||||
update();
|
||||
_remove_text(selection.from_line, selection.from_column, selection.to_line, selection.to_column);
|
||||
cursor_set_line(selection.from_line, false, false);
|
||||
cursor_set_column(selection.from_column);
|
||||
update();
|
||||
void TextEdit::delete_selection() {
|
||||
if (!is_selection_active()) {
|
||||
return;
|
||||
}
|
||||
|
||||
selection.active = false;
|
||||
_remove_text(selection.from_line, selection.from_column, selection.to_line, selection.to_column);
|
||||
cursor_set_line(selection.from_line, false, false);
|
||||
cursor_set_column(selection.from_column);
|
||||
update();
|
||||
}
|
||||
|
||||
void TextEdit::_move_cursor_document_start(bool p_select) {
|
||||
|
@ -2459,7 +2139,7 @@ void TextEdit::_move_cursor_document_end(bool p_select) {
|
|||
|
||||
void TextEdit::_handle_unicode_character(uint32_t unicode, bool p_had_selection) {
|
||||
if (p_had_selection) {
|
||||
_delete_selection();
|
||||
delete_selection();
|
||||
}
|
||||
|
||||
// Remove the old character if in insert mode and no selection.
|
||||
|
@ -2942,31 +2622,19 @@ void TextEdit::_gui_input(const Ref<InputEvent> &p_gui_input) {
|
|||
return;
|
||||
}
|
||||
|
||||
// INDENTATION.
|
||||
if (k->is_action("ui_text_dedent", true)) {
|
||||
_indent_left();
|
||||
accept_event();
|
||||
return;
|
||||
}
|
||||
if (k->is_action("ui_text_indent", true)) {
|
||||
_indent_right();
|
||||
accept_event();
|
||||
return;
|
||||
}
|
||||
|
||||
// BACKSPACE AND DELETE.
|
||||
if (k->is_action("ui_text_backspace_all_to_left", true)) {
|
||||
_backspace(false, true);
|
||||
_do_backspace(false, true);
|
||||
accept_event();
|
||||
return;
|
||||
}
|
||||
if (k->is_action("ui_text_backspace_word", true)) {
|
||||
_backspace(true);
|
||||
_do_backspace(true);
|
||||
accept_event();
|
||||
return;
|
||||
}
|
||||
if (k->is_action("ui_text_backspace", true)) {
|
||||
_backspace();
|
||||
_do_backspace();
|
||||
accept_event();
|
||||
return;
|
||||
}
|
||||
|
@ -4540,6 +4208,39 @@ bool TextEdit::is_gutter_overwritable(int p_gutter) const {
|
|||
return gutters[p_gutter].overwritable;
|
||||
}
|
||||
|
||||
void TextEdit::merge_gutters(int p_from_line, int p_to_line) {
|
||||
ERR_FAIL_INDEX(p_from_line, text.size());
|
||||
ERR_FAIL_INDEX(p_to_line, text.size());
|
||||
if (p_from_line == p_to_line) {
|
||||
return;
|
||||
}
|
||||
|
||||
for (int i = 0; i < gutters.size(); i++) {
|
||||
if (!gutters[i].overwritable) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (text.get_line_gutter_text(p_from_line, i) != "") {
|
||||
text.set_line_gutter_text(p_to_line, i, text.get_line_gutter_text(p_from_line, i));
|
||||
text.set_line_gutter_item_color(p_to_line, i, text.get_line_gutter_item_color(p_from_line, i));
|
||||
}
|
||||
|
||||
if (text.get_line_gutter_icon(p_from_line, i).is_valid()) {
|
||||
text.set_line_gutter_icon(p_to_line, i, text.get_line_gutter_icon(p_from_line, i));
|
||||
text.set_line_gutter_item_color(p_to_line, i, text.get_line_gutter_item_color(p_from_line, i));
|
||||
}
|
||||
|
||||
if (text.get_line_gutter_metadata(p_from_line, i) != "") {
|
||||
text.set_line_gutter_metadata(p_to_line, i, text.get_line_gutter_metadata(p_from_line, i));
|
||||
}
|
||||
|
||||
if (text.is_line_gutter_clickable(p_from_line, i)) {
|
||||
text.set_line_gutter_clickable(p_to_line, i, true);
|
||||
}
|
||||
}
|
||||
update();
|
||||
}
|
||||
|
||||
void TextEdit::set_gutter_custom_draw(int p_gutter, Object *p_object, const StringName &p_callback) {
|
||||
ERR_FAIL_INDEX(p_gutter, gutters.size());
|
||||
ERR_FAIL_NULL(p_object);
|
||||
|
@ -4625,10 +4326,6 @@ Color TextEdit::get_line_background_color(int p_line) {
|
|||
return text.get_line_background_color(p_line);
|
||||
}
|
||||
|
||||
void TextEdit::set_auto_indent(bool p_auto_indent) {
|
||||
auto_indent = p_auto_indent;
|
||||
}
|
||||
|
||||
void TextEdit::cut() {
|
||||
if (readonly) {
|
||||
return;
|
||||
|
@ -4644,7 +4341,7 @@ void TextEdit::cut() {
|
|||
_remove_text(cursor.line, 0, cursor.line + 1, 0);
|
||||
} else {
|
||||
_remove_text(cursor.line, 0, cursor.line, text[cursor.line].length());
|
||||
backspace_at_cursor();
|
||||
backspace();
|
||||
cursor_set_line(cursor.line + 1);
|
||||
}
|
||||
|
||||
|
@ -5191,7 +4888,6 @@ int TextEdit::get_last_unhidden_line() const {
|
|||
int TextEdit::get_indent_level(int p_line) const {
|
||||
ERR_FAIL_INDEX_V(p_line, text.size(), 0);
|
||||
|
||||
// Counts number of tabs and spaces before line starts.
|
||||
int tab_count = 0;
|
||||
int whitespace_count = 0;
|
||||
int line_length = text[p_line].size();
|
||||
|
@ -5204,28 +4900,17 @@ int TextEdit::get_indent_level(int p_line) const {
|
|||
break;
|
||||
}
|
||||
}
|
||||
return tab_count * indent_size + whitespace_count;
|
||||
return tab_count * text.get_tab_size() + whitespace_count;
|
||||
}
|
||||
|
||||
bool TextEdit::is_line_comment(int p_line) const {
|
||||
// Checks to see if this line is the start of a comment.
|
||||
ERR_FAIL_INDEX_V(p_line, text.size(), false);
|
||||
int TextEdit::get_first_non_whitespace_column(int p_line) const {
|
||||
ERR_FAIL_INDEX_V(p_line, text.size(), 0);
|
||||
|
||||
int line_length = text[p_line].size();
|
||||
for (int i = 0; i < line_length - 1; i++) {
|
||||
if (_is_whitespace(text[p_line][i])) {
|
||||
continue;
|
||||
}
|
||||
if (_is_symbol(text[p_line][i])) {
|
||||
if (text[p_line][i] == '\\') {
|
||||
i++; // Skip quoted anything.
|
||||
continue;
|
||||
}
|
||||
return text[p_line][i] == '#' || (i + 1 < line_length && text[p_line][i] == '/' && text[p_line][i + 1] == '/');
|
||||
}
|
||||
break;
|
||||
int col = 0;
|
||||
while (col < text[p_line].length() && _is_whitespace(text[p_line][col])) {
|
||||
col++;
|
||||
}
|
||||
return false;
|
||||
return col;
|
||||
}
|
||||
|
||||
int TextEdit::get_line_count() const {
|
||||
|
@ -5401,32 +5086,18 @@ void TextEdit::_push_current_op() {
|
|||
}
|
||||
}
|
||||
|
||||
void TextEdit::set_indent_using_spaces(const bool p_use_spaces) {
|
||||
indent_using_spaces = p_use_spaces;
|
||||
}
|
||||
|
||||
bool TextEdit::is_indent_using_spaces() const {
|
||||
return indent_using_spaces;
|
||||
}
|
||||
|
||||
void TextEdit::set_indent_size(const int p_size) {
|
||||
ERR_FAIL_COND_MSG(p_size <= 0, "Indend size must be greater than 0.");
|
||||
if (indent_size != p_size) {
|
||||
indent_size = p_size;
|
||||
text.set_indent_size(p_size);
|
||||
text.invalidate_all_lines();
|
||||
void TextEdit::set_tab_size(const int p_size) {
|
||||
ERR_FAIL_COND_MSG(p_size <= 0, "Tab size must be greater than 0.");
|
||||
if (p_size == text.get_tab_size()) {
|
||||
return;
|
||||
}
|
||||
|
||||
space_indent = "";
|
||||
for (int i = 0; i < p_size; i++) {
|
||||
space_indent += " ";
|
||||
}
|
||||
|
||||
text.set_tab_size(p_size);
|
||||
text.invalidate_all_lines();
|
||||
update();
|
||||
}
|
||||
|
||||
int TextEdit::get_indent_size() {
|
||||
return indent_size;
|
||||
int TextEdit::get_tab_size() const {
|
||||
return text.get_tab_size();
|
||||
}
|
||||
|
||||
void TextEdit::set_draw_tabs(bool p_draw) {
|
||||
|
@ -6019,6 +5690,11 @@ void TextEdit::_bind_methods() {
|
|||
ClassDB::bind_method(D_METHOD("set_language", "language"), &TextEdit::set_language);
|
||||
ClassDB::bind_method(D_METHOD("get_language"), &TextEdit::get_language);
|
||||
|
||||
ClassDB::bind_method(D_METHOD("get_first_non_whitespace_column", "line"), &TextEdit::get_first_non_whitespace_column);
|
||||
ClassDB::bind_method(D_METHOD("get_indent_level", "line"), &TextEdit::get_indent_level);
|
||||
ClassDB::bind_method(D_METHOD("set_tab_size", "size"), &TextEdit::set_tab_size);
|
||||
ClassDB::bind_method(D_METHOD("get_tab_size"), &TextEdit::get_tab_size);
|
||||
|
||||
ClassDB::bind_method(D_METHOD("set_text", "text"), &TextEdit::set_text);
|
||||
ClassDB::bind_method(D_METHOD("insert_text_at_cursor", "text"), &TextEdit::insert_text_at_cursor);
|
||||
|
||||
|
@ -6073,6 +5749,10 @@ void TextEdit::_bind_methods() {
|
|||
ClassDB::bind_method(D_METHOD("set_selecting_enabled", "enable"), &TextEdit::set_selecting_enabled);
|
||||
ClassDB::bind_method(D_METHOD("is_selecting_enabled"), &TextEdit::is_selecting_enabled);
|
||||
|
||||
ClassDB::bind_method(D_METHOD("delete_selection"), &TextEdit::delete_selection);
|
||||
ClassDB::bind_method(D_METHOD("backspace"), &TextEdit::backspace);
|
||||
BIND_VMETHOD(MethodInfo("_backspace"));
|
||||
|
||||
ClassDB::bind_method(D_METHOD("cut"), &TextEdit::cut);
|
||||
ClassDB::bind_method(D_METHOD("copy"), &TextEdit::copy);
|
||||
ClassDB::bind_method(D_METHOD("paste"), &TextEdit::paste);
|
||||
|
@ -6128,6 +5808,7 @@ void TextEdit::_bind_methods() {
|
|||
ClassDB::bind_method(D_METHOD("is_gutter_clickable", "gutter"), &TextEdit::is_gutter_clickable);
|
||||
ClassDB::bind_method(D_METHOD("set_gutter_overwritable", "gutter", "overwritable"), &TextEdit::set_gutter_overwritable);
|
||||
ClassDB::bind_method(D_METHOD("is_gutter_overwritable", "gutter"), &TextEdit::is_gutter_overwritable);
|
||||
ClassDB::bind_method(D_METHOD("merge_gutters", "from_line", "to_line"), &TextEdit::merge_gutters);
|
||||
ClassDB::bind_method(D_METHOD("set_gutter_custom_draw", "column", "object", "callback"), &TextEdit::set_gutter_custom_draw);
|
||||
|
||||
// Line gutters.
|
||||
|
@ -6254,7 +5935,7 @@ TextEdit::TextEdit() {
|
|||
_update_caches();
|
||||
set_default_cursor_shape(CURSOR_IBEAM);
|
||||
|
||||
text.set_indent_size(indent_size);
|
||||
text.set_tab_size(text.get_tab_size());
|
||||
text.clear();
|
||||
|
||||
h_scroll = memnew(HScrollBar);
|
||||
|
|
|
@ -112,11 +112,12 @@ private:
|
|||
|
||||
int width = -1;
|
||||
|
||||
int indent_size = 4;
|
||||
int tab_size = 4;
|
||||
int gutter_count = 0;
|
||||
|
||||
public:
|
||||
void set_indent_size(int p_indent_size);
|
||||
void set_tab_size(int p_tab_size);
|
||||
int get_tab_size() const;
|
||||
void set_font(const Ref<Font> &p_font);
|
||||
void set_font_size(int p_font_size);
|
||||
void set_font_features(const Dictionary &p_features);
|
||||
|
@ -259,9 +260,6 @@ private:
|
|||
|
||||
int max_chars = 0;
|
||||
bool readonly = true; // Initialise to opposite first, so we get past the early-out in set_readonly.
|
||||
bool indent_using_spaces = false;
|
||||
int indent_size = 4;
|
||||
String space_indent = " ";
|
||||
|
||||
Timer *caret_blink_timer;
|
||||
bool caret_blink_enabled = false;
|
||||
|
@ -296,7 +294,6 @@ private:
|
|||
bool scroll_past_end_of_file_enabled = false;
|
||||
bool brace_matching_enabled = false;
|
||||
bool highlight_current_line = false;
|
||||
bool auto_indent = false;
|
||||
|
||||
String cut_copy_line;
|
||||
bool insert_mode = false;
|
||||
|
@ -420,14 +417,9 @@ private:
|
|||
|
||||
void _clear();
|
||||
|
||||
int _calculate_spaces_till_next_left_indent(int column);
|
||||
int _calculate_spaces_till_next_right_indent(int column);
|
||||
|
||||
// Methods used in shortcuts
|
||||
void _swap_current_input_direction();
|
||||
void _new_line(bool p_split_current = true, bool p_above = false);
|
||||
void _indent_right();
|
||||
void _indent_left();
|
||||
void _move_cursor_left(bool p_select, bool p_move_by_word = false);
|
||||
void _move_cursor_right(bool p_select, bool p_move_by_word = false);
|
||||
void _move_cursor_up(bool p_select);
|
||||
|
@ -436,9 +428,8 @@ private:
|
|||
void _move_cursor_to_line_end(bool p_select);
|
||||
void _move_cursor_page_up(bool p_select);
|
||||
void _move_cursor_page_down(bool p_select);
|
||||
void _backspace(bool p_word = false, bool p_all_to_left = false);
|
||||
void _do_backspace(bool p_word = false, bool p_all_to_left = false);
|
||||
void _delete(bool p_word = false, bool p_all_to_right = false);
|
||||
void _delete_selection();
|
||||
void _move_cursor_document_start(bool p_select);
|
||||
void _move_cursor_document_end(bool p_select);
|
||||
void _handle_unicode_character(uint32_t unicode, bool p_had_selection);
|
||||
|
@ -522,6 +513,8 @@ public:
|
|||
void set_gutter_overwritable(int p_gutter, bool p_overwritable);
|
||||
bool is_gutter_overwritable(int p_gutter) const;
|
||||
|
||||
void merge_gutters(int p_from_line, int p_to_line);
|
||||
|
||||
void set_gutter_custom_draw(int p_gutter, Object *p_object, const StringName &p_callback);
|
||||
|
||||
// Line gutters.
|
||||
|
@ -635,12 +628,9 @@ public:
|
|||
bool has_ime_text() const;
|
||||
void set_line(int line, String new_text);
|
||||
int get_row_height() const;
|
||||
void backspace_at_cursor();
|
||||
|
||||
void indent_selected_lines_left();
|
||||
void indent_selected_lines_right();
|
||||
int get_indent_level(int p_line) const;
|
||||
bool is_line_comment(int p_line) const;
|
||||
int get_first_non_whitespace_column(int p_line) const;
|
||||
|
||||
inline void set_scroll_pass_end_of_file(bool p_enabled) {
|
||||
scroll_past_end_of_file_enabled = p_enabled;
|
||||
|
@ -653,7 +643,6 @@ public:
|
|||
brace_matching_enabled = p_enabled;
|
||||
update();
|
||||
}
|
||||
void set_auto_indent(bool p_auto_indent);
|
||||
|
||||
void center_viewport_to_cursor();
|
||||
|
||||
|
@ -699,6 +688,9 @@ public:
|
|||
|
||||
void clear();
|
||||
|
||||
void delete_selection();
|
||||
|
||||
virtual void backspace();
|
||||
void cut();
|
||||
void copy();
|
||||
void paste();
|
||||
|
@ -730,10 +722,8 @@ public:
|
|||
void redo();
|
||||
void clear_undo_history();
|
||||
|
||||
void set_indent_using_spaces(const bool p_use_spaces);
|
||||
bool is_indent_using_spaces() const;
|
||||
void set_indent_size(const int p_size);
|
||||
int get_indent_size();
|
||||
void set_tab_size(const int p_size);
|
||||
int get_tab_size() const;
|
||||
void set_draw_tabs(bool p_draw);
|
||||
bool is_drawing_tabs() const;
|
||||
void set_draw_spaces(bool p_draw);
|
||||
|
|
Loading…
Reference in a new issue