From 7e4c58c56331f0a6f98c9ac950135041d8578f97 Mon Sep 17 00:00:00 2001
From: Ignacio Etcheverry <ignalfonsore@gmail.com>
Date: Mon, 30 May 2016 18:15:41 +0200
Subject: [PATCH] Fixed and improved search bar - Search no longer selects the
 results - Return focus to the text editor when hiding the bar - Fix
 connecting to invalid signal - Update/redraw the text editor after searching

---
 scene/gui/text_edit.cpp      |   1 +
 tools/editor/code_editor.cpp | 202 ++++++++++++++++++++---------------
 tools/editor/code_editor.h   |  17 +--
 3 files changed, 130 insertions(+), 90 deletions(-)

diff --git a/scene/gui/text_edit.cpp b/scene/gui/text_edit.cpp
index ceb40925ec5..fd6e97d33f1 100644
--- a/scene/gui/text_edit.cpp
+++ b/scene/gui/text_edit.cpp
@@ -3554,6 +3554,7 @@ void TextEdit::set_search_flags(uint32_t p_flags) {
 void TextEdit::set_current_search_result(int line, int col) {
 	search_result_line = line;
 	search_result_col = col;
+	update();
 }
 
 void TextEdit::set_highlight_all_occurrences(const bool p_enabled) {
diff --git a/tools/editor/code_editor.cpp b/tools/editor/code_editor.cpp
index a9e31a65615..f62209fafa3 100644
--- a/tools/editor/code_editor.cpp
+++ b/tools/editor/code_editor.cpp
@@ -122,82 +122,30 @@ void FindReplaceBar::_unhandled_input(const InputEvent &p_event) {
 	}
 }
 
-bool FindReplaceBar::_search(bool p_include_current, bool p_backwards) {
+bool FindReplaceBar::_search(uint32_t p_flags, int p_from_line, int p_from_col) {
 
+	int line, col;
 	String text=get_search_text();
-	uint32_t flags=0;
 
-	if (is_whole_words())
-		flags|=TextEdit::SEARCH_WHOLE_WORDS;
-	if (is_case_sensitive())
-		flags|=TextEdit::SEARCH_MATCH_CASE;
-	if (p_backwards)
-		flags|=TextEdit::SEARCH_BACKWARDS;
-
-	int line=text_edit->cursor_get_line();
-	int col=text_edit->cursor_get_column();
-
-	if (text_edit->is_selection_active() && !replace_all_mode) {
-		line = text_edit->get_selection_from_line();
-		col = text_edit->get_selection_from_column();
-	}
-
-	bool cursor_at_result=false;
-
-	if (line==current_result_line && col>=current_result_col && col<=current_result_col+text.length()) {
-		col=current_result_col;
-		cursor_at_result=true;
-	}
-
-	if (!p_include_current) {
-		if (p_backwards) {
-			col-=text.length();
-			if (col<0) {
-				line-=1;
-				if (line<0)
-					line=text_edit->get_line_count()-1;
-				col=text_edit->get_line(line).length();
-			}
-		} else if (cursor_at_result) {
-			col+=text.length();
-			if (col>text_edit->get_line(line).length()) {
-				line+=1;
-				if (line>=text_edit->get_line_count())
-					line=0;
-				col=0;
-			}
-		}
-	}
-
-	bool found = text_edit->search(text,flags,line,col,line,col);
-
-	if (!found) {
-		if (p_backwards) {
-			line = text_edit->get_line_count()-1;
-			col = text_edit->get_line(line).length()-1;
-		} else {
-			line = 0;
-			col = 0;
-		}
-
-		found = text_edit->search(text,flags,line,col,line,col);
-	}
+	bool found=text_edit->search(text,p_flags,p_from_line,p_from_col,line,col);
 
 	if (found) {
-		text_edit->cursor_set_line(line);
-		text_edit->cursor_set_column(p_backwards?col:col+text.length());
-		text_edit->select(line,col,line,col+text.length());
+		if (!preserve_cursor) {
+			text_edit->cursor_set_line(line);
+			text_edit->cursor_set_column(col+text.length());
+		}
+
 		text_edit->set_search_text(text);
-		text_edit->set_search_flags(flags);
+		text_edit->set_search_flags(p_flags);
 		text_edit->set_current_search_result(line,col);
 
-		current_result_line = line;
-		current_result_col = col;
+		result_line=line;
+		result_col=col;
 
 		set_error("");
 	} else {
-		current_result_line = -1;
-		current_result_col = -1;
+		result_line=-1;
+		result_col=-1;
 		text_edit->set_search_text("");
 		set_error(text.empty()?"":TTR("No Matches"));
 	}
@@ -207,8 +155,13 @@ bool FindReplaceBar::_search(bool p_include_current, bool p_backwards) {
 
 void FindReplaceBar::_replace() {
 
-	if (text_edit->get_selection_text()==get_search_text()) {
+	if (result_line!=-1 && result_col!=-1) {
+		text_edit->begin_complex_operation();
+
+		text_edit->select(result_line,result_col,result_line,result_col+get_search_text().length());
 		text_edit->insert_text_at_cursor(get_replace_text());
+
+		text_edit->end_complex_operation();
 	}
 
 	search_current();
@@ -232,28 +185,26 @@ void FindReplaceBar::_replace_all() {
 	text_edit->cursor_set_line(0);
 	text_edit->cursor_set_column(0);
 
+	int search_text_len=get_search_text().length();
 	int rc=0;
 
 	replace_all_mode = true;
 
 	text_edit->begin_complex_operation();
 
-	while(_search(false)) {
-
-		if (!text_edit->is_selection_active()) {
-			// search selects
-			break;
-		}
+	while (search_next()) {
 
 		// replace area
-		Point2i match_from(text_edit->get_selection_from_line(),text_edit->get_selection_from_column());
-		Point2i match_to(text_edit->get_selection_to_line(),text_edit->get_selection_to_column());
+		Point2i match_from(result_line,result_col);
+		Point2i match_to(result_line,result_col+search_text_len);
 
 		if (match_from < prev_match)
 			break; // done
 
 		prev_match=match_to;
 
+		text_edit->select(result_line,result_col,result_line,match_to.y);
+
 		if (selection_enabled && is_selection_only()) {
 
 			if (match_from<selection_begin || match_to>selection_end)
@@ -264,7 +215,7 @@ void FindReplaceBar::_replace_all() {
 			if (match_to.x==selection_end.x)
 				selection_end.y+=get_replace_text().length() - get_search_text().length();
 		} else {
-			//just replace
+			// just replace
 			text_edit->insert_text_at_cursor(get_replace_text());
 		}
 
@@ -290,26 +241,96 @@ void FindReplaceBar::_replace_all() {
 	set_error(vformat(TTR("Replaced %d Ocurrence(s)."), rc));
 }
 
-void FindReplaceBar::search_current() {
+void FindReplaceBar::_get_search_from(int& r_line, int& r_col) {
 
-	_search(true);
+	r_line=text_edit->cursor_get_line();
+	r_col=text_edit->cursor_get_column();
+
+	if (text_edit->is_selection_active() && !replace_all_mode) {
+		r_line=text_edit->get_selection_from_line();
+		r_col=text_edit->get_selection_to_column();
+	}
+
+	if (r_line==result_line && r_col>=result_col && r_col<=result_col+get_search_text().length()) {
+		r_col=result_col;
+	}
 }
 
-void FindReplaceBar::search_prev() {
+bool FindReplaceBar::search_current() {
 
-	_search(false, true);
+	uint32_t flags=0;
+
+	if (is_whole_words())
+		flags|=TextEdit::SEARCH_WHOLE_WORDS;
+	if (is_case_sensitive())
+		flags|=TextEdit::SEARCH_MATCH_CASE;
+
+	int line, col;
+	_get_search_from(line, col);
+
+	return _search(flags,line,col);
 }
 
-void FindReplaceBar::search_next() {
+bool FindReplaceBar::search_prev() {
 
-	_search();
+	uint32_t flags=0;
+	String text = get_search_text();
+
+	if (is_whole_words())
+		flags|=TextEdit::SEARCH_WHOLE_WORDS;
+	if (is_case_sensitive())
+		flags|=TextEdit::SEARCH_MATCH_CASE;
+
+	flags|=TextEdit::SEARCH_BACKWARDS;
+
+	int line, col;
+	_get_search_from(line, col);
+
+	col-=text.length();
+	if (col<0) {
+		line-=1;
+		if (line<0)
+			line=text_edit->get_line_count()-1;
+		col=text_edit->get_line(line).length();
+	}
+
+	return _search(flags,line,col);
+}
+
+bool FindReplaceBar::search_next() {
+
+	uint32_t flags=0;
+	String text = get_search_text();
+
+	if (is_whole_words())
+		flags|=TextEdit::SEARCH_WHOLE_WORDS;
+	if (is_case_sensitive())
+		flags|=TextEdit::SEARCH_MATCH_CASE;
+
+	int line, col;
+	_get_search_from(line, col);
+
+	if (line==result_line && col==result_col) {
+		col+=text.length();
+		if (col>text_edit->get_line(line).length()) {
+			line+=1;
+			if (line>=text_edit->get_line_count())
+				line=0;
+			col=0;
+		}
+	}
+
+	return _search(flags,line,col);
 }
 
 void FindReplaceBar::_hide_bar() {
 
+	if (replace_text->has_focus() || search_text->has_focus())
+		text_edit->grab_focus();
+
 	text_edit->set_search_text("");
-	current_result_line = -1;
-	current_result_col = -1;
+	result_line = -1;
+	result_col = -1;
 	replace_hbc->hide();
 	replace_options_hbc->hide();
 	hide();
@@ -354,6 +375,15 @@ void FindReplaceBar::_search_options_changed(bool p_pressed) {
 	search_current();
 }
 
+void FindReplaceBar::_editor_text_changed() {
+
+	if (is_visible()) {
+		preserve_cursor=true;
+		search_current();
+		preserve_cursor=false;
+	}
+}
+
 void FindReplaceBar::_search_text_changed(const String& p_text) {
 
 	search_current();
@@ -397,13 +427,14 @@ void FindReplaceBar::set_error(const String &p_label) {
 void FindReplaceBar::set_text_edit(TextEdit *p_text_edit) {
 
 	text_edit = p_text_edit;
-	text_edit->connect("_text_changed",this,"_search_text_changed",varray(String()));
+	text_edit->connect("text_changed",this,"_editor_text_changed");
 }
 
 void FindReplaceBar::_bind_methods() {
 
 	ObjectTypeDB::bind_method("_unhandled_input",&FindReplaceBar::_unhandled_input);
 
+	ObjectTypeDB::bind_method("_editor_text_changed",&FindReplaceBar::_editor_text_changed);
 	ObjectTypeDB::bind_method("_search_text_changed",&FindReplaceBar::_search_text_changed);
 	ObjectTypeDB::bind_method("_search_text_entered",&FindReplaceBar::_search_text_entered);
 	ObjectTypeDB::bind_method("_search_current",&FindReplaceBar::search_current);
@@ -419,6 +450,9 @@ void FindReplaceBar::_bind_methods() {
 
 FindReplaceBar::FindReplaceBar() {
 
+	replace_all_mode=false;
+	preserve_cursor=false;
+
 	text_vbc = memnew(VBoxContainer);
 	add_child(text_vbc);
 
diff --git a/tools/editor/code_editor.h b/tools/editor/code_editor.h
index 52a36c979d8..2e1bf46c026 100644
--- a/tools/editor/code_editor.h
+++ b/tools/editor/code_editor.h
@@ -83,13 +83,18 @@ class FindReplaceBar : public HBoxContainer {
 
 	TextEdit *text_edit;
 
-	int current_result_line;
-	int current_result_col;
+	int result_line;
+	int result_col;
 
 	bool replace_all_mode;
+	bool preserve_cursor;
+
+	void _get_search_from(int& r_line, int& r_col);
 
 	void _show_search();
 	void _hide_bar();
+
+	void _editor_text_changed();
 	void _search_options_changed(bool p_pressed);
 	void _search_text_changed(const String& p_text);
 	void _search_text_entered(const String& p_text);
@@ -98,7 +103,7 @@ protected:
 	void _notification(int p_what);
 	void _unhandled_input(const InputEvent &p_event);
 
-	bool _search(bool p_include_current=false, bool p_backwards=false);
+	bool _search(uint32_t p_flags, int p_from_line, int p_from_col);
 
 	void _replace();
 	void _replace_all();
@@ -119,9 +124,9 @@ public:
 	void popup_search();
 	void popup_replace();
 
-	void search_current();
-	void search_prev();
-	void search_next();
+	bool search_current();
+	bool search_prev();
+	bool search_next();
 
 	FindReplaceBar();
 };