From 765d6752bb6ae59d0b19d0d2b602ef2fcb98385b Mon Sep 17 00:00:00 2001
From: Paulb23 <p_batty@hotmail.co.uk>
Date: Fri, 25 May 2018 23:49:35 +0100
Subject: [PATCH] Refactored text manipulation into CodeTexteditor

---
 editor/code_editor.cpp                  | 339 ++++++++++++++++++++++
 editor/code_editor.h                    |  23 ++
 editor/plugins/script_text_editor.cpp   | 365 ++----------------------
 editor/plugins/script_text_editor.h     |   7 +-
 editor/plugins/shader_editor_plugin.cpp | 127 +--------
 5 files changed, 388 insertions(+), 473 deletions(-)

diff --git a/editor/code_editor.cpp b/editor/code_editor.cpp
index 6aec6135f14..925f97de8e3 100644
--- a/editor/code_editor.cpp
+++ b/editor/code_editor.cpp
@@ -784,6 +784,345 @@ void CodeTextEditor::update_editor_settings() {
 	text_editor->set_v_scroll_speed(EditorSettings::get_singleton()->get("text_editor/open_scripts/v_scroll_speed"));
 }
 
+void CodeTextEditor::trim_trailing_whitespace() {
+	bool trimed_whitespace = false;
+	for (int i = 0; i < text_editor->get_line_count(); i++) {
+		String line = text_editor->get_line(i);
+		if (line.ends_with(" ") || line.ends_with("\t")) {
+
+			if (!trimed_whitespace) {
+				text_editor->begin_complex_operation();
+				trimed_whitespace = true;
+			}
+
+			int end = 0;
+			for (int j = line.length() - 1; j > -1; j--) {
+				if (line[j] != ' ' && line[j] != '\t') {
+					end = j + 1;
+					break;
+				}
+			}
+			text_editor->set_line(i, line.substr(0, end));
+		}
+	}
+
+	if (trimed_whitespace) {
+		text_editor->end_complex_operation();
+		text_editor->update();
+	}
+}
+
+void CodeTextEditor::convert_indent_to_spaces() {
+	int indent_size = EditorSettings::get_singleton()->get("text_editor/indent/size");
+	String indent = "";
+
+	for (int i = 0; i < indent_size; i++) {
+		indent += " ";
+	}
+
+	int cursor_line = text_editor->cursor_get_line();
+	int cursor_column = text_editor->cursor_get_column();
+
+	bool changed_indentation = false;
+	for (int i = 0; i < text_editor->get_line_count(); i++) {
+		String line = text_editor->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) {
+					text_editor->begin_complex_operation();
+					changed_indentation = true;
+				}
+				if (cursor_line == i && cursor_column > j) {
+					cursor_column += indent_size - 1;
+				}
+				line = line.left(j) + indent + line.right(j + 1);
+			}
+			j++;
+		}
+		if (changed_indentation) {
+			text_editor->set_line(i, line);
+		}
+	}
+	if (changed_indentation) {
+		text_editor->cursor_set_column(cursor_column);
+		text_editor->end_complex_operation();
+		text_editor->update();
+	}
+}
+
+void CodeTextEditor::convert_indent_to_tabs() {
+	int indent_size = EditorSettings::get_singleton()->get("text_editor/indent/size");
+	indent_size -= 1;
+
+	int cursor_line = text_editor->cursor_get_line();
+	int cursor_column = text_editor->cursor_get_column();
+
+	bool changed_indentation = false;
+	for (int i = 0; i < text_editor->get_line_count(); i++) {
+		String line = text_editor->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) {
+						text_editor->begin_complex_operation();
+						changed_indentation = true;
+					}
+					if (cursor_line == i && cursor_column > j) {
+						cursor_column -= indent_size;
+					}
+					line = line.left(j - indent_size) + "\t" + line.right(j + 1);
+					j = 0;
+					space_count = -1;
+				}
+			} else {
+				space_count = -1;
+			}
+			j++;
+		}
+		if (changed_indentation) {
+			text_editor->set_line(i, line);
+		}
+	}
+	if (changed_indentation) {
+		text_editor->cursor_set_column(cursor_column);
+		text_editor->end_complex_operation();
+		text_editor->update();
+	}
+}
+
+void CodeTextEditor::convert_case(CaseStyle p_case) {
+	if (!text_editor->is_selection_active()) {
+		return;
+	}
+
+	text_editor->begin_complex_operation();
+
+	int begin = text_editor->get_selection_from_line();
+	int end = text_editor->get_selection_to_line();
+	int begin_col = text_editor->get_selection_from_column();
+	int end_col = text_editor->get_selection_to_column();
+
+	for (int i = begin; i <= end; i++) {
+		int len = text_editor->get_line(i).length();
+		if (i == end)
+			len -= len - end_col;
+		if (i == begin)
+			len -= begin_col;
+		String new_line = text_editor->get_line(i).substr(i == begin ? begin_col : 0, len);
+
+		switch (p_case) {
+			case UPPER: {
+				new_line = new_line.to_upper();
+			} break;
+			case LOWER: {
+				new_line = new_line.to_lower();
+			} break;
+			case CAPITALIZE: {
+				new_line = new_line.capitalize();
+			} break;
+		}
+
+		if (i == begin) {
+			new_line = text_editor->get_line(i).left(begin_col) + new_line;
+		}
+		if (i == end) {
+			new_line = new_line + text_editor->get_line(i).right(end_col);
+		}
+		text_editor->set_line(i, new_line);
+	}
+	text_editor->end_complex_operation();
+}
+
+void CodeTextEditor::move_lines_up() {
+	text_editor->begin_complex_operation();
+	if (text_editor->is_selection_active()) {
+		int from_line = text_editor->get_selection_from_line();
+		int from_col = text_editor->get_selection_from_column();
+		int to_line = text_editor->get_selection_to_line();
+		int to_column = text_editor->get_selection_to_column();
+
+		for (int i = from_line; i <= to_line; i++) {
+			int line_id = i;
+			int next_id = i - 1;
+
+			if (line_id == 0 || next_id < 0)
+				return;
+
+			text_editor->unfold_line(line_id);
+			text_editor->unfold_line(next_id);
+
+			text_editor->swap_lines(line_id, next_id);
+			text_editor->cursor_set_line(next_id);
+		}
+		int from_line_up = from_line > 0 ? from_line - 1 : from_line;
+		int to_line_up = to_line > 0 ? to_line - 1 : to_line;
+		text_editor->select(from_line_up, from_col, to_line_up, to_column);
+	} else {
+		int line_id = text_editor->cursor_get_line();
+		int next_id = line_id - 1;
+
+		if (line_id == 0 || next_id < 0)
+			return;
+
+		text_editor->unfold_line(line_id);
+		text_editor->unfold_line(next_id);
+
+		text_editor->swap_lines(line_id, next_id);
+		text_editor->cursor_set_line(next_id);
+	}
+	text_editor->end_complex_operation();
+	text_editor->update();
+}
+
+void CodeTextEditor::move_lines_down() {
+	text_editor->begin_complex_operation();
+	if (text_editor->is_selection_active()) {
+		int from_line = text_editor->get_selection_from_line();
+		int from_col = text_editor->get_selection_from_column();
+		int to_line = text_editor->get_selection_to_line();
+		int to_column = text_editor->get_selection_to_column();
+
+		for (int i = to_line; i >= from_line; i--) {
+			int line_id = i;
+			int next_id = i + 1;
+
+			if (line_id == text_editor->get_line_count() - 1 || next_id > text_editor->get_line_count())
+				return;
+
+			text_editor->unfold_line(line_id);
+			text_editor->unfold_line(next_id);
+
+			text_editor->swap_lines(line_id, next_id);
+			text_editor->cursor_set_line(next_id);
+		}
+		int from_line_down = from_line < text_editor->get_line_count() ? from_line + 1 : from_line;
+		int to_line_down = to_line < text_editor->get_line_count() ? to_line + 1 : to_line;
+		text_editor->select(from_line_down, from_col, to_line_down, to_column);
+	} else {
+		int line_id = text_editor->cursor_get_line();
+		int next_id = line_id + 1;
+
+		if (line_id == text_editor->get_line_count() - 1 || next_id > text_editor->get_line_count())
+			return;
+
+		text_editor->unfold_line(line_id);
+		text_editor->unfold_line(next_id);
+
+		text_editor->swap_lines(line_id, next_id);
+		text_editor->cursor_set_line(next_id);
+	}
+	text_editor->end_complex_operation();
+	text_editor->update();
+}
+
+void CodeTextEditor::delete_lines() {
+	text_editor->begin_complex_operation();
+	if (text_editor->is_selection_active()) {
+		int to_line = text_editor->get_selection_to_line();
+		int from_line = text_editor->get_selection_from_line();
+		int count = Math::abs(to_line - from_line) + 1;
+		while (count) {
+			text_editor->set_line(text_editor->cursor_get_line(), "");
+			text_editor->backspace_at_cursor();
+			count--;
+			if (count)
+				text_editor->unfold_line(from_line);
+		}
+		text_editor->cursor_set_line(from_line - 1);
+		text_editor->deselect();
+	} else {
+		int line = text_editor->cursor_get_line();
+		text_editor->set_line(text_editor->cursor_get_line(), "");
+		text_editor->backspace_at_cursor();
+		text_editor->unfold_line(line);
+		text_editor->cursor_set_line(line);
+	}
+	text_editor->end_complex_operation();
+}
+
+void CodeTextEditor::code_lines_down() {
+	int from_line = text_editor->cursor_get_line();
+	int to_line = text_editor->cursor_get_line();
+	int column = text_editor->cursor_get_column();
+
+	if (text_editor->is_selection_active()) {
+		from_line = text_editor->get_selection_from_line();
+		to_line = text_editor->get_selection_to_line();
+		column = text_editor->cursor_get_column();
+	}
+	int next_line = to_line + 1;
+
+	if (to_line >= text_editor->get_line_count() - 1) {
+		text_editor->set_line(to_line, text_editor->get_line(to_line) + "\n");
+	}
+
+	text_editor->begin_complex_operation();
+	for (int i = from_line; i <= to_line; i++) {
+
+		text_editor->unfold_line(i);
+		if (i >= text_editor->get_line_count() - 1) {
+			text_editor->set_line(i, text_editor->get_line(i) + "\n");
+		}
+		String line_clone = text_editor->get_line(i);
+		text_editor->insert_at(line_clone, next_line);
+		next_line++;
+	}
+
+	text_editor->cursor_set_column(column);
+	if (text_editor->is_selection_active()) {
+		text_editor->select(to_line + 1, text_editor->get_selection_from_column(), next_line - 1, text_editor->get_selection_to_column());
+	}
+
+	text_editor->end_complex_operation();
+	text_editor->update();
+}
+
+void CodeTextEditor::goto_line(int p_line) {
+	text_editor->deselect();
+	text_editor->unfold_line(p_line);
+	text_editor->call_deferred("cursor_set_line", p_line);
+}
+
+void CodeTextEditor::goto_line_selection(int p_line, int p_begin, int p_end) {
+	text_editor->unfold_line(p_line);
+	text_editor->call_deferred("cursor_set_line", p_line);
+	text_editor->call_deferred("cursor_set_column", p_begin);
+	text_editor->select(p_line, p_begin, p_line, p_end);
+}
+
+Variant CodeTextEditor::get_edit_state() {
+	Dictionary state;
+
+	state["scroll_position"] = text_editor->get_v_scroll();
+	state["column"] = text_editor->cursor_get_column();
+	state["row"] = text_editor->cursor_get_line();
+
+	return state;
+}
+
+void CodeTextEditor::set_edit_state(const Variant &p_state) {
+	Dictionary state = p_state;
+	text_editor->cursor_set_column(state["column"]);
+	text_editor->cursor_set_line(state["row"]);
+	text_editor->set_v_scroll(state["scroll_position"]);
+	text_editor->grab_focus();
+}
+
 void CodeTextEditor::set_error(const String &p_error) {
 
 	error->set_text(p_error);
diff --git a/editor/code_editor.h b/editor/code_editor.h
index 2a3bb1ba76f..903f61d87d8 100644
--- a/editor/code_editor.h
+++ b/editor/code_editor.h
@@ -186,6 +186,29 @@ protected:
 	static void _bind_methods();
 
 public:
+	void trim_trailing_whitespace();
+
+	void convert_indent_to_spaces();
+	void convert_indent_to_tabs();
+
+	enum CaseStyle {
+		UPPER,
+		LOWER,
+		CAPITALIZE,
+	};
+	void convert_case(CaseStyle p_case);
+
+	void move_lines_up();
+	void move_lines_down();
+	void delete_lines();
+	void code_lines_down();
+
+	void goto_line(int p_line);
+	void goto_line_selection(int p_line, int p_begin, int p_end);
+
+	Variant get_edit_state();
+	void set_edit_state(const Variant &p_state);
+
 	void update_editor_settings();
 	void set_error(const String &p_error);
 	void update_line_and_column() { _line_col_changed(); }
diff --git a/editor/plugins/script_text_editor.cpp b/editor/plugins/script_text_editor.cpp
index 2263d782d93..08aba47a569 100644
--- a/editor/plugins/script_text_editor.cpp
+++ b/editor/plugins/script_text_editor.cpp
@@ -190,6 +190,7 @@ void ScriptTextEditor::_set_theme_for_script() {
 
 	List<String> keywords;
 	script->get_language()->get_reserved_words(&keywords);
+
 	for (List<String>::Element *E = keywords.front(); E; E = E->next()) {
 
 		text_edit->add_keyword_color(E->get(), colors_cache.keyword_color);
@@ -251,7 +252,6 @@ void ScriptTextEditor::_set_theme_for_script() {
 	//colorize strings
 	List<String> strings;
 	script->get_language()->get_string_delimiters(&strings);
-
 	for (List<String>::Element *E = strings.front(); E; E = E->next()) {
 
 		String string = E->get();
@@ -326,197 +326,32 @@ bool ScriptTextEditor::is_unsaved() {
 
 Variant ScriptTextEditor::get_edit_state() {
 
-	Dictionary state;
-
-	state["scroll_position"] = code_editor->get_text_edit()->get_v_scroll();
-	state["column"] = code_editor->get_text_edit()->cursor_get_column();
-	state["row"] = code_editor->get_text_edit()->cursor_get_line();
-
-	return state;
+	return code_editor->get_edit_state();
 }
 
-void ScriptTextEditor::_convert_case(CaseStyle p_case) {
-	TextEdit *te = code_editor->get_text_edit();
-	Ref<Script> scr = get_edited_script();
-	if (scr.is_null()) {
-		return;
-	}
+void ScriptTextEditor::set_edit_state(const Variant &p_state) {
 
-	if (te->is_selection_active()) {
-		te->begin_complex_operation();
+	code_editor->set_edit_state(p_state);
+}
 
-		int begin = te->get_selection_from_line();
-		int end = te->get_selection_to_line();
-		int begin_col = te->get_selection_from_column();
-		int end_col = te->get_selection_to_column();
+void ScriptTextEditor::_convert_case(CodeTextEditor::CaseStyle p_case) {
 
-		for (int i = begin; i <= end; i++) {
-			int len = te->get_line(i).length();
-			if (i == end)
-				len -= len - end_col;
-			if (i == begin)
-				len -= begin_col;
-			String new_line = te->get_line(i).substr(i == begin ? begin_col : 0, len);
-
-			switch (p_case) {
-				case UPPER: {
-					new_line = new_line.to_upper();
-				} break;
-				case LOWER: {
-					new_line = new_line.to_lower();
-				} break;
-				case CAPITALIZE: {
-					new_line = new_line.capitalize();
-				} break;
-			}
-
-			if (i == begin) {
-				new_line = te->get_line(i).left(begin_col) + new_line;
-			}
-			if (i == end) {
-				new_line = new_line + te->get_line(i).right(end_col);
-			}
-			te->set_line(i, new_line);
-		}
-		te->end_complex_operation();
-	}
+	code_editor->convert_case(p_case);
 }
 
 void ScriptTextEditor::trim_trailing_whitespace() {
 
-	TextEdit *tx = code_editor->get_text_edit();
-
-	bool trimed_whitespace = false;
-	for (int i = 0; i < tx->get_line_count(); i++) {
-		String line = tx->get_line(i);
-		if (line.ends_with(" ") || line.ends_with("\t")) {
-
-			if (!trimed_whitespace) {
-				tx->begin_complex_operation();
-				trimed_whitespace = true;
-			}
-
-			int end = 0;
-			for (int j = line.length() - 1; j > -1; j--) {
-				if (line[j] != ' ' && line[j] != '\t') {
-					end = j + 1;
-					break;
-				}
-			}
-			tx->set_line(i, line.substr(0, end));
-		}
-	}
-	if (trimed_whitespace) {
-		tx->end_complex_operation();
-		tx->update();
-	}
+	code_editor->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 += " ";
-	}
-
-	int cursor_line = tx->cursor_get_line();
-	int cursor_column = tx->cursor_get_column();
-
-	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;
-				}
-				if (cursor_line == i && cursor_column > j) {
-					cursor_column += indent_size - 1;
-				}
-				line = line.left(j) + indent + line.right(j + 1);
-			}
-			j++;
-		}
-		if (changed_indentation) {
-			tx->set_line(i, line);
-		}
-	}
-	if (changed_indentation) {
-		tx->cursor_set_column(cursor_column);
-		tx->end_complex_operation();
-		tx->update();
-	}
+	code_editor->convert_indent_to_spaces();
 }
 
 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;
-
-	int cursor_line = tx->cursor_get_line();
-	int cursor_column = tx->cursor_get_column();
-
-	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;
-					}
-					if (cursor_line == i && cursor_column > j) {
-						cursor_column -= indent_size;
-					}
-					line = line.left(j - indent_size) + "\t" + line.right(j + 1);
-					j = 0;
-					space_count = -1;
-				}
-			} else {
-				space_count = -1;
-			}
-			j++;
-		}
-		if (changed_indentation) {
-			tx->set_line(i, line);
-		}
-	}
-	if (changed_indentation) {
-		tx->cursor_set_column(cursor_column);
-		tx->end_complex_operation();
-		tx->update();
-	}
+	code_editor->convert_indent_to_tabs();
 }
 
 void ScriptTextEditor::tag_saved_version() {
@@ -525,18 +360,13 @@ void ScriptTextEditor::tag_saved_version() {
 }
 
 void ScriptTextEditor::goto_line(int p_line, bool p_with_error) {
-	TextEdit *tx = code_editor->get_text_edit();
-	tx->deselect();
-	tx->unfold_line(p_line);
-	tx->call_deferred("cursor_set_line", p_line);
+
+	code_editor->goto_line(p_line);
 }
 
 void ScriptTextEditor::goto_line_selection(int p_line, int p_begin, int p_end) {
-	TextEdit *tx = code_editor->get_text_edit();
-	tx->unfold_line(p_line);
-	tx->call_deferred("cursor_set_line", p_line);
-	tx->call_deferred("cursor_set_column", p_begin);
-	tx->select(p_line, p_begin, p_line, p_end);
+
+	code_editor->goto_line_selection(p_line, p_begin, p_end);
 }
 
 void ScriptTextEditor::ensure_focus() {
@@ -544,15 +374,6 @@ void ScriptTextEditor::ensure_focus() {
 	code_editor->get_text_edit()->grab_focus();
 }
 
-void ScriptTextEditor::set_edit_state(const Variant &p_state) {
-
-	Dictionary state = p_state;
-	code_editor->get_text_edit()->cursor_set_column(state["column"]);
-	code_editor->get_text_edit()->cursor_set_line(state["row"]);
-	code_editor->get_text_edit()->set_v_scroll(state["scroll_position"]);
-	code_editor->get_text_edit()->grab_focus();
-}
-
 String ScriptTextEditor::get_name() {
 	String name;
 
@@ -878,94 +699,11 @@ void ScriptTextEditor::_edit_option(int p_op) {
 		} break;
 		case EDIT_MOVE_LINE_UP: {
 
-			Ref<Script> scr = script;
-			if (scr.is_null())
-				return;
-
-			tx->begin_complex_operation();
-			if (tx->is_selection_active()) {
-				int from_line = tx->get_selection_from_line();
-				int from_col = tx->get_selection_from_column();
-				int to_line = tx->get_selection_to_line();
-				int to_column = tx->get_selection_to_column();
-
-				for (int i = from_line; i <= to_line; i++) {
-					int line_id = i;
-					int next_id = i - 1;
-
-					if (line_id == 0 || next_id < 0)
-						return;
-
-					tx->unfold_line(line_id);
-					tx->unfold_line(next_id);
-
-					tx->swap_lines(line_id, next_id);
-					tx->cursor_set_line(next_id);
-				}
-				int from_line_up = from_line > 0 ? from_line - 1 : from_line;
-				int to_line_up = to_line > 0 ? to_line - 1 : to_line;
-				tx->select(from_line_up, from_col, to_line_up, to_column);
-			} else {
-				int line_id = tx->cursor_get_line();
-				int next_id = line_id - 1;
-
-				if (line_id == 0 || next_id < 0)
-					return;
-
-				tx->unfold_line(line_id);
-				tx->unfold_line(next_id);
-
-				tx->swap_lines(line_id, next_id);
-				tx->cursor_set_line(next_id);
-			}
-			tx->end_complex_operation();
-			tx->update();
+			code_editor->move_lines_up();
 		} break;
 		case EDIT_MOVE_LINE_DOWN: {
 
-			Ref<Script> scr = get_edited_script();
-			if (scr.is_null())
-				return;
-
-			tx->begin_complex_operation();
-			if (tx->is_selection_active()) {
-				int from_line = tx->get_selection_from_line();
-				int from_col = tx->get_selection_from_column();
-				int to_line = tx->get_selection_to_line();
-				int to_column = tx->get_selection_to_column();
-
-				for (int i = to_line; i >= from_line; i--) {
-					int line_id = i;
-					int next_id = i + 1;
-
-					if (line_id == tx->get_line_count() - 1 || next_id > tx->get_line_count())
-						return;
-
-					tx->unfold_line(line_id);
-					tx->unfold_line(next_id);
-
-					tx->swap_lines(line_id, next_id);
-					tx->cursor_set_line(next_id);
-				}
-				int from_line_down = from_line < tx->get_line_count() ? from_line + 1 : from_line;
-				int to_line_down = to_line < tx->get_line_count() ? to_line + 1 : to_line;
-				tx->select(from_line_down, from_col, to_line_down, to_column);
-			} else {
-				int line_id = tx->cursor_get_line();
-				int next_id = line_id + 1;
-
-				if (line_id == tx->get_line_count() - 1 || next_id > tx->get_line_count())
-					return;
-
-				tx->unfold_line(line_id);
-				tx->unfold_line(next_id);
-
-				tx->swap_lines(line_id, next_id);
-				tx->cursor_set_line(next_id);
-			}
-			tx->end_complex_operation();
-			tx->update();
-
+			code_editor->move_lines_down();
 		} break;
 		case EDIT_INDENT_LEFT: {
 
@@ -985,72 +723,11 @@ void ScriptTextEditor::_edit_option(int p_op) {
 		} break;
 		case EDIT_DELETE_LINE: {
 
-			Ref<Script> scr = get_edited_script();
-			if (scr.is_null())
-				return;
-			tx->begin_complex_operation();
-			if (tx->is_selection_active()) {
-				int to_line = tx->get_selection_to_line();
-				int from_line = tx->get_selection_from_line();
-				int count = Math::abs(to_line - from_line) + 1;
-				while (count) {
-					tx->set_line(tx->cursor_get_line(), "");
-					tx->backspace_at_cursor();
-					count--;
-					if (count)
-						tx->unfold_line(from_line);
-				}
-				tx->cursor_set_line(from_line - 1);
-				tx->deselect();
-			} else {
-				int line = tx->cursor_get_line();
-				tx->set_line(tx->cursor_get_line(), "");
-				tx->backspace_at_cursor();
-				tx->unfold_line(line);
-				tx->cursor_set_line(line);
-			}
-			tx->end_complex_operation();
+			code_editor->delete_lines();
 		} break;
 		case EDIT_CLONE_DOWN: {
 
-			Ref<Script> scr = get_edited_script();
-			if (scr.is_null())
-				return;
-
-			int from_line = tx->cursor_get_line();
-			int to_line = tx->cursor_get_line();
-			int column = tx->cursor_get_column();
-
-			if (tx->is_selection_active()) {
-				from_line = tx->get_selection_from_line();
-				to_line = tx->get_selection_to_line();
-				column = tx->cursor_get_column();
-			}
-			int next_line = to_line + 1;
-
-			if (to_line >= tx->get_line_count() - 1) {
-				tx->set_line(to_line, tx->get_line(to_line) + "\n");
-			}
-
-			tx->begin_complex_operation();
-			for (int i = from_line; i <= to_line; i++) {
-
-				tx->unfold_line(i);
-				if (i >= tx->get_line_count() - 1) {
-					tx->set_line(i, tx->get_line(i) + "\n");
-				}
-				String line_clone = tx->get_line(i);
-				tx->insert_at(line_clone, next_line);
-				next_line++;
-			}
-
-			tx->cursor_set_column(column);
-			if (tx->is_selection_active()) {
-				tx->select(to_line + 1, tx->get_selection_from_column(), next_line - 1, tx->get_selection_to_column());
-			}
-
-			tx->end_complex_operation();
-			tx->update();
+			code_editor->code_lines_down();
 		} break;
 		case EDIT_TOGGLE_FOLD_LINE: {
 
@@ -1180,15 +857,15 @@ void ScriptTextEditor::_edit_option(int p_op) {
 		} break;
 		case EDIT_TO_UPPERCASE: {
 
-			_convert_case(UPPER);
+			_convert_case(CodeTextEditor::UPPER);
 		} break;
 		case EDIT_TO_LOWERCASE: {
 
-			_convert_case(LOWER);
+			_convert_case(CodeTextEditor::LOWER);
 		} break;
 		case EDIT_CAPITALIZE: {
 
-			_convert_case(CAPITALIZE);
+			_convert_case(CodeTextEditor::CAPITALIZE);
 		} break;
 		case SEARCH_FIND: {
 
diff --git a/editor/plugins/script_text_editor.h b/editor/plugins/script_text_editor.h
index a415f478e8b..30420521c4b 100644
--- a/editor/plugins/script_text_editor.h
+++ b/editor/plugins/script_text_editor.h
@@ -138,12 +138,7 @@ protected:
 	void _goto_line(int p_line) { goto_line(p_line); }
 	void _lookup_symbol(const String &p_symbol, int p_row, int p_column);
 
-	enum CaseStyle {
-		UPPER,
-		LOWER,
-		CAPITALIZE,
-	};
-	void _convert_case(CaseStyle p_case);
+	void _convert_case(CodeTextEditor::CaseStyle p_case);
 
 	Variant get_drag_data_fw(const Point2 &p_point, Control *p_from);
 	bool can_drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from) const;
diff --git a/editor/plugins/shader_editor_plugin.cpp b/editor/plugins/shader_editor_plugin.cpp
index 4b7f27c0c1a..7650cd6ae78 100644
--- a/editor/plugins/shader_editor_plugin.cpp
+++ b/editor/plugins/shader_editor_plugin.cpp
@@ -258,84 +258,10 @@ void ShaderEditor::_menu_option(int p_option) {
 			shader_editor->get_text_edit()->select_all();
 		} break;
 		case EDIT_MOVE_LINE_UP: {
-
-			TextEdit *tx = shader_editor->get_text_edit();
-			if (shader.is_null())
-				return;
-
-			tx->begin_complex_operation();
-			if (tx->is_selection_active()) {
-				int from_line = tx->get_selection_from_line();
-				int from_col = tx->get_selection_from_column();
-				int to_line = tx->get_selection_to_line();
-				int to_column = tx->get_selection_to_column();
-
-				for (int i = from_line; i <= to_line; i++) {
-					int line_id = i;
-					int next_id = i - 1;
-
-					if (line_id == 0 || next_id < 0)
-						return;
-
-					tx->swap_lines(line_id, next_id);
-					tx->cursor_set_line(next_id);
-				}
-				int from_line_up = from_line > 0 ? from_line - 1 : from_line;
-				int to_line_up = to_line > 0 ? to_line - 1 : to_line;
-				tx->select(from_line_up, from_col, to_line_up, to_column);
-			} else {
-				int line_id = tx->cursor_get_line();
-				int next_id = line_id - 1;
-
-				if (line_id == 0 || next_id < 0)
-					return;
-
-				tx->swap_lines(line_id, next_id);
-				tx->cursor_set_line(next_id);
-			}
-			tx->end_complex_operation();
-			tx->update();
-
+			shader_editor->move_lines_up();
 		} break;
 		case EDIT_MOVE_LINE_DOWN: {
-
-			TextEdit *tx = shader_editor->get_text_edit();
-			if (shader.is_null())
-				return;
-
-			tx->begin_complex_operation();
-			if (tx->is_selection_active()) {
-				int from_line = tx->get_selection_from_line();
-				int from_col = tx->get_selection_from_column();
-				int to_line = tx->get_selection_to_line();
-				int to_column = tx->get_selection_to_column();
-
-				for (int i = to_line; i >= from_line; i--) {
-					int line_id = i;
-					int next_id = i + 1;
-
-					if (line_id == tx->get_line_count() - 1 || next_id > tx->get_line_count())
-						return;
-
-					tx->swap_lines(line_id, next_id);
-					tx->cursor_set_line(next_id);
-				}
-				int from_line_down = from_line < tx->get_line_count() ? from_line + 1 : from_line;
-				int to_line_down = to_line < tx->get_line_count() ? to_line + 1 : to_line;
-				tx->select(from_line_down, from_col, to_line_down, to_column);
-			} else {
-				int line_id = tx->cursor_get_line();
-				int next_id = line_id + 1;
-
-				if (line_id == tx->get_line_count() - 1 || next_id > tx->get_line_count())
-					return;
-
-				tx->swap_lines(line_id, next_id);
-				tx->cursor_set_line(next_id);
-			}
-			tx->end_complex_operation();
-			tx->update();
-
+			shader_editor->move_lines_down();
 		} break;
 		case EDIT_INDENT_LEFT: {
 
@@ -356,55 +282,10 @@ void ShaderEditor::_menu_option(int p_option) {
 
 		} break;
 		case EDIT_DELETE_LINE: {
-
-			TextEdit *tx = shader_editor->get_text_edit();
-			if (shader.is_null())
-				return;
-
-			tx->begin_complex_operation();
-			int line = tx->cursor_get_line();
-			tx->set_line(tx->cursor_get_line(), "");
-			tx->backspace_at_cursor();
-			tx->cursor_set_line(line);
-			tx->end_complex_operation();
-
+			shader_editor->delete_lines();
 		} break;
 		case EDIT_CLONE_DOWN: {
-
-			TextEdit *tx = shader_editor->get_text_edit();
-			if (shader.is_null())
-				return;
-
-			int from_line = tx->cursor_get_line();
-			int to_line = tx->cursor_get_line();
-			int column = tx->cursor_get_column();
-
-			if (tx->is_selection_active()) {
-				from_line = tx->get_selection_from_line();
-				to_line = tx->get_selection_to_line();
-				column = tx->cursor_get_column();
-			}
-			int next_line = to_line + 1;
-
-			tx->begin_complex_operation();
-			for (int i = from_line; i <= to_line; i++) {
-
-				if (i >= tx->get_line_count() - 1) {
-					tx->set_line(i, tx->get_line(i) + "\n");
-				}
-				String line_clone = tx->get_line(i);
-				tx->insert_at(line_clone, next_line);
-				next_line++;
-			}
-
-			tx->cursor_set_column(column);
-			if (tx->is_selection_active()) {
-				tx->select(to_line + 1, tx->get_selection_from_column(), next_line - 1, tx->get_selection_to_column());
-			}
-
-			tx->end_complex_operation();
-			tx->update();
-
+			shader_editor->code_lines_down();
 		} break;
 		case EDIT_TOGGLE_COMMENT: {