diff --git a/modules/gdscript/gdscript_highlighter.cpp b/modules/gdscript/gdscript_highlighter.cpp
index 5b8b652c298..4e89851bf21 100644
--- a/modules/gdscript/gdscript_highlighter.cpp
+++ b/modules/gdscript/gdscript_highlighter.cpp
@@ -71,24 +71,8 @@ Map<int, TextEdit::HighlighterInfo> GDScriptSyntaxHighlighter::_get_line_syntax_
 	Color keyword_color;
 	Color color;
 
-	int in_region = -1;
+	int in_region = text_editor->_is_line_in_region(p_line);
 	int deregion = 0;
-	for (int i = 0; i < p_line; i++) {
-		int ending_color_region = text_editor->_get_line_ending_color_region(i);
-		if (in_region == -1) {
-			in_region = ending_color_region;
-		} else if (in_region == ending_color_region) {
-			in_region = -1;
-		} else {
-			const Map<int, TextEdit::Text::ColorRegionInfo> &cri_map = text_editor->_get_line_color_region_info(i);
-			for (const Map<int, TextEdit::Text::ColorRegionInfo>::Element *E = cri_map.front(); E; E = E->next()) {
-				const TextEdit::Text::ColorRegionInfo &cri = E->get();
-				if (cri.region == in_region) {
-					in_region = -1;
-				}
-			}
-		}
-	}
 
 	const Map<int, TextEdit::Text::ColorRegionInfo> cri_map = text_editor->_get_line_color_region_info(p_line);
 	const String &str = text_editor->get_line(p_line);
diff --git a/scene/gui/text_edit.cpp b/scene/gui/text_edit.cpp
index e214a020d51..cc6a677ec8f 100644
--- a/scene/gui/text_edit.cpp
+++ b/scene/gui/text_edit.cpp
@@ -145,7 +145,6 @@ void TextEdit::Text::_update_line_cache(int p_line) const {
 
 	text[p_line].region_info.clear();
 
-	int ending_color_region = -1;
 	for (int i = 0; i < len; i++) {
 
 		if (!_is_symbol(str[i]))
@@ -186,11 +185,6 @@ void TextEdit::Text::_update_line_cache(int p_line) const {
 				text[p_line].region_info[i] = cri;
 				i += lr - 1;
 
-				if (ending_color_region == -1 && !cr.line_only) {
-					ending_color_region = j;
-				} else if (ending_color_region == j) {
-					ending_color_region = -1;
-				}
 				break;
 			}
 
@@ -219,15 +213,10 @@ void TextEdit::Text::_update_line_cache(int p_line) const {
 				text[p_line].region_info[i] = cri;
 				i += lr - 1;
 
-				if (ending_color_region == j) {
-					ending_color_region = -1;
-				}
-
 				break;
 			}
 		}
 	}
-	text[p_line].ending_color_region = ending_color_region;
 }
 
 const Map<int, TextEdit::Text::ColorRegionInfo> &TextEdit::Text::get_color_region_info(int p_line) const {
@@ -569,7 +558,6 @@ void TextEdit::_notification(int p_what) {
 			}
 		} break;
 		case NOTIFICATION_DRAW: {
-
 			if ((!has_focus() && !menu->has_focus()) || !window_has_focus) {
 				draw_caret = false;
 			}
@@ -3196,6 +3184,7 @@ void TextEdit::_base_insert_text(int p_line, int p_char, const String &p_text, i
 			MessageQueue::get_singleton()->push_call(this, "_text_changed_emit");
 		text_changed_dirty = true;
 	}
+	_line_edited_from(p_line);
 }
 
 String TextEdit::_base_get_text(int p_from_line, int p_from_column, int p_to_line, int p_to_column) const {
@@ -3246,6 +3235,7 @@ void TextEdit::_base_remove_text(int p_from_line, int p_from_column, int p_to_li
 			MessageQueue::get_singleton()->push_call(this, "_text_changed_emit");
 		text_changed_dirty = true;
 	}
+	_line_edited_from(p_from_line);
 }
 
 void TextEdit::_insert_text(int p_line, int p_char, const String &p_text, int *r_end_line, int *r_end_char) {
@@ -3368,6 +3358,13 @@ void TextEdit::_insert_text_at_cursor(const String &p_text) {
 	update();
 }
 
+void TextEdit::_line_edited_from(int p_line) {
+	int cache_size = color_region_cache.size();
+	for (int i = p_line; i < cache_size; i++) {
+		color_region_cache.erase(i);
+	}
+}
+
 int TextEdit::get_char_count() {
 
 	int totalsize = 0;
@@ -4009,15 +4006,49 @@ void TextEdit::_set_syntax_highlighting(SyntaxHighlighter *p_syntax_highlighter)
 	update();
 }
 
-int TextEdit::_get_line_ending_color_region(int p_line) const {
-	if (p_line < 0 || p_line > text.size() - 1) {
-		return -1;
+int TextEdit::_is_line_in_region(int p_line) {
+
+	// do we have in cache?
+	if (color_region_cache.has(p_line)) {
+		return color_region_cache[p_line];
 	}
-	return text.get_line_ending_color_region(p_line);
+
+	// if not find the closest line we have
+	int previous_line = p_line - 1;
+	for (previous_line; previous_line > -1; previous_line--) {
+		if (color_region_cache.has(p_line)) {
+			break;
+		}
+	}
+
+	// calculate up to line we need and update the cache along the way.
+	int in_region = color_region_cache[previous_line];
+	for (int i = previous_line; i < p_line; i++) {
+		const Map<int, Text::ColorRegionInfo> &cri_map = _get_line_color_region_info(i);
+		for (const Map<int, Text::ColorRegionInfo>::Element *E = cri_map.front(); E; E = E->next()) {
+			const Text::ColorRegionInfo &cri = E->get();
+			if (in_region == -1) {
+				if (!cri.end) {
+					in_region = cri.region;
+				}
+			} else if (in_region == cri.region && !_get_color_region(cri.region).line_only) {
+				if (cri.end || _get_color_region(cri.region).eq) {
+					in_region = -1;
+				}
+			}
+		}
+
+		if (in_region >= 0 && _get_color_region(in_region).line_only) {
+			in_region = -1;
+		}
+
+		color_region_cache[i + 1] = in_region;
+	}
+	return in_region;
 }
 
 TextEdit::ColorRegion TextEdit::_get_color_region(int p_region) const {
-	if (p_region < 0 || p_region > color_regions.size()) {
+	if (p_region < 0 || p_region >= color_regions.size()) {
 		return ColorRegion();
 	}
 	return color_regions[p_region];
@@ -4034,6 +4065,7 @@ void TextEdit::clear_colors() {
 
 	keywords.clear();
 	color_regions.clear();
+	color_region_cache.clear();
 	text.clear_caches();
 }
 
@@ -5777,24 +5809,8 @@ Map<int, TextEdit::HighlighterInfo> TextEdit::_get_line_syntax_highlighting(int
 	Color keyword_color;
 	Color color;
 
-	int in_region = -1;
+	int in_region = _is_line_in_region(p_line);
 	int deregion = 0;
-	for (int i = 0; i < p_line; i++) {
-		int ending_color_region = text.get_line_ending_color_region(i);
-		if (in_region == -1) {
-			in_region = ending_color_region;
-		} else if (in_region == ending_color_region) {
-			in_region = -1;
-		} else {
-			const Map<int, TextEdit::Text::ColorRegionInfo> &cri_map = text.get_color_region_info(i);
-			for (const Map<int, TextEdit::Text::ColorRegionInfo>::Element *E = cri_map.front(); E; E = E->next()) {
-				const TextEdit::Text::ColorRegionInfo &cri = E->get();
-				if (cri.region == in_region) {
-					in_region = -1;
-				}
-			}
-		}
-	}
 
 	const Map<int, TextEdit::Text::ColorRegionInfo> cri_map = text.get_color_region_info(p_line);
 	const String &str = text[p_line];
diff --git a/scene/gui/text_edit.h b/scene/gui/text_edit.h
index 2360ce79dba..30e70bfd0b6 100644
--- a/scene/gui/text_edit.h
+++ b/scene/gui/text_edit.h
@@ -76,7 +76,6 @@ public:
 			bool marked : 1;
 			bool breakpoint : 1;
 			bool hidden : 1;
-			int ending_color_region;
 			Map<int, ColorRegionInfo> region_info;
 			String data;
 		};
@@ -103,7 +102,6 @@ public:
 		bool is_breakpoint(int p_line) const { return text[p_line].breakpoint; }
 		void set_hidden(int p_line, bool p_hidden) { text[p_line].hidden = p_hidden; }
 		bool is_hidden(int p_line) const { return text[p_line].hidden; }
-		int get_line_ending_color_region(int p_line) const { return text[p_line].ending_color_region; }
 		void insert(int p_at, const String &p_text);
 		void remove(int p_at);
 		int size() const { return text.size(); }
@@ -189,6 +187,8 @@ private:
 		Size2 size;
 	} cache;
 
+	Map<int, int> color_region_cache;
+
 	struct TextOperation {
 
 		enum Type {
@@ -368,6 +368,7 @@ private:
 	void _update_caches();
 	void _cursor_changed_emit();
 	void _text_changed_emit();
+	void _line_edited_from(int p_line);
 
 	void _push_current_op();
 
@@ -407,7 +408,7 @@ public:
 	SyntaxHighlighter *_get_syntax_highlighting();
 	void _set_syntax_highlighting(SyntaxHighlighter *p_syntax_highlighter);
 
-	int _get_line_ending_color_region(int p_line) const;
+	int _is_line_in_region(int p_line);
 	ColorRegion _get_color_region(int p_region) const;
 	Map<int, Text::ColorRegionInfo> _get_line_color_region_info(int p_line) const;