Pārlūkot izejas kodu

Merge pull request #8424 from Paulb23/convert_indent

Support for space indentation
Rémi Verschelde 8 gadi atpakaļ
vecāks
revīzija
5237bc952d

+ 2 - 1
editor/code_editor.cpp

@@ -1071,7 +1071,8 @@ void CodeTextEditor::update_editor_settings() {
 
 	text_editor->set_auto_brace_completion(EditorSettings::get_singleton()->get("text_editor/completion/auto_brace_complete"));
 	text_editor->set_scroll_pass_end_of_file(EditorSettings::get_singleton()->get("text_editor/cursor/scroll_past_end_of_file"));
-	text_editor->set_tab_size(EditorSettings::get_singleton()->get("text_editor/indent/tab_size"));
+	text_editor->set_indent_using_spaces(EditorSettings::get_singleton()->get("text_editor/indent/type") == "Tabs" ? 0 : 1);
+	text_editor->set_indent_size(EditorSettings::get_singleton()->get("text_editor/indent/size"));
 	text_editor->set_draw_tabs(EditorSettings::get_singleton()->get("text_editor/indent/draw_tabs"));
 	text_editor->set_show_line_numbers(EditorSettings::get_singleton()->get("text_editor/line_numbers/show_line_numbers"));
 	text_editor->set_line_numbers_zero_padded(EditorSettings::get_singleton()->get("text_editor/line_numbers/line_numbers_zero_padded"));

+ 5 - 2
editor/editor_settings.cpp

@@ -529,8 +529,11 @@ void EditorSettings::_load_defaults(Ref<ConfigFile> p_extra_config) {
 	set("text_editor/highlighting/highlight_all_occurrences", true);
 	set("text_editor/cursor/scroll_past_end_of_file", false);
 
-	set("text_editor/indent/tab_size", 4);
-	hints["text_editor/indent/tab_size"] = PropertyInfo(Variant::INT, "text_editor/indent/tab_size", PROPERTY_HINT_RANGE, "1, 64, 1"); // size of 0 crashes.
+	set("text_editor/indent/type", 0);
+	hints["text_editor/indent/type"] = PropertyInfo(Variant::STRING, "text_editor/indent/type", PROPERTY_HINT_ENUM, "Tabs,Spaces");
+	set("text_editor/indent/size", 4);
+	hints["text_editor/indent/size"] = PropertyInfo(Variant::INT, "text_editor/indent/size", PROPERTY_HINT_RANGE, "1, 64, 1"); // size of 0 crashes.
+	set("text_editor/indent/convert_indent_on_save", false);
 	set("text_editor/indent/draw_tabs", true);
 
 	set("text_editor/line_numbers/show_line_numbers", true);

+ 38 - 0
editor/plugins/script_editor_plugin.cpp

@@ -530,6 +530,15 @@ void ScriptEditor::_resave_scripts(const String &p_str) {
 		if (trim_trailing_whitespace_on_save) {
 			se->trim_trailing_whitespace();
 		}
+
+		if (convert_indent_on_save) {
+			if (use_space_indentation) {
+				se->convert_indent_to_spaces();
+			} else {
+				se->convert_indent_to_tabs();
+			}
+		}
+
 		editor->save_resource(script);
 		se->tag_saved_version();
 	}
@@ -795,12 +804,28 @@ void ScriptEditor::_menu_option(int p_option) {
 
 				if (trim_trailing_whitespace_on_save)
 					current->trim_trailing_whitespace();
+
+				if (convert_indent_on_save) {
+					if (use_space_indentation) {
+						current->convert_indent_to_spaces();
+					} else {
+						current->convert_indent_to_tabs();
+					}
+				}
 				editor->save_resource(current->get_edited_script());
 
 			} break;
 			case FILE_SAVE_AS: {
 
 				current->trim_trailing_whitespace();
+
+				if (convert_indent_on_save) {
+					if (use_space_indentation) {
+						current->convert_indent_to_spaces();
+					} else {
+						current->convert_indent_to_tabs();
+					}
+				}
 				editor->push_item(current->get_edited_script()->cast_to<Object>());
 				editor->save_resource_as(current->get_edited_script());
 
@@ -1484,6 +1509,14 @@ void ScriptEditor::save_all_scripts() {
 			se->trim_trailing_whitespace();
 		}
 
+		if (convert_indent_on_save) {
+			if (use_space_indentation) {
+				se->convert_indent_to_spaces();
+			} else {
+				se->convert_indent_to_tabs();
+			}
+		}
+
 		Ref<Script> script = se->get_edited_script();
 		if (script.is_valid())
 			se->apply_code();
@@ -1583,6 +1616,9 @@ void ScriptEditor::_save_layout() {
 void ScriptEditor::_editor_settings_changed() {
 
 	trim_trailing_whitespace_on_save = EditorSettings::get_singleton()->get("text_editor/files/trim_trailing_whitespace_on_save");
+	convert_indent_on_save = EditorSettings::get_singleton()->get("text_editor/indent/convert_indent_on_save");
+	use_space_indentation = EditorSettings::get_singleton()->get("text_editor/indent/type") == "Tabs" ? 0 : 1;
+
 	float autosave_time = EditorSettings::get_singleton()->get("text_editor/files/autosave_interval_secs");
 	if (autosave_time > 0) {
 		autosave_timer->set_wait_time(autosave_time);
@@ -2161,6 +2197,8 @@ ScriptEditor::ScriptEditor(EditorNode *p_editor) {
 
 	edit_pass = 0;
 	trim_trailing_whitespace_on_save = false;
+	convert_indent_on_save = false;
+	use_space_indentation = false;
 
 	ScriptServer::edit_request_func = _open_script_request;
 }

+ 4 - 0
editor/plugins/script_editor_plugin.h

@@ -91,6 +91,8 @@ public:
 	virtual void set_edit_state(const Variant &p_state) = 0;
 	virtual void goto_line(int p_line, bool p_with_error = false) = 0;
 	virtual void trim_trailing_whitespace() = 0;
+	virtual void convert_indent_to_spaces() = 0;
+	virtual void convert_indent_to_tabs() = 0;
 	virtual void ensure_focus() = 0;
 	virtual void tag_saved_version() = 0;
 	virtual void reload(bool p_soft) = 0;
@@ -252,6 +254,8 @@ class ScriptEditor : public VBoxContainer {
 	void _res_saved_callback(const Ref<Resource> &p_res);
 
 	bool trim_trailing_whitespace_on_save;
+	bool use_space_indentation;
+	bool convert_indent_on_save;
 
 	void _trim_trailing_whitespace(TextEdit *tx);
 

+ 100 - 0
editor/plugins/script_text_editor.cpp

@@ -290,6 +290,96 @@ void ScriptTextEditor::trim_trailing_whitespace() {
 	}
 }
 
+void ScriptTextEditor::convert_indent_to_spaces() {
+	TextEdit *tx = code_editor->get_text_edit();
+	Ref<Script> scr = get_edited_script();
+
+	if (scr.is_null()) {
+		return;
+	}
+
+	int indent_size = EditorSettings::get_singleton()->get("text_editor/indent/size");
+	String indent = "";
+
+	for (int i = 0; i < indent_size; i++) {
+		indent += " ";
+	}
+
+	bool changed_indentation = false;
+	for (int i = 0; i < tx->get_line_count(); i++) {
+		String line = tx->get_line(i);
+
+		if (line.length() <= 0) {
+			continue;
+		}
+
+		int j = 0;
+		while (j < line.length() && (line[j] == ' ' || line[j] == '\t')) {
+			if (line[j] == '\t') {
+				if (!changed_indentation) {
+					tx->begin_complex_operation();
+					changed_indentation = true;
+				}
+				line = line.left(j) + indent + line.right(j + 1);
+			}
+			j++;
+		}
+		tx->set_line(i, line);
+	}
+	if (changed_indentation) {
+		tx->end_complex_operation();
+		tx->update();
+	}
+}
+
+void ScriptTextEditor::convert_indent_to_tabs() {
+	TextEdit *tx = code_editor->get_text_edit();
+	Ref<Script> scr = get_edited_script();
+
+	if (scr.is_null()) {
+		return;
+	}
+
+	int indent_size = EditorSettings::get_singleton()->get("text_editor/indent/size");
+	indent_size -= 1;
+
+	bool changed_indentation = false;
+	for (int i = 0; i < tx->get_line_count(); i++) {
+		String line = tx->get_line(i);
+
+		if (line.length() <= 0) {
+			continue;
+		}
+
+		int j = 0;
+		int space_count = -1;
+		while (j < line.length() && (line[j] == ' ' || line[j] == '\t')) {
+			if (line[j] != '\t') {
+				space_count++;
+
+				if (space_count == indent_size) {
+					if (!changed_indentation) {
+						tx->begin_complex_operation();
+						changed_indentation = true;
+					}
+
+					line = line.left(j - indent_size) + "\t" + line.right(j + 1);
+					j = 0;
+					space_count = -1;
+				}
+			} else {
+				space_count = -1;
+			}
+			j++;
+		}
+		tx->set_line(i, line);
+	}
+	if (changed_indentation) {
+		tx->end_complex_operation();
+		tx->update();
+	}
+}
+
 void ScriptTextEditor::tag_saved_version() {
 
 	code_editor->get_text_edit()->tag_saved_version();
@@ -827,6 +917,12 @@ void ScriptTextEditor::_edit_option(int p_op) {
 		case EDIT_TRIM_TRAILING_WHITESAPCE: {
 			trim_trailing_whitespace();
 		} break;
+		case EDIT_CONVERT_INDENT_TO_SPACES: {
+			convert_indent_to_spaces();
+		} break;
+		case EDIT_CONVERT_INDENT_TO_TABS: {
+			convert_indent_to_tabs();
+		} break;
 		case EDIT_PICK_COLOR: {
 			color_panel->popup();
 		} break;
@@ -1237,6 +1333,8 @@ ScriptTextEditor::ScriptTextEditor() {
 	edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/complete_symbol"), EDIT_COMPLETE);
 #endif
 	edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/trim_trailing_whitespace"), EDIT_TRIM_TRAILING_WHITESAPCE);
+	edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/convert_indent_to_spaces"), EDIT_CONVERT_INDENT_TO_SPACES);
+	edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/convert_indent_to_tabs"), EDIT_CONVERT_INDENT_TO_TABS);
 	edit_menu->get_popup()->add_shortcut(ED_GET_SHORTCUT("script_text_editor/auto_indent"), EDIT_AUTO_INDENT);
 	edit_menu->get_popup()->connect("id_pressed", this, "_edit_option");
 	edit_menu->get_popup()->add_separator();
@@ -1305,6 +1403,8 @@ void ScriptTextEditor::register_editor() {
 	ED_SHORTCUT("script_text_editor/complete_symbol", TTR("Complete Symbol"), KEY_MASK_CMD | KEY_SPACE);
 #endif
 	ED_SHORTCUT("script_text_editor/trim_trailing_whitespace", TTR("Trim Trailing Whitespace"), KEY_MASK_CTRL | KEY_MASK_ALT | KEY_T);
+	ED_SHORTCUT("script_text_editor/convert_indent_to_spaces", TTR("Convert Indent To Spaces"), KEY_MASK_CTRL | KEY_MASK_SHIFT | KEY_Y);
+	ED_SHORTCUT("script_text_editor/convert_indent_to_tabs", TTR("Convert Indent To Tabs"), KEY_MASK_CTRL | KEY_MASK_SHIFT | KEY_X);
 	ED_SHORTCUT("script_text_editor/auto_indent", TTR("Auto Indent"), KEY_MASK_CMD | KEY_I);
 
 	ED_SHORTCUT("script_text_editor/toggle_breakpoint", TTR("Toggle Breakpoint"), KEY_F9);

+ 4 - 0
editor/plugins/script_text_editor.h

@@ -67,6 +67,8 @@ class ScriptTextEditor : public ScriptEditorBase {
 		EDIT_COMPLETE,
 		EDIT_AUTO_INDENT,
 		EDIT_TRIM_TRAILING_WHITESAPCE,
+		EDIT_CONVERT_INDENT_TO_SPACES,
+		EDIT_CONVERT_INDENT_TO_TABS,
 		EDIT_TOGGLE_COMMENT,
 		EDIT_MOVE_LINE_UP,
 		EDIT_MOVE_LINE_DOWN,
@@ -125,6 +127,8 @@ public:
 	virtual void set_edit_state(const Variant &p_state);
 	virtual void ensure_focus();
 	virtual void trim_trailing_whitespace();
+	virtual void convert_indent_to_spaces();
+	virtual void convert_indent_to_tabs();
 	virtual void tag_saved_version();
 
 	virtual void goto_line(int p_line, bool p_with_error = false);

+ 2 - 1
editor/plugins/shader_editor_plugin.cpp

@@ -370,7 +370,8 @@ void ShaderEditor::_editor_settings_changed() {
 
 	shader_editor->get_text_edit()->set_auto_brace_completion(EditorSettings::get_singleton()->get("text_editor/completion/auto_brace_complete"));
 	shader_editor->get_text_edit()->set_scroll_pass_end_of_file(EditorSettings::get_singleton()->get("text_editor/cursor/scroll_past_end_of_file"));
-	shader_editor->get_text_edit()->set_tab_size(EditorSettings::get_singleton()->get("text_editor/indent/tab_size"));
+	shader_editor->get_text_edit()->set_indent_size(EditorSettings::get_singleton()->get("text_editor/indent/size"));
+	shader_editor->get_text_edit()->set_indent_using_spaces(EditorSettings::get_singleton()->get("text_editor/indent/type") == "Tabs" ? 0 : 1);
 	shader_editor->get_text_edit()->set_draw_tabs(EditorSettings::get_singleton()->get("text_editor/indent/draw_tabs"));
 	shader_editor->get_text_edit()->set_show_line_numbers(EditorSettings::get_singleton()->get("text_editor/line_numbers/show_line_numbers"));
 	shader_editor->get_text_edit()->set_syntax_coloring(EditorSettings::get_singleton()->get("text_editor/highlighting/syntax_highlighting"));

+ 23 - 2
modules/gdscript/gd_editor.cpp

@@ -27,6 +27,7 @@
 /* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE     */
 /* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.                */
 /*************************************************************************/
+#include "editor/editor_settings.h"
 #include "gd_compiler.h"
 #include "gd_script.h"
 #include "global_config.h"
@@ -2391,8 +2392,27 @@ Error GDScriptLanguage::complete_code(const String &p_code, const String &p_base
 
 #endif
 
+String GDScriptLanguage::_get_indentation() const {
+#ifdef TOOLS_ENABLED
+	bool use_space_indentation = EDITOR_DEF("text_editor/indent/type", "Tabs") == "Tabs" ? 0 : 1;
+
+	if (use_space_indentation) {
+		int indent_size = EDITOR_DEF("text_editor/indent/size", 4);
+
+		String space_indent = "";
+		for (int i = 0; i < indent_size; i++) {
+			space_indent += " ";
+		}
+		return space_indent;
+	}
+#endif
+	return "\t";
+}
+
 void GDScriptLanguage::auto_indent_code(String &p_code, int p_from_line, int p_to_line) const {
 
+	String indent = _get_indentation();
+
 	Vector<String> lines = p_code.split("\n");
 	List<int> indent_stack;
 
@@ -2432,8 +2452,9 @@ void GDScriptLanguage::auto_indent_code(String &p_code, int p_from_line, int p_t
 		if (i >= p_from_line) {
 
 			l = "";
-			for (int j = 0; j < indent_stack.size(); j++)
-				l += "\t";
+			for (int j = 0; j < indent_stack.size(); j++) {
+				l += indent;
+			}
 			l += st;
 
 		} else if (i > p_to_line) {

+ 1 - 0
modules/gdscript/gd_script.h

@@ -390,6 +390,7 @@ public:
 #ifdef TOOLS_ENABLED
 	virtual Error lookup_code(const String &p_code, const String &p_symbol, const String &p_base_path, Object *p_owner, LookupResult &r_result);
 #endif
+	virtual String _get_indentation() const;
 	virtual void auto_indent_code(String &p_code, int p_from_line, int p_to_line) const;
 	virtual void add_global_constant(const StringName &p_variable, const Variant &p_value);
 

+ 6 - 0
modules/visual_script/visual_script_editor.cpp

@@ -2163,6 +2163,12 @@ void VisualScriptEditor::goto_line(int p_line, bool p_with_error) {
 void VisualScriptEditor::trim_trailing_whitespace() {
 }
 
+void VisualScriptEditor::convert_indent_to_spaces() {
+}
+
+void VisualScriptEditor::convert_indent_to_tabs() {
+}
+
 void VisualScriptEditor::ensure_focus() {
 
 	graph->grab_focus();

+ 2 - 0
modules/visual_script/visual_script_editor.h

@@ -240,6 +240,8 @@ public:
 	virtual void set_edit_state(const Variant &p_state);
 	virtual void goto_line(int p_line, bool p_with_error = false);
 	virtual void trim_trailing_whitespace();
+	virtual void convert_indent_to_spaces();
+	virtual void convert_indent_to_tabs();
 	virtual void ensure_focus();
 	virtual void tag_saved_version();
 	virtual void reload(bool p_soft);

+ 117 - 23
scene/gui/text_edit.cpp

@@ -101,15 +101,15 @@ void TextEdit::Text::set_font(const Ref<Font> &p_font) {
 	font = p_font;
 }
 
-void TextEdit::Text::set_tab_size(int p_tab_size) {
+void TextEdit::Text::set_indent_size(int p_indent_size) {
 
-	tab_size = p_tab_size;
+	indent_size = p_indent_size;
 }
 
 void TextEdit::Text::_update_line_cache(int p_line) const {
 
 	int w = 0;
-	int tab_w = font->get_char_size(' ').width * tab_size;
+	int tab_w = font->get_char_size(' ').width * indent_size;
 
 	int len = text[p_line].data.length();
 	const CharType *str = text[p_line].data.c_str();
@@ -456,7 +456,7 @@ void TextEdit::_notification(int p_what) {
 
 			int visible_rows = get_visible_rows();
 
-			int tab_w = cache.font->get_char_size(' ').width * tab_size;
+			int tab_w = cache.font->get_char_size(' ').width * indent_size;
 
 			Color color = cache.font_color;
 			int in_region = -1;
@@ -1305,7 +1305,38 @@ 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 {
-		_remove_text(prev_line, prev_column, cursor.line, cursor.column);
+		// handle space indentation
+		if (cursor.column - indent_size >= 0 && indent_using_spaces) {
+
+			// if there is enough spaces to count as a tab
+			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') {
+					unindent = false;
+					break;
+				}
+				i++;
+			}
+
+			// then we can remove it as a single character.
+			if (unindent) {
+				_remove_text(cursor.line, cursor.column - indent_size, cursor.line, cursor.column);
+				prev_column = cursor.column - indent_size;
+			} else {
+				_remove_text(prev_line, prev_column, cursor.line, cursor.column);
+			}
+		} else {
+			_remove_text(prev_line, prev_column, cursor.line, cursor.column);
+		}
 	}
 
 	cursor_set_line(prev_line);
@@ -1328,7 +1359,11 @@ void TextEdit::indent_selection_right() {
 
 	for (int i = start_line; i <= end_line; i++) {
 		String line_text = get_line(i);
-		line_text = '\t' + line_text;
+		if (indent_using_spaces) {
+			line_text = space_indent + line_text;
+		} else {
+			line_text = '\t' + line_text;
+		}
 		set_line(i, line_text);
 	}
 
@@ -1359,8 +1394,8 @@ void TextEdit::indent_selection_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("    ")) {
-			line_text = line_text.substr(4, line_text.length());
+		} else if (line_text.begins_with(space_indent)) {
+			line_text = line_text.substr(indent_size, line_text.length());
 			set_line(i, line_text);
 		}
 	}
@@ -1931,17 +1966,39 @@ void TextEdit::_gui_input(const InputEvent &p_gui_input) {
 					String ins = "\n";
 
 					//keep indentation
+					int space_count = 0;
 					for (int i = 0; i < text[cursor.line].length(); i++) {
-						if (text[cursor.line][i] == '\t')
-							ins += "\t";
-						else
+						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;
+						}
 					}
 					if (auto_indent) {
 						// indent once again if previous line will end with ':'
 						// (i.e. colon precedes current cursor position)
 						if (cursor.column > 0 && text[cursor.line][cursor.column - 1] == ':') {
-							ins += "\t";
+							if (indent_using_spaces) {
+								ins += space_indent;
+							} else {
+								ins += "\t";
+							}
 						}
 					}
 
@@ -1987,15 +2044,36 @@ void TextEdit::_gui_input(const InputEvent &p_gui_input) {
 					} else {
 						if (k.mod.shift) {
 
+							//simple unindent
 							int cc = cursor.column;
-							if (cc > 0 && cc <= text[cursor.line].length() && text[cursor.line][cursor.column - 1] == '\t') {
-								//simple unindent
+							if (cc > 0 && cc <= text[cursor.line].length()) {
+								if (text[cursor.line][cursor.column - 1] == '\t') {
+									backspace_at_cursor();
+								} else {
+									if (cursor.column - indent_size >= 0) {
+
+										bool unindent = true;
+										for (int i = 1; i <= indent_size; i++) {
+											if (text[cursor.line][cursor.column - i] != ' ') {
+												unindent = false;
+												break;
+											}
+										}
 
-								backspace_at_cursor();
+										if (unindent) {
+											_remove_text(cursor.line, cursor.column - indent_size, cursor.line, cursor.column);
+											cursor_set_column(cursor.column - indent_size);
+										}
+									}
+								}
 							}
 						} else {
 							//simple indent
-							_insert_text_at_cursor("\t");
+							if (indent_using_spaces) {
+								_insert_text_at_cursor(space_indent);
+							} else {
+								_insert_text_at_cursor("\t");
+							}
 						}
 					}
 
@@ -3103,7 +3181,7 @@ int TextEdit::get_char_pos_for(int p_px, String p_str) const {
 	int px = 0;
 	int c = 0;
 
-	int tab_w = cache.font->get_char_size(' ').width * tab_size;
+	int tab_w = cache.font->get_char_size(' ').width * indent_size;
 
 	while (c < p_str.length()) {
 
@@ -3135,7 +3213,7 @@ int TextEdit::get_column_x_offset(int p_char, String p_str) {
 
 	int px = 0;
 
-	int tab_w = cache.font->get_char_size(' ').width * tab_size;
+	int tab_w = cache.font->get_char_size(' ').width * indent_size;
 
 	for (int i = 0; i < p_char; i++) {
 
@@ -3952,10 +4030,24 @@ void TextEdit::_push_current_op() {
 	current_op.chain_forward = false;
 }
 
-void TextEdit::set_tab_size(const int p_size) {
+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(p_size <= 0);
-	tab_size = p_size;
-	text.set_tab_size(p_size);
+	indent_size = p_size;
+	text.set_indent_size(p_size);
+
+	space_indent = "";
+	for (int i = 0; i < p_size; i++) {
+		space_indent += " ";
+	}
+
 	update();
 }
 
@@ -4542,8 +4634,8 @@ TextEdit::TextEdit() {
 	cache.breakpoint_gutter_width = 0;
 	breakpoint_gutter_width = 0;
 
-	tab_size = 4;
-	text.set_tab_size(tab_size);
+	indent_size = 4;
+	text.set_indent_size(indent_size);
 	text.clear();
 	//text.insert(1,"Mongolia..");
 	//text.insert(2,"PAIS GENEROSO!!");
@@ -4631,6 +4723,8 @@ TextEdit::TextEdit() {
 	auto_brace_completion_enabled = false;
 	brace_matching_enabled = false;
 	highlight_all_occurrences = false;
+	indent_using_spaces = false;
+	space_indent = "    ";
 	auto_indent = false;
 	insert_mode = false;
 	window_has_focus = true;

+ 9 - 5
scene/gui/text_edit.h

@@ -141,12 +141,12 @@ class TextEdit : public Control {
 		const Vector<ColorRegion> *color_regions;
 		mutable Vector<Line> text;
 		Ref<Font> font;
-		int tab_size;
+		int indent_size;
 
 		void _update_line_cache(int p_line) const;
 
 	public:
-		void set_tab_size(int p_tab_size);
+		void set_indent_size(int p_indent_size);
 		void set_font(const Ref<Font> &p_font);
 		void set_color_regions(const Vector<ColorRegion> *p_regions) { color_regions = p_regions; }
 		int get_line_width(int p_line) const;
@@ -163,7 +163,7 @@ class TextEdit : public Control {
 		void clear();
 		void clear_caches();
 		_FORCE_INLINE_ const String &operator[](int p_line) const { return text[p_line].data; }
-		Text() { tab_size = 4; }
+		Text() { indent_size = 4; }
 	};
 
 	struct TextOperation {
@@ -221,7 +221,9 @@ class TextEdit : public Control {
 	int max_chars;
 	bool readonly;
 	bool syntax_coloring;
-	int tab_size;
+	bool indent_using_spaces;
+	int indent_size;
+	String space_indent;
 
 	Timer *caret_blink_timer;
 	bool caret_blink_enabled;
@@ -461,7 +463,9 @@ public:
 	void redo();
 	void clear_undo_history();
 
-	void set_tab_size(const int p_size);
+	void set_indent_using_spaces(const bool p_use_spaces);
+	bool is_indent_using_spaces() const;
+	void set_indent_size(const int p_size);
 	void set_draw_tabs(bool p_draw);
 	bool is_drawing_tabs() const;