SF.net SVN: geany: [551] trunk

ntrel at users.sourceforge.net ntrel at xxxxx
Thu Jul 13 14:31:16 UTC 2006


Revision: 551
Author:   ntrel
Date:     2006-07-13 07:30:44 -0700 (Thu, 13 Jul 2006)
ViewCVS:  http://svn.sourceforge.net/geany/?rev=551&view=rev

Log Message:
-----------
Added basic Find in files search functionality.

Modified Paths:
--------------
    trunk/ChangeLog
    trunk/geany.glade
    trunk/src/Makefile.am
    trunk/src/build.c
    trunk/src/callbacks.c
    trunk/src/callbacks.h
    trunk/src/dialogs.c
    trunk/src/dialogs.h
    trunk/src/geany.h
    trunk/src/interface.c
    trunk/src/keyfile.c
    trunk/src/main.c
    trunk/src/msgwindow.c
    trunk/src/msgwindow.h
    trunk/src/prefs.c
    trunk/src/utils.c
    trunk/src/utils.h

Added Paths:
-----------
    trunk/src/search.c
    trunk/src/search.h
Modified: trunk/ChangeLog
===================================================================
--- trunk/ChangeLog	2006-07-11 17:44:42 UTC (rev 550)
+++ trunk/ChangeLog	2006-07-13 14:30:44 UTC (rev 551)
@@ -1,3 +1,12 @@
+2006-07-13  Nick Treleaven  <nick.treleaven at btinternet.com>
+
+ * src/build.c, src/interface.c, src/utils.c, src/utils.h, src/geany.h,
+   src/msgwindow.c, src/msgwindow.h, src/callbacks.c, src/callbacks.h,
+   src/keyfile.c, src/search.c, src/search.h, src/prefs.c,
+   src/dialogs.c, src/main.c, src/dialogs.h, src/Makefile.am,
+   geany.glade: Added basic Find in files search functionality.
+
+
 2006-07-11  Enrico Tröger  <enrico.troeger at uvena.de>
 
  * src/dialogs.c: Moved dialogs_show_prefs_dialog() to src/prefs.c.

Modified: trunk/geany.glade
===================================================================
--- trunk/geany.glade	2006-07-11 17:44:42 UTC (rev 550)
+++ trunk/geany.glade	2006-07-13 14:30:44 UTC (rev 551)
@@ -58,7 +58,7 @@
 		      <property name="use_underline">True</property>
 
 		      <child internal-child="image">
-			<widget class="GtkImage" id="image791">
+			<widget class="GtkImage" id="image799">
 			  <property name="visible">True</property>
 			  <property name="stock">gtk-new</property>
 			  <property name="icon_size">1</property>
@@ -151,7 +151,7 @@
 		      <signal name="activate" handler="on_save_all1_activate" last_modification_time="Thu, 02 Jun 2005 14:15:30 GMT"/>
 
 		      <child internal-child="image">
-			<widget class="GtkImage" id="image792">
+			<widget class="GtkImage" id="image800">
 			  <property name="visible">True</property>
 			  <property name="stock">gtk-save</property>
 			  <property name="icon_size">1</property>
@@ -228,7 +228,7 @@
 		      <signal name="activate" handler="on_close_all1_activate" last_modification_time="Thu, 02 Jun 2005 14:15:30 GMT"/>
 
 		      <child internal-child="image">
-			<widget class="GtkImage" id="image793">
+			<widget class="GtkImage" id="image801">
 			  <property name="visible">True</property>
 			  <property name="stock">gtk-close</property>
 			  <property name="icon_size">1</property>
@@ -359,7 +359,7 @@
 		      <property name="use_underline">True</property>
 
 		      <child internal-child="image">
-			<widget class="GtkImage" id="image794">
+			<widget class="GtkImage" id="image802">
 			  <property name="visible">True</property>
 			  <property name="stock">gtk-add</property>
 			  <property name="icon_size">1</property>
@@ -391,7 +391,7 @@
 		      <property name="use_underline">True</property>
 
 		      <child internal-child="image">
-			<widget class="GtkImage" id="image795">
+			<widget class="GtkImage" id="image803">
 			  <property name="visible">True</property>
 			  <property name="stock">gtk-add</property>
 			  <property name="icon_size">1</property>
@@ -569,7 +569,7 @@
 		      <signal name="activate" handler="on_replace1_activate" last_modification_time="Sun, 23 Oct 2005 13:22:36 GMT"/>
 
 		      <child internal-child="image">
-			<widget class="GtkImage" id="image796">
+			<widget class="GtkImage" id="image804">
 			  <property name="visible">True</property>
 			  <property name="stock">gtk-find-and-replace</property>
 			  <property name="icon_size">1</property>
@@ -583,6 +583,21 @@
 		  </child>
 
 		  <child>
+		    <widget class="GtkSeparatorMenuItem" id="separator27">
+		      <property name="visible">True</property>
+		    </widget>
+		  </child>
+
+		  <child>
+		    <widget class="GtkMenuItem" id="find_in_files1">
+		      <property name="visible">True</property>
+		      <property name="label" translatable="yes">Find in f_iles</property>
+		      <property name="use_underline">True</property>
+		      <signal name="activate" handler="on_find_in_files1_activate" last_modification_time="Thu, 06 Jul 2006 11:31:09 GMT"/>
+		    </widget>
+		  </child>
+
+		  <child>
 		    <widget class="GtkSeparatorMenuItem" id="separator11">
 		      <property name="visible">True</property>
 		    </widget>
@@ -596,7 +611,7 @@
 		      <signal name="activate" handler="on_go_to_line1_activate" last_modification_time="Tue, 23 May 2006 17:10:49 GMT"/>
 
 		      <child internal-child="image">
-			<widget class="GtkImage" id="image797">
+			<widget class="GtkImage" id="image805">
 			  <property name="visible">True</property>
 			  <property name="stock">gtk-jump-to</property>
 			  <property name="icon_size">1</property>
@@ -631,7 +646,7 @@
 		      <signal name="activate" handler="on_change_font1_activate" last_modification_time="Fri, 22 Apr 2005 18:58:45 GMT"/>
 
 		      <child internal-child="image">
-			<widget class="GtkImage" id="image798">
+			<widget class="GtkImage" id="image806">
 			  <property name="visible">True</property>
 			  <property name="stock">gtk-select-font</property>
 			  <property name="icon_size">1</property>
@@ -653,7 +668,7 @@
 		      <signal name="activate" handler="on_show_color_chooser1_activate" last_modification_time="Wed, 22 Jun 2005 18:10:21 GMT"/>
 
 		      <child internal-child="image">
-			<widget class="GtkImage" id="image799">
+			<widget class="GtkImage" id="image807">
 			  <property name="visible">True</property>
 			  <property name="stock">gtk-select-color</property>
 			  <property name="icon_size">1</property>
@@ -4703,7 +4718,7 @@
 	      <child>
 		<widget class="GtkTable" id="table1">
 		  <property name="visible">True</property>
-		  <property name="n_rows">4</property>
+		  <property name="n_rows">5</property>
 		  <property name="n_columns">3</property>
 		  <property name="homogeneous">False</property>
 		  <property name="row_spacing">7</property>
@@ -5024,6 +5039,84 @@
 		      <property name="y_options"></property>
 		    </packing>
 		  </child>
+
+		  <child>
+		    <widget class="GtkLabel" id="label171">
+		      <property name="visible">True</property>
+		      <property name="label" translatable="yes">Grep</property>
+		      <property name="use_underline">False</property>
+		      <property name="use_markup">False</property>
+		      <property name="justify">GTK_JUSTIFY_LEFT</property>
+		      <property name="wrap">False</property>
+		      <property name="selectable">False</property>
+		      <property name="xalign">0</property>
+		      <property name="yalign">0.5</property>
+		      <property name="xpad">0</property>
+		      <property name="ypad">0</property>
+		      <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+		      <property name="width_chars">-1</property>
+		      <property name="single_line_mode">False</property>
+		      <property name="angle">0</property>
+		    </widget>
+		    <packing>
+		      <property name="left_attach">0</property>
+		      <property name="right_attach">1</property>
+		      <property name="top_attach">4</property>
+		      <property name="bottom_attach">5</property>
+		      <property name="x_options">fill</property>
+		      <property name="y_options"></property>
+		    </packing>
+		  </child>
+
+		  <child>
+		    <widget class="GtkEntry" id="entry_grep">
+		      <property name="visible">True</property>
+		      <property name="can_focus">True</property>
+		      <property name="editable">True</property>
+		      <property name="visibility">True</property>
+		      <property name="max_length">0</property>
+		      <property name="text" translatable="yes"></property>
+		      <property name="has_frame">True</property>
+		      <property name="invisible_char">*</property>
+		      <property name="activates_default">False</property>
+		    </widget>
+		    <packing>
+		      <property name="left_attach">1</property>
+		      <property name="right_attach">2</property>
+		      <property name="top_attach">4</property>
+		      <property name="bottom_attach">5</property>
+		      <property name="y_options"></property>
+		    </packing>
+		  </child>
+
+		  <child>
+		    <widget class="GtkButton" id="button_grep">
+		      <property name="visible">True</property>
+		      <property name="can_focus">True</property>
+		      <property name="relief">GTK_RELIEF_NORMAL</property>
+		      <property name="focus_on_click">True</property>
+
+		      <child>
+			<widget class="GtkImage" id="image808">
+			  <property name="visible">True</property>
+			  <property name="stock">gtk-directory</property>
+			  <property name="icon_size">4</property>
+			  <property name="xalign">0.5</property>
+			  <property name="yalign">0.5</property>
+			  <property name="xpad">0</property>
+			  <property name="ypad">0</property>
+			</widget>
+		      </child>
+		    </widget>
+		    <packing>
+		      <property name="left_attach">2</property>
+		      <property name="right_attach">3</property>
+		      <property name="top_attach">4</property>
+		      <property name="bottom_attach">5</property>
+		      <property name="x_options">fill</property>
+		      <property name="y_options"></property>
+		    </packing>
+		  </child>
 		</widget>
 		<packing>
 		  <property name="padding">0</property>

Modified: trunk/src/Makefile.am
===================================================================
--- trunk/src/Makefile.am	2006-07-11 17:44:42 UTC (rev 550)
+++ trunk/src/Makefile.am	2006-07-13 14:30:44 UTC (rev 551)
@@ -14,6 +14,7 @@
 
 geany_SOURCES = \
 	main.c geany.h \
+	search.c search.h \
 	notebook.c notebook.h \
 	keybindings.c keybindings.h \
 	templates.c templates.h \

Modified: trunk/src/build.c
===================================================================
--- trunk/src/build.c	2006-07-11 17:44:42 UTC (rev 550)
+++ trunk/src/build.c	2006-07-13 14:30:44 UTC (rev 551)
@@ -41,7 +41,6 @@
 #include "document.h"
 
 
-static GIOChannel *build_set_up_io_channel (gint fd, GIOCondition cond, GIOFunc func, gpointer data);
 static gboolean build_iofunc(GIOChannel *ioc, GIOCondition cond, gpointer data);
 static gboolean build_create_shellscript(const gint idx, const gchar *fname, const gchar *cmd);
 static GPid build_spawn_cmd(gint idx, gchar **cmd);
@@ -303,8 +302,10 @@
 	}
 
 	// use GIOChannels to monitor stdout and stderr
-	build_set_up_io_channel(stdout_fd, G_IO_IN|G_IO_PRI|G_IO_ERR|G_IO_HUP|G_IO_NVAL, build_iofunc, GINT_TO_POINTER(0));
-	build_set_up_io_channel(stderr_fd, G_IO_IN|G_IO_PRI|G_IO_ERR|G_IO_HUP|G_IO_NVAL, build_iofunc, GINT_TO_POINTER(1));
+	utils_set_up_io_channel(stdout_fd, G_IO_IN|G_IO_PRI|G_IO_ERR|G_IO_HUP|G_IO_NVAL,
+		build_iofunc, GINT_TO_POINTER(0));
+	utils_set_up_io_channel(stderr_fd, G_IO_IN|G_IO_PRI|G_IO_ERR|G_IO_HUP|G_IO_NVAL,
+		build_iofunc, GINT_TO_POINTER(1));
 
 	g_strfreev(argv);
 	g_free(utf8_working_dir);
@@ -497,35 +498,6 @@
 }
 
 
-static GIOChannel *build_set_up_io_channel(gint fd, GIOCondition cond, GIOFunc func, gpointer data)
-{
-	GIOChannel *ioc;
-	GError *error = NULL;
-	const gchar *encoding;
-
-	ioc = g_io_channel_unix_new(fd);
-
-	g_io_channel_set_flags(ioc, G_IO_FLAG_NONBLOCK, NULL);
-	if (! g_get_charset(&encoding))
-	{	// hope this works reliably
-		g_io_channel_set_encoding(ioc, encoding, &error);
-		if (error)
-		{
-			geany_debug("compile: %s", error->message);
-			g_error_free(error);
-			return ioc;
-		}
-	}
-	// "auto-close" ;-)
-	g_io_channel_set_close_on_unref(ioc, TRUE);
-
-	g_io_add_watch(ioc, cond, func, data);
-	g_io_channel_unref(ioc);
-
-	return ioc;
-}
-
-
 void build_exit_cb(GPid child_pid, gint status, gpointer user_data)
 {
 #ifdef G_OS_UNIX

Modified: trunk/src/callbacks.c
===================================================================
--- trunk/src/callbacks.c	2006-07-11 17:44:42 UTC (rev 550)
+++ trunk/src/callbacks.c	2006-07-13 14:30:44 UTC (rev 551)
@@ -48,6 +48,7 @@
 #include "treeviews.h"
 #include "keybindings.h"
 #include "encodings.h"
+#include "search.h"
 
 
 #ifdef GEANY_WIN32
@@ -1437,52 +1438,11 @@
 	{
 		if (GPOINTER_TO_INT(user_data) == 4)
 		{	// double click in the message treeview (results of 'Find usage')
-			GtkTreeIter iter;
-			GtkTreeModel *model;
-			GtkTreeSelection *selection;
-			gint idx;
-			gint line;
-
-			selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(msgwindow.tree_msg));
-			if (gtk_tree_selection_get_selected(selection, &model, &iter))
-			{
-				gtk_tree_model_get(model, &iter, 0, &line, 1, &idx, -1);
-				if (idx >= 0 && doc_list[idx].is_valid)
-				{
-					utils_goto_line(idx, line);
-				}
-			}
+			msgwin_goto_messages_file_line();
 		}
 		else if (GPOINTER_TO_INT(user_data) == 5)
 		{	// double click in the compiler treeview
-			GtkTreeIter iter;
-			GtkTreeModel *model;
-			GtkTreeSelection *selection;
-			gchar *string;
-
-			selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(msgwindow.tree_compiler));
-			if (gtk_tree_selection_get_selected(selection, &model, &iter))
-			{
-				gtk_tree_model_get(model, &iter, 1, &string, -1);
-				if (string != NULL)
-				{
-					gint line;
-					gint idx;
-					gchar *filename;
-					utils_parse_compiler_error_line(string, &filename, &line);
-					if (filename != NULL && line > -1)
-					{
-						// use document_open_file to find an already open file, or open it in place
-						idx = document_open_file(-1, filename, 0, FALSE, NULL);
-						// document_set_indicator will check valid idx
-						document_set_indicator(idx, line - 1);
-						// utils_goto_file_line will check valid filename.
-						utils_goto_file_line(filename, FALSE, line);
-					}
-					g_free(filename);
-				}
-				g_free(string);
-			}
+			msgwin_goto_compiler_file_line();
 		}
 	}
 
@@ -1987,6 +1947,43 @@
 
 
 void
+on_find_in_files1_activate             (GtkMenuItem     *menuitem,
+                                        gpointer         user_data)
+{
+	dialogs_show_find_in_files();
+}
+
+
+void
+on_find_in_files_dialog_response       (GtkDialog *dialog,
+                                        gint response,
+                                        gpointer user_data)
+{
+	if (response == GTK_RESPONSE_ACCEPT)
+	{
+		const gchar *entry_text =
+			gtk_entry_get_text(GTK_ENTRY(gtk_bin_get_child(GTK_BIN(user_data))));
+		gchar *search_text = g_strstrip(g_strdup(entry_text));
+
+		if (search_text && *search_text)
+		{
+			gchar *cur_dir = utils_get_current_file_dir();
+			if (cur_dir)
+				search_find_in_files(search_text, cur_dir);
+			else
+				msgwin_status_add(_("Invalid directory for find in files."));
+			g_free(cur_dir);
+		}
+		else
+			msgwin_status_add(_("No text to find."));
+
+		g_free(search_text);
+	}
+	gtk_widget_hide(app->find_in_files_dialog);
+}
+
+
+void
 on_toolbutton_new_clicked              (GtkToolButton   *toolbutton,
                                         gpointer         user_data)
 {

Modified: trunk/src/callbacks.h
===================================================================
--- trunk/src/callbacks.h	2006-07-11 17:44:42 UTC (rev 550)
+++ trunk/src/callbacks.h	2006-07-13 14:30:44 UTC (rev 551)
@@ -394,11 +394,19 @@
                                         gpointer         user_data);
 
 void
-on_new_with_template                   (GtkMenuItem     *menuitem,
+on_find_in_files1_activate             (GtkMenuItem     *menuitem,
                                         gpointer         user_data);
 
+void
+on_find_in_files_dialog_response       (GtkDialog *dialog,
+                                        gint response,
+                                        gpointer user_data);
 
 void
+on_new_with_template                   (GtkMenuItem     *menuitem,
+                                        gpointer         user_data);
+
+void
 on_toolbutton_new_clicked              (GtkToolButton   *toolbutton,
                                         gpointer         user_data);
 

Modified: trunk/src/dialogs.c
===================================================================
--- trunk/src/dialogs.c	2006-07-11 17:44:42 UTC (rev 550)
+++ trunk/src/dialogs.c	2006-07-13 14:30:44 UTC (rev 551)
@@ -801,6 +801,8 @@
 	gint idx = document_get_cur_idx();
 	gchar *sel = NULL;
 
+	if (idx == -1 || ! doc_list[idx].is_valid) return;
+
 	if (sci_get_lines_selected(doc_list[idx].sci) == 1)
 	{
 		sel = g_malloc(sci_get_selected_text_length(doc_list[idx].sci));
@@ -817,7 +819,7 @@
 
 		gtk_dialog_add_button(GTK_DIALOG(app->find_dialog), "gtk-find", GTK_RESPONSE_ACCEPT);
 
-		label = gtk_label_new(_("Enter the search text here"));
+		label = gtk_label_new(_("Enter the search text here:"));
 		gtk_misc_set_padding(GTK_MISC(label), 0, 6);
 		gtk_misc_set_alignment(GTK_MISC(label), 0, 0);
 
@@ -925,11 +927,11 @@
 		gtk_dialog_add_action_widget(GTK_DIALOG(app->replace_dialog), button,
 			GEANY_RESPONSE_REPLACE);
 
-		label_find = gtk_label_new(_("Enter the search text here"));
+		label_find = gtk_label_new(_("Enter the search text here:"));
 		gtk_misc_set_padding(GTK_MISC(label_find), 0, 6);
 		gtk_misc_set_alignment(GTK_MISC(label_find), 0, 0);
 
-		label_replace = gtk_label_new(_("Enter the replace text here"));
+		label_replace = gtk_label_new(_("Enter the replace text here:"));
 		gtk_misc_set_padding(GTK_MISC(label_replace), 0, 6);
 		gtk_misc_set_alignment(GTK_MISC(label_replace), 0, 0);
 
@@ -1014,6 +1016,81 @@
 	g_free(sel);
 }
 
+
+void dialogs_show_find_in_files(void)
+{
+	static GtkWidget *dirlabel = NULL, *combo = NULL;
+	GtkWidget *entry; //the child GtkEntry of combo
+	gint idx = document_get_cur_idx();
+	gchar *sel = NULL;
+	gchar *cur_dir, *dirtext;
+
+	if (idx == -1 || ! doc_list[idx].is_valid) return;
+
+	if (app->find_in_files_dialog == NULL)
+	{
+		GtkWidget *label;
+
+		app->find_in_files_dialog = gtk_dialog_new_with_buttons(
+			_("Find in files"), GTK_WINDOW(app->window), GTK_DIALOG_DESTROY_WITH_PARENT,
+			GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL, NULL);
+
+		gtk_dialog_add_button(GTK_DIALOG(app->find_in_files_dialog), "gtk-find", GTK_RESPONSE_ACCEPT);
+		gtk_dialog_set_default_response(GTK_DIALOG(app->find_in_files_dialog),
+			GTK_RESPONSE_ACCEPT);
+
+		dirlabel = gtk_label_new("");
+		gtk_misc_set_alignment(GTK_MISC(dirlabel), 0, 0);
+
+		label = gtk_label_new(_("Enter the search text here:"));
+		gtk_misc_set_alignment(GTK_MISC(label), 0, 0);
+
+		combo = gtk_combo_box_entry_new_text();
+		entry = gtk_bin_get_child(GTK_BIN(combo));
+		gtk_entry_set_max_length(GTK_ENTRY(entry), 248);
+		gtk_entry_set_width_chars(GTK_ENTRY(entry), 50);
+		gtk_entry_set_activates_default(GTK_ENTRY(entry), TRUE);
+
+		g_signal_connect((gpointer) app->find_in_files_dialog, "response",
+				G_CALLBACK(on_find_in_files_dialog_response), combo);
+		g_signal_connect((gpointer) app->find_in_files_dialog, "delete_event",
+				G_CALLBACK(gtk_widget_hide), NULL);
+
+		gtk_box_pack_start(GTK_BOX(GTK_DIALOG(app->find_in_files_dialog)->vbox),
+			dirlabel, TRUE, TRUE, 6);
+		gtk_box_pack_start(GTK_BOX(GTK_DIALOG(app->find_in_files_dialog)->vbox),
+			label, TRUE, TRUE, 0);
+		gtk_box_pack_start(GTK_BOX(GTK_DIALOG(app->find_in_files_dialog)->vbox),
+			combo, TRUE, TRUE, 0);
+		gtk_box_pack_start(GTK_BOX(GTK_DIALOG(app->find_in_files_dialog)->vbox),
+			gtk_label_new(""), TRUE, TRUE, 0);
+
+		gtk_box_set_spacing(GTK_BOX(GTK_DIALOG(app->find_in_files_dialog)->vbox), 6);
+
+		gtk_widget_show_all(app->find_in_files_dialog);
+	}
+
+	if (sci_get_lines_selected(doc_list[idx].sci) == 1)
+	{
+		sel = g_malloc(sci_get_selected_text_length(doc_list[idx].sci));
+		sci_get_selected_text(doc_list[idx].sci, sel);
+	}
+
+	entry = GTK_BIN(combo)->child;
+	if (sel) gtk_entry_set_text(GTK_ENTRY(entry), sel);
+	g_free(sel);
+	gtk_widget_grab_focus(entry);
+
+	cur_dir = utils_get_current_file_dir();
+	dirtext = g_strdup_printf(_("Current directory: %s"), cur_dir);
+	g_free(cur_dir);
+	gtk_label_set_text(GTK_LABEL(dirlabel), dirtext);
+	g_free(dirtext);
+
+	gtk_widget_show(app->find_in_files_dialog);
+}
+
+
 void dialogs_show_includes_arguments_tex(void)
 {
 	GtkWidget *dialog, *label, *entries[4];

Modified: trunk/src/dialogs.h
===================================================================
--- trunk/src/dialogs.h	2006-07-11 17:44:42 UTC (rev 550)
+++ trunk/src/dialogs.h	2006-07-13 14:30:44 UTC (rev 551)
@@ -61,6 +61,8 @@
 
 void dialogs_show_replace(void);
 
+void dialogs_show_find_in_files(void);
+
 void dialogs_show_goto_line(void);
 
 void dialogs_show_includes_arguments_gen(void);

Modified: trunk/src/geany.h
===================================================================
--- trunk/src/geany.h	2006-07-11 17:44:42 UTC (rev 550)
+++ trunk/src/geany.h	2006-07-13 14:30:44 UTC (rev 551)
@@ -78,6 +78,7 @@
 #define GEANY_DEFAULT_TOOLS_TERMINAL	"xterm"
 #define GEANY_DEFAULT_TOOLS_BROWSER		"mozilla"
 #define GEANY_DEFAULT_TOOLS_PRINTCMD	"lpr"
+#define GEANY_DEFAULT_TOOLS_GREP		"grep"
 #define GEANY_DEFAULT_MRU_LENGHTH		10
 #define GEANY_DEFAULT_FONT_SYMBOL_LIST	"Cursor 8"
 #define GEANY_DEFAULT_FONT_MSG_WINDOW	"Cursor 8"
@@ -202,6 +203,7 @@
 	gchar				*tools_make_cmd;
 	gchar				*tools_term_cmd;
 	gchar				*tools_print_cmd;
+	gchar				*tools_grep_cmd;
 	GtkIconSize			 toolbar_icon_size;
 	GtkWidget			*toolbar;
 	GtkWidget			*run_button;
@@ -230,6 +232,7 @@
 	GtkWidget			*prefs_dialog;
 	GtkWidget			*find_dialog;
 	GtkWidget			*replace_dialog;
+	GtkWidget			*find_in_files_dialog;
 	GtkWidget			*default_tag_tree;
 	const TMWorkspace	*tm_workspace;
 	GQueue				*recent_queue;

Modified: trunk/src/interface.c
===================================================================
--- trunk/src/interface.c	2006-07-11 17:44:42 UTC (rev 550)
+++ trunk/src/interface.c	2006-07-13 14:30:44 UTC (rev 551)
@@ -37,7 +37,7 @@
   GtkWidget *menuitem1_menu;
   GtkWidget *menu_new1;
   GtkWidget *menu_new_with_template1;
-  GtkWidget *image791;
+  GtkWidget *image799;
   GtkWidget *menu_new_with_template1_menu;
   GtkWidget *invisible2;
   GtkWidget *separator12;
@@ -49,7 +49,7 @@
   GtkWidget *menu_save1;
   GtkWidget *menu_save_as1;
   GtkWidget *menu_save_all1;
-  GtkWidget *image792;
+  GtkWidget *image800;
   GtkWidget *revert1;
   GtkWidget *separator21;
   GtkWidget *preferences2;
@@ -58,7 +58,7 @@
   GtkWidget *separator14;
   GtkWidget *menu_close1;
   GtkWidget *menu_close_all1;
-  GtkWidget *image793;
+  GtkWidget *image801;
   GtkWidget *menu_separatormenuitem1;
   GtkWidget *menu_quit1;
   GtkWidget *edit1;
@@ -74,11 +74,11 @@
   GtkWidget *menu_select_all1;
   GtkWidget *separator25;
   GtkWidget *insert_include2;
-  GtkWidget *image794;
+  GtkWidget *image802;
   GtkWidget *insert_include2_menu;
   GtkWidget *invisible4;
   GtkWidget *add_comments1;
-  GtkWidget *image795;
+  GtkWidget *image803;
   GtkWidget *add_comments1_menu;
   GtkWidget *menu_add_changelog_entry1;
   GtkWidget *insert_file_header1;
@@ -99,16 +99,18 @@
   GtkWidget *find_next1;
   GtkWidget *find_previous1;
   GtkWidget *replace1;
-  GtkWidget *image796;
+  GtkWidget *image804;
+  GtkWidget *separator27;
+  GtkWidget *find_in_files1;
   GtkWidget *separator11;
   GtkWidget *go_to_line1;
-  GtkWidget *image797;
+  GtkWidget *image805;
   GtkWidget *menuitem3;
   GtkWidget *menuitem3_menu;
   GtkWidget *menu_change_font1;
-  GtkWidget *image798;
+  GtkWidget *image806;
   GtkWidget *menu_choose_color1;
-  GtkWidget *image799;
+  GtkWidget *image807;
   GtkWidget *menu_separator4;
   GtkWidget *menu_fullscreen1;
   GtkWidget *menu_show_messages_window1;
@@ -243,9 +245,9 @@
   gtk_widget_show (menu_new_with_template1);
   gtk_container_add (GTK_CONTAINER (menuitem1_menu), menu_new_with_template1);
 
-  image791 = gtk_image_new_from_stock ("gtk-new", GTK_ICON_SIZE_MENU);
-  gtk_widget_show (image791);
-  gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (menu_new_with_template1), image791);
+  image799 = gtk_image_new_from_stock ("gtk-new", GTK_ICON_SIZE_MENU);
+  gtk_widget_show (image799);
+  gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (menu_new_with_template1), image799);
 
   menu_new_with_template1_menu = gtk_menu_new ();
   gtk_menu_item_set_submenu (GTK_MENU_ITEM (menu_new_with_template1), menu_new_with_template1_menu);
@@ -290,9 +292,9 @@
   gtk_container_add (GTK_CONTAINER (menuitem1_menu), menu_save_all1);
   gtk_tooltips_set_tip (tooltips, menu_save_all1, _("Saves all open files"), NULL);
 
-  image792 = gtk_image_new_from_stock ("gtk-save", GTK_ICON_SIZE_MENU);
-  gtk_widget_show (image792);
-  gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (menu_save_all1), image792);
+  image800 = gtk_image_new_from_stock ("gtk-save", GTK_ICON_SIZE_MENU);
+  gtk_widget_show (image800);
+  gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (menu_save_all1), image800);
 
   revert1 = gtk_image_menu_item_new_from_stock ("gtk-revert-to-saved", accel_group);
   gtk_widget_show (revert1);
@@ -331,9 +333,9 @@
   gtk_container_add (GTK_CONTAINER (menuitem1_menu), menu_close_all1);
   gtk_tooltips_set_tip (tooltips, menu_close_all1, _("Closes all open files"), NULL);
 
-  image793 = gtk_image_new_from_stock ("gtk-close", GTK_ICON_SIZE_MENU);
-  gtk_widget_show (image793);
-  gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (menu_close_all1), image793);
+  image801 = gtk_image_new_from_stock ("gtk-close", GTK_ICON_SIZE_MENU);
+  gtk_widget_show (image801);
+  gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (menu_close_all1), image801);
 
   menu_separatormenuitem1 = gtk_separator_menu_item_new ();
   gtk_widget_show (menu_separatormenuitem1);
@@ -399,9 +401,9 @@
   gtk_widget_show (insert_include2);
   gtk_container_add (GTK_CONTAINER (edit1_menu), insert_include2);
 
-  image794 = gtk_image_new_from_stock ("gtk-add", GTK_ICON_SIZE_MENU);
-  gtk_widget_show (image794);
-  gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (insert_include2), image794);
+  image802 = gtk_image_new_from_stock ("gtk-add", GTK_ICON_SIZE_MENU);
+  gtk_widget_show (image802);
+  gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (insert_include2), image802);
 
   insert_include2_menu = gtk_menu_new ();
   gtk_menu_item_set_submenu (GTK_MENU_ITEM (insert_include2), insert_include2_menu);
@@ -413,9 +415,9 @@
   gtk_widget_show (add_comments1);
   gtk_container_add (GTK_CONTAINER (edit1_menu), add_comments1);
 
-  image795 = gtk_image_new_from_stock ("gtk-add", GTK_ICON_SIZE_MENU);
-  gtk_widget_show (image795);
-  gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (add_comments1), image795);
+  image803 = gtk_image_new_from_stock ("gtk-add", GTK_ICON_SIZE_MENU);
+  gtk_widget_show (image803);
+  gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (add_comments1), image803);
 
   add_comments1_menu = gtk_menu_new ();
   gtk_menu_item_set_submenu (GTK_MENU_ITEM (add_comments1), add_comments1_menu);
@@ -502,10 +504,19 @@
   gtk_widget_show (replace1);
   gtk_container_add (GTK_CONTAINER (search1_menu), replace1);
 
-  image796 = gtk_image_new_from_stock ("gtk-find-and-replace", GTK_ICON_SIZE_MENU);
-  gtk_widget_show (image796);
-  gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (replace1), image796);
+  image804 = gtk_image_new_from_stock ("gtk-find-and-replace", GTK_ICON_SIZE_MENU);
+  gtk_widget_show (image804);
+  gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (replace1), image804);
 
+  separator27 = gtk_separator_menu_item_new ();
+  gtk_widget_show (separator27);
+  gtk_container_add (GTK_CONTAINER (search1_menu), separator27);
+  gtk_widget_set_sensitive (separator27, FALSE);
+
+  find_in_files1 = gtk_menu_item_new_with_mnemonic (_("Find in f_iles"));
+  gtk_widget_show (find_in_files1);
+  gtk_container_add (GTK_CONTAINER (search1_menu), find_in_files1);
+
   separator11 = gtk_separator_menu_item_new ();
   gtk_widget_show (separator11);
   gtk_container_add (GTK_CONTAINER (search1_menu), separator11);
@@ -515,9 +526,9 @@
   gtk_widget_show (go_to_line1);
   gtk_container_add (GTK_CONTAINER (search1_menu), go_to_line1);
 
-  image797 = gtk_image_new_from_stock ("gtk-jump-to", GTK_ICON_SIZE_MENU);
-  gtk_widget_show (image797);
-  gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (go_to_line1), image797);
+  image805 = gtk_image_new_from_stock ("gtk-jump-to", GTK_ICON_SIZE_MENU);
+  gtk_widget_show (image805);
+  gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (go_to_line1), image805);
 
   menuitem3 = gtk_menu_item_new_with_mnemonic (_("_View"));
   gtk_widget_show (menuitem3);
@@ -531,18 +542,18 @@
   gtk_container_add (GTK_CONTAINER (menuitem3_menu), menu_change_font1);
   gtk_tooltips_set_tip (tooltips, menu_change_font1, _("Change the default font"), NULL);
 
-  image798 = gtk_image_new_from_stock ("gtk-select-font", GTK_ICON_SIZE_MENU);
-  gtk_widget_show (image798);
-  gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (menu_change_font1), image798);
+  image806 = gtk_image_new_from_stock ("gtk-select-font", GTK_ICON_SIZE_MENU);
+  gtk_widget_show (image806);
+  gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (menu_change_font1), image806);
 
   menu_choose_color1 = gtk_image_menu_item_new_with_mnemonic (_("Show _Colour Chooser"));
   gtk_widget_show (menu_choose_color1);
   gtk_container_add (GTK_CONTAINER (menuitem3_menu), menu_choose_color1);
   gtk_tooltips_set_tip (tooltips, menu_choose_color1, _("Open a color chooser dialog, to interactively pick colors from a palette."), NULL);
 
-  image799 = gtk_image_new_from_stock ("gtk-select-color", GTK_ICON_SIZE_MENU);
-  gtk_widget_show (image799);
-  gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (menu_choose_color1), image799);
+  image807 = gtk_image_new_from_stock ("gtk-select-color", GTK_ICON_SIZE_MENU);
+  gtk_widget_show (image807);
+  gtk_image_menu_item_set_image (GTK_IMAGE_MENU_ITEM (menu_choose_color1), image807);
 
   menu_separator4 = gtk_separator_menu_item_new ();
   gtk_widget_show (menu_separator4);
@@ -1096,6 +1107,9 @@
   g_signal_connect ((gpointer) replace1, "activate",
                     G_CALLBACK (on_replace1_activate),
                     NULL);
+  g_signal_connect ((gpointer) find_in_files1, "activate",
+                    G_CALLBACK (on_find_in_files1_activate),
+                    NULL);
   g_signal_connect ((gpointer) go_to_line1, "activate",
                     G_CALLBACK (on_go_to_line1_activate),
                     NULL);
@@ -1250,7 +1264,7 @@
   GLADE_HOOKUP_OBJECT (window1, menuitem1_menu, "menuitem1_menu");
   GLADE_HOOKUP_OBJECT (window1, menu_new1, "menu_new1");
   GLADE_HOOKUP_OBJECT (window1, menu_new_with_template1, "menu_new_with_template1");
-  GLADE_HOOKUP_OBJECT (window1, image791, "image791");
+  GLADE_HOOKUP_OBJECT (window1, image799, "image799");
   GLADE_HOOKUP_OBJECT (window1, menu_new_with_template1_menu, "menu_new_with_template1_menu");
   GLADE_HOOKUP_OBJECT (window1, invisible2, "invisible2");
   GLADE_HOOKUP_OBJECT (window1, separator12, "separator12");
@@ -1262,7 +1276,7 @@
   GLADE_HOOKUP_OBJECT (window1, menu_save1, "menu_save1");
   GLADE_HOOKUP_OBJECT (window1, menu_save_as1, "menu_save_as1");
   GLADE_HOOKUP_OBJECT (window1, menu_save_all1, "menu_save_all1");
-  GLADE_HOOKUP_OBJECT (window1, image792, "image792");
+  GLADE_HOOKUP_OBJECT (window1, image800, "image800");
   GLADE_HOOKUP_OBJECT (window1, revert1, "revert1");
   GLADE_HOOKUP_OBJECT (window1, separator21, "separator21");
   GLADE_HOOKUP_OBJECT (window1, preferences2, "preferences2");
@@ -1271,7 +1285,7 @@
   GLADE_HOOKUP_OBJECT (window1, separator14, "separator14");
   GLADE_HOOKUP_OBJECT (window1, menu_close1, "menu_close1");
   GLADE_HOOKUP_OBJECT (window1, menu_close_all1, "menu_close_all1");
-  GLADE_HOOKUP_OBJECT (window1, image793, "image793");
+  GLADE_HOOKUP_OBJECT (window1, image801, "image801");
   GLADE_HOOKUP_OBJECT (window1, menu_separatormenuitem1, "menu_separatormenuitem1");
   GLADE_HOOKUP_OBJECT (window1, menu_quit1, "menu_quit1");
   GLADE_HOOKUP_OBJECT (window1, edit1, "edit1");
@@ -1287,11 +1301,11 @@
   GLADE_HOOKUP_OBJECT (window1, menu_select_all1, "menu_select_all1");
   GLADE_HOOKUP_OBJECT (window1, separator25, "separator25");
   GLADE_HOOKUP_OBJECT (window1, insert_include2, "insert_include2");
-  GLADE_HOOKUP_OBJECT (window1, image794, "image794");
+  GLADE_HOOKUP_OBJECT (window1, image802, "image802");
   GLADE_HOOKUP_OBJECT (window1, insert_include2_menu, "insert_include2_menu");
   GLADE_HOOKUP_OBJECT (window1, invisible4, "invisible4");
   GLADE_HOOKUP_OBJECT (window1, add_comments1, "add_comments1");
-  GLADE_HOOKUP_OBJECT (window1, image795, "image795");
+  GLADE_HOOKUP_OBJECT (window1, image803, "image803");
   GLADE_HOOKUP_OBJECT (window1, add_comments1_menu, "add_comments1_menu");
   GLADE_HOOKUP_OBJECT (window1, menu_add_changelog_entry1, "menu_add_changelog_entry1");
   GLADE_HOOKUP_OBJECT (window1, insert_file_header1, "insert_file_header1");
@@ -1312,16 +1326,18 @@
   GLADE_HOOKUP_OBJECT (window1, find_next1, "find_next1");
   GLADE_HOOKUP_OBJECT (window1, find_previous1, "find_previous1");
   GLADE_HOOKUP_OBJECT (window1, replace1, "replace1");
-  GLADE_HOOKUP_OBJECT (window1, image796, "image796");
+  GLADE_HOOKUP_OBJECT (window1, image804, "image804");
+  GLADE_HOOKUP_OBJECT (window1, separator27, "separator27");
+  GLADE_HOOKUP_OBJECT (window1, find_in_files1, "find_in_files1");
   GLADE_HOOKUP_OBJECT (window1, separator11, "separator11");
   GLADE_HOOKUP_OBJECT (window1, go_to_line1, "go_to_line1");
-  GLADE_HOOKUP_OBJECT (window1, image797, "image797");
+  GLADE_HOOKUP_OBJECT (window1, image805, "image805");
   GLADE_HOOKUP_OBJECT (window1, menuitem3, "menuitem3");
   GLADE_HOOKUP_OBJECT (window1, menuitem3_menu, "menuitem3_menu");
   GLADE_HOOKUP_OBJECT (window1, menu_change_font1, "menu_change_font1");
-  GLADE_HOOKUP_OBJECT (window1, image798, "image798");
+  GLADE_HOOKUP_OBJECT (window1, image806, "image806");
   GLADE_HOOKUP_OBJECT (window1, menu_choose_color1, "menu_choose_color1");
-  GLADE_HOOKUP_OBJECT (window1, image799, "image799");
+  GLADE_HOOKUP_OBJECT (window1, image807, "image807");
   GLADE_HOOKUP_OBJECT (window1, menu_separator4, "menu_separator4");
   GLADE_HOOKUP_OBJECT (window1, menu_fullscreen1, "menu_fullscreen1");
   GLADE_HOOKUP_OBJECT (window1, menu_show_messages_window1, "menu_show_messages_window1");
@@ -2005,6 +2021,10 @@
   GtkWidget *entry_print;
   GtkWidget *button_print;
   GtkWidget *image763;
+  GtkWidget *label171;
+  GtkWidget *entry_grep;
+  GtkWidget *button_grep;
+  GtkWidget *image808;
   GtkWidget *label96;
   GtkWidget *vbox9;
   GtkWidget *label120;
@@ -2769,7 +2789,7 @@
   gtk_box_pack_start (GTK_BOX (vbox2), label17, FALSE, FALSE, 0);
   gtk_misc_set_padding (GTK_MISC (label17), 0, 6);
 
-  table1 = gtk_table_new (4, 3, FALSE);
+  table1 = gtk_table_new (5, 3, FALSE);
   gtk_widget_show (table1);
   gtk_box_pack_start (GTK_BOX (vbox2), table1, TRUE, TRUE, 0);
   gtk_table_set_row_spacings (GTK_TABLE (table1), 7);
@@ -2871,6 +2891,29 @@
   gtk_widget_show (image763);
   gtk_container_add (GTK_CONTAINER (button_print), image763);
 
+  label171 = gtk_label_new (_("Grep"));
+  gtk_widget_show (label171);
+  gtk_table_attach (GTK_TABLE (table1), label171, 0, 1, 4, 5,
+                    (GtkAttachOptions) (GTK_FILL),
+                    (GtkAttachOptions) (0), 0, 0);
+  gtk_misc_set_alignment (GTK_MISC (label171), 0, 0.5);
+
+  entry_grep = gtk_entry_new ();
+  gtk_widget_show (entry_grep);
+  gtk_table_attach (GTK_TABLE (table1), entry_grep, 1, 2, 4, 5,
+                    (GtkAttachOptions) (GTK_EXPAND | GTK_FILL),
+                    (GtkAttachOptions) (0), 0, 0);
+
+  button_grep = gtk_button_new ();
+  gtk_widget_show (button_grep);
+  gtk_table_attach (GTK_TABLE (table1), button_grep, 2, 3, 4, 5,
+                    (GtkAttachOptions) (GTK_FILL),
+                    (GtkAttachOptions) (0), 0, 0);
+
+  image808 = gtk_image_new_from_stock ("gtk-directory", GTK_ICON_SIZE_BUTTON);
+  gtk_widget_show (image808);
+  gtk_container_add (GTK_CONTAINER (button_grep), image808);
+
   label96 = gtk_label_new (_("Tools"));
   gtk_widget_show (label96);
   gtk_notebook_set_tab_label (GTK_NOTEBOOK (notebook2), gtk_notebook_get_nth_page (GTK_NOTEBOOK (notebook2), 4), label96);
@@ -3159,6 +3202,10 @@
   GLADE_HOOKUP_OBJECT (prefs_dialog, entry_print, "entry_print");
   GLADE_HOOKUP_OBJECT (prefs_dialog, button_print, "button_print");
   GLADE_HOOKUP_OBJECT (prefs_dialog, image763, "image763");
+  GLADE_HOOKUP_OBJECT (prefs_dialog, label171, "label171");
+  GLADE_HOOKUP_OBJECT (prefs_dialog, entry_grep, "entry_grep");
+  GLADE_HOOKUP_OBJECT (prefs_dialog, button_grep, "button_grep");
+  GLADE_HOOKUP_OBJECT (prefs_dialog, image808, "image808");
   GLADE_HOOKUP_OBJECT (prefs_dialog, label96, "label96");
   GLADE_HOOKUP_OBJECT (prefs_dialog, vbox9, "vbox9");
   GLADE_HOOKUP_OBJECT (prefs_dialog, label120, "label120");

Modified: trunk/src/keyfile.c
===================================================================
--- trunk/src/keyfile.c	2006-07-11 17:44:42 UTC (rev 550)
+++ trunk/src/keyfile.c	2006-07-13 14:30:44 UTC (rev 551)
@@ -145,6 +145,7 @@
 	g_key_file_set_string(config, "tools", "term_cmd", app->tools_term_cmd ? app->tools_term_cmd : "");
 	g_key_file_set_string(config, "tools", "browser_cmd", app->tools_browser_cmd ? app->tools_browser_cmd : "");
 	g_key_file_set_string(config, "tools", "print_cmd", app->tools_print_cmd ? app->tools_print_cmd : "");
+	g_key_file_set_string(config, "tools", "grep_cmd", app->tools_grep_cmd? app->tools_grep_cmd: "");
 
 	for (i = 0; i < app->mru_length; i++)
 	{
@@ -337,6 +338,10 @@
 	g_free(tmp_string);
 	g_free(tmp_string2);
 
+	tmp_string = g_find_program_in_path(GEANY_DEFAULT_TOOLS_GREP);
+	app->tools_grep_cmd = utils_get_setting_string(config, "tools", "grep_cmd", tmp_string);
+	g_free(tmp_string);
+
 	recent_files = g_key_file_get_string_list(config, "files", "recent_files", &len, NULL);
 	if (recent_files != NULL)
 	{

Modified: trunk/src/main.c
===================================================================
--- trunk/src/main.c	2006-07-11 17:44:42 UTC (rev 550)
+++ trunk/src/main.c	2006-07-13 14:30:44 UTC (rev 551)
@@ -217,6 +217,7 @@
 	app->prefs_dialog		= NULL;
 	app->find_dialog		= NULL;
 	app->replace_dialog		= NULL;
+	app->find_in_files_dialog = NULL;
 	app->default_tag_tree	= NULL;
 	app->main_window_realized= FALSE;
 	app->tab_order_ltr		= FALSE;

Modified: trunk/src/msgwindow.c
===================================================================
--- trunk/src/msgwindow.c	2006-07-11 17:44:42 UTC (rev 550)
+++ trunk/src/msgwindow.c	2006-07-13 14:30:44 UTC (rev 551)
@@ -29,11 +29,19 @@
 #include "callbacks.h"
 #include "msgwindow.h"
 #include "utils.h"
+#include "search.h"
+#include "document.h"
 
+#include <string.h>
+#include <stdlib.h>
+
+
 static GdkColor dark = {0, 58832, 58832, 58832};
 static GdkColor white = {0, 65535, 65535, 65535};
 
+static void msgwin_parse_grep_line(const gchar *string, gchar **filename, gint *line);
 
+
 /* does some preparing things to the status message list widget */
 void msgwin_prepare_status_tree_view(void)
 {
@@ -235,3 +243,139 @@
 	return message_popup_menu;
 }
 
+
+gboolean msgwin_goto_compiler_file_line()
+{
+	GtkTreeIter iter;
+	GtkTreeModel *model;
+	GtkTreeSelection *selection;
+	gchar *string;
+	gboolean ret = FALSE;
+
+	selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(msgwindow.tree_compiler));
+	if (gtk_tree_selection_get_selected(selection, &model, &iter))
+	{
+		gtk_tree_model_get(model, &iter, 1, &string, -1);
+		if (string != NULL)
+		{
+			gint line;
+			gint idx;
+			gchar *filename;
+			utils_parse_compiler_error_line(string, &filename, &line);
+			if (filename != NULL && line > -1)
+			{
+				// use document_open_file to find an already open file, or open it in place
+				idx = document_open_file(-1, filename, 0, FALSE, NULL);
+				// document_set_indicator will check valid idx
+				document_set_indicator(idx, line - 1);
+				// utils_goto_file_line will check valid filename.
+				ret = utils_goto_file_line(filename, FALSE, line);
+			}
+			g_free(filename);
+		}
+		g_free(string);
+	}
+	return ret;
+}
+
+
+gboolean msgwin_goto_messages_file_line()
+{
+	GtkTreeIter iter;
+	GtkTreeModel *model;
+	GtkTreeSelection *selection;
+	gboolean ret = FALSE;
+
+	selection = gtk_tree_view_get_selection(GTK_TREE_VIEW(msgwindow.tree_msg));
+	if (gtk_tree_selection_get_selected(selection, &model, &iter))
+	{
+		gint idx, line;
+		gchar *string;
+
+		gtk_tree_model_get(model, &iter, 0, &line, 1, &idx, 3, &string, -1);
+		if (line >= 0 && idx >= 0)
+			utils_goto_line(idx, line); //checks valid idx
+		else if (line < 0 && string != NULL)
+		{
+			gchar *filename;
+			msgwin_parse_grep_line(string, &filename, &line);
+			if (filename != NULL && line > -1)
+			{
+				// use document_open_file to find an already open file, or open it in place
+				idx = document_open_file(-1, filename, 0, FALSE, NULL);
+				// utils_goto_file_line will check valid filename.
+				ret = utils_goto_file_line(filename, FALSE, line);
+			}
+			g_free(filename);
+		}
+		g_free(string);
+	}
+	return ret;
+}
+
+
+// Taken from utils_parse_compiler_error_line, could refactor both (keep get_cur_idx).
+/* Try to parse the file and line number for string and when something useful is
+ * found, store the line number in *line and the relevant file with the error in
+ * *filename.
+ * *line will be -1 if no error was found in string. 
+ * *filename must be freed unless NULL. */
+static void msgwin_parse_grep_line(const gchar *string, gchar **filename, gint *line)
+{
+	gchar *end = NULL;
+	gchar *path;
+	gchar **fields;
+	gchar *pattern;				// pattern to split the error message into some fields
+	guint field_min_len;		// used to detect errors after parsing
+	guint field_idx_line;		// idx of the field where the line is
+	guint field_idx_file;		// idx of the field where the filename is
+	guint skip_dot_slash = 0;	// number of characters to skip at the beginning of the filename
+	gint cur_idx;
+
+	*filename = NULL;
+	*line = -1;
+
+	if (string == NULL) return;
+
+	// conflict:3:conflicting types for `foo'
+	pattern = ":";
+	field_min_len = 3;
+	field_idx_line = 1;
+	field_idx_file = 0;
+
+	fields = g_strsplit_set(string, pattern, field_min_len);
+
+	// parse the line
+	if (g_strv_length(fields) < field_min_len)
+	{
+		g_strfreev(fields);
+		return;
+	}
+
+	*line = strtol(fields[field_idx_line], &end, 10);
+
+	// if the line could not be read, line is 0 and an error occurred, so we leave
+	if (fields[field_idx_line] == end)
+	{
+		g_strfreev(fields);
+		return;
+	}
+
+	// skip some characters at the beginning of the filename, at the moment only "./"
+	// can be extended if other "trash" is known
+	if (strncmp(fields[field_idx_file], "./", 2) == 0) skip_dot_slash = 2;
+
+	// get the basename of the built file to get the path to look for other files
+	cur_idx = document_get_cur_idx();
+	if (cur_idx >= 0 && doc_list[cur_idx].is_valid)
+	{
+		path = g_path_get_dirname(doc_list[cur_idx].file_name);
+		*filename = g_strconcat(path, G_DIR_SEPARATOR_S,
+			fields[field_idx_file] + skip_dot_slash, NULL);
+		g_free(path);
+	}
+
+	g_strfreev(fields);
+}
+
+

Modified: trunk/src/msgwindow.h
===================================================================
--- trunk/src/msgwindow.h	2006-07-11 17:44:42 UTC (rev 550)
+++ trunk/src/msgwindow.h	2006-07-13 14:30:44 UTC (rev 551)
@@ -73,4 +73,8 @@
 
 GtkWidget *msgwin_create_message_popup_menu(gint type);
 
+gboolean msgwin_goto_compiler_file_line();
+
+gboolean msgwin_goto_messages_file_line();
+
 #endif

Modified: trunk/src/prefs.c
===================================================================
--- trunk/src/prefs.c	2006-07-11 17:44:42 UTC (rev 550)
+++ trunk/src/prefs.c	2006-07-13 14:30:44 UTC (rev 551)
@@ -227,7 +227,7 @@
 
 	// Tools Settings
 #ifdef GEANY_WIN32
-        // hide related Terminal path setting
+        // hide related Make path setting
         gtk_widget_set_sensitive(lookup_widget(app->prefs_dialog, "label11"), FALSE);
         gtk_widget_set_sensitive(lookup_widget(app->prefs_dialog, "entry_com_make"), FALSE);
         gtk_widget_set_sensitive(lookup_widget(app->prefs_dialog, "button_make"), FALSE);
@@ -246,10 +246,13 @@
 	if (app->tools_browser_cmd)
 		gtk_entry_set_text(GTK_ENTRY(lookup_widget(app->prefs_dialog, "entry_browser")), app->tools_browser_cmd);
 
-	if (app->tools_browser_cmd)
+	if (app->tools_print_cmd)
 		gtk_entry_set_text(GTK_ENTRY(lookup_widget(app->prefs_dialog, "entry_print")), app->tools_print_cmd);
 
+	if (app->tools_grep_cmd)
+		gtk_entry_set_text(GTK_ENTRY(lookup_widget(app->prefs_dialog, "entry_grep")), app->tools_grep_cmd);
 
+
 	// Template settings
 	widget = lookup_widget(app->prefs_dialog, "entry_template_developer");
 	gtk_entry_set_text(GTK_ENTRY(widget), app->pref_template_developer);
@@ -512,7 +515,11 @@
 		g_free(app->tools_print_cmd);
 		app->tools_print_cmd = g_strdup(gtk_entry_get_text(GTK_ENTRY(widget)));
 
+		widget = lookup_widget(app->prefs_dialog, "entry_grep");
+		g_free(app->tools_grep_cmd);
+		app->tools_grep_cmd = g_strdup(gtk_entry_get_text(GTK_ENTRY(widget)));
 
+
 		// Template settings
 		widget = lookup_widget(app->prefs_dialog, "entry_template_developer");
 		g_free(app->pref_template_developer);
@@ -1070,6 +1077,8 @@
 				"clicked", G_CALLBACK(on_pref_tools_button_clicked), lookup_widget(app->prefs_dialog, "entry_browser"));
 		g_signal_connect((gpointer) lookup_widget(app->prefs_dialog, "button_print"),
 				"clicked", G_CALLBACK(on_pref_tools_button_clicked), lookup_widget(app->prefs_dialog, "entry_print"));
+		g_signal_connect((gpointer) lookup_widget(app->prefs_dialog, "button_grep"),
+				"clicked", G_CALLBACK(on_pref_tools_button_clicked), lookup_widget(app->prefs_dialog, "entry_grep"));
 
 		g_signal_connect((gpointer) lookup_widget(app->prefs_dialog, "check_toolbar_show"),
 				"toggled", G_CALLBACK(on_pref_toolbar_show_toggled), NULL);

Added: trunk/src/search.c
===================================================================
--- trunk/src/search.c	                        (rev 0)
+++ trunk/src/search.c	2006-07-13 14:30:44 UTC (rev 551)
@@ -0,0 +1,214 @@
+/*
+ *      search.c
+ *
+ *      Copyright 2006 Nick Treleaven <nick.treleaven at btinternet.com>
+ *
+ *      This program is free software; you can redistribute it and/or modify
+ *      it under the terms of the GNU General Public License as published by
+ *      the Free Software Foundation; either version 2 of the License, or
+ *      (at your option) any later version.
+ *
+ *      This program is distributed in the hope that it will be useful,
+ *      but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *      GNU General Public License for more details.
+ *
+ *      You should have received a copy of the GNU General Public License
+ *      along with this program; if not, write to the Free Software
+ *      Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $Id$
+ */
+
+#include "geany.h"
+#include "search.h"
+#include "support.h"
+#include "utils.h"
+#include "msgwindow.h"
+
+#include <unistd.h>
+#include <stdlib.h>
+
+#ifdef G_OS_UNIX
+# include <sys/types.h>
+# include <sys/wait.h>
+#endif
+
+
+static gboolean search_read_io              (GIOChannel *source,
+                                             GIOCondition condition,
+                                             gpointer data);
+
+static void search_close_pid(GPid child_pid, gint status, gpointer user_data);
+
+static gchar **search_get_argv(const gchar **argv_prefix, const gchar *dir);
+
+static GSList *search_get_file_list(const gchar *path, gint *length);
+
+
+gboolean search_find_in_files(const gchar *search_text, const gchar *dir)
+{
+	const gchar *argv_prefix[] = {app->tools_grep_cmd, "-nHI", "--", search_text, NULL};
+	gchar **argv;
+	GPid child_pid;
+	gint stdout_fd, stdin_fd;
+	GError *error = NULL;
+	gboolean ret = FALSE;
+
+	if (! search_text || ! *search_text || ! dir) return TRUE;
+	if (! g_file_test(app->tools_grep_cmd, G_FILE_TEST_IS_EXECUTABLE))
+	{
+		msgwin_status_add(_("Cannot execute grep tool '%s';"
+			" check the path setting in Preferences."), argv_prefix[0]);
+		return FALSE;
+	}
+
+	gtk_list_store_clear(msgwindow.store_msg);
+	gtk_notebook_set_current_page(GTK_NOTEBOOK(msgwindow.notebook), MSG_MESSAGE);
+
+	argv = search_get_argv(argv_prefix, dir);
+	if (argv == NULL) return FALSE;
+
+	if (! g_spawn_async_with_pipes(dir, (gchar**)argv, NULL,
+		G_SPAWN_STDERR_TO_DEV_NULL | G_SPAWN_DO_NOT_REAP_CHILD,
+		NULL, NULL, &child_pid,
+		&stdin_fd, &stdout_fd, NULL, &error))
+	{
+		geany_debug("%s: g_spawn_async_with_pipes() failed: %s", __func__, error->message);
+		msgwin_status_add(_("Process failed (%s)"), error->message);
+		g_error_free(error);
+		ret = FALSE;
+	}
+	else
+	{
+		g_child_watch_add(child_pid, search_close_pid, NULL);
+		utils_set_up_io_channel(stdout_fd, G_IO_IN|G_IO_PRI|G_IO_ERR|G_IO_HUP|G_IO_NVAL,
+			search_read_io, NULL);
+		ret = TRUE;
+	}
+	g_strfreev(argv);
+	return ret;
+}
+
+
+/* Creates an argument vector of strings, copying argv_prefix[] values for
+ * the first arguments, then followed by filenames found in dir.
+ * Returns NULL if no files were found, otherwise returned vector should be fully freed. */
+static gchar **search_get_argv(const gchar **argv_prefix, const gchar *dir)
+{
+	guint prefix_len, list_len, i, j;
+	gchar **argv;
+	GSList *list, *item;
+	g_return_val_if_fail(dir != NULL, NULL);
+
+	prefix_len = g_strv_length((gchar**)argv_prefix);
+	list = search_get_file_list(dir, &list_len);
+	if (list == NULL) return NULL;
+
+	argv = g_new(gchar*, prefix_len + list_len + 1);
+
+	for (i = 0; i < prefix_len; i++)
+		argv[i] = g_strdup(argv_prefix[i]);
+
+	item = list;
+	for (j = 0; j < list_len; j++)
+	{
+		argv[i++] = item->data;
+		item = g_slist_next(item);
+	}
+	argv[i] = NULL;
+
+	g_slist_free(list);
+	return argv;
+}
+
+
+/* Gets a list of files in the current directory, or NULL if no files found.
+ * The list and the data in the list should be freed after use.
+ * *length is set to the number of non-NULL data items in the list. */
+static GSList *search_get_file_list(const gchar *path, gint *length)
+{
+	GError *error = NULL;
+	GSList *list = NULL;
+	gint len = 0;
+	const gchar *filename;
+	GDir *dir;
+	g_return_val_if_fail(path != NULL, NULL);
+
+	dir = g_dir_open(path, 0, &error);
+	if (error)
+	{
+		geany_debug("Could not open directory (%s)", error->message);
+		g_error_free(error);
+		*length = 0;
+		return NULL;
+	}
+	do
+	{
+		filename = g_dir_read_name(dir);
+		list = g_slist_append(list, g_strdup(filename));
+		len++;
+	} while (filename != NULL);
+
+	g_dir_close(dir);
+	len--; //subtract 1 for the last null data element.
+	*length = len;
+	if (len == 0)
+	{
+		g_slist_free(list);
+		return NULL;
+	}
+	return list;
+}
+
+
+static gboolean search_read_io              (GIOChannel *source,
+                                             GIOCondition condition,
+                                             gpointer data)
+{
+	if (condition & (G_IO_IN | G_IO_PRI))
+	{
+		//GIOStatus s;
+		gchar *msg;
+
+		while (g_io_channel_read_line(source, &msg, NULL, NULL, NULL) && msg)
+		{
+			//if (s != G_IO_STATUS_NORMAL && s != G_IO_STATUS_EOF) break;
+			msgwin_msg_add(-1, -1, g_strstrip(msg));
+			g_free(msg);
+		}
+	}
+	if (condition & (G_IO_ERR | G_IO_HUP | G_IO_NVAL))
+		return FALSE;
+
+	return TRUE;
+}
+
+
+static void search_close_pid(GPid child_pid, gint status, gpointer user_data)
+{
+#ifdef G_OS_UNIX
+	gboolean failure = FALSE;
+
+	if (WIFEXITED(status))
+	{
+		if (WEXITSTATUS(status) != EXIT_SUCCESS)
+			failure = TRUE;
+	}
+	else if (WIFSIGNALED(status))
+	{
+		// the terminating signal: WTERMSIG (status));
+		failure = TRUE;
+	}
+	else
+	{	// any other failure occured
+		failure = TRUE;
+	}
+
+	msgwin_msg_add(-1, -1, (failure) ? _("Search failed.") : _("Search completed."));
+#endif
+	utils_beep();
+	g_spawn_close_pid(child_pid);
+}
+
+


Property changes on: trunk/src/search.c
___________________________________________________________________
Name: svn:keywords
   + Author Date Id Revision
Name: svn:eol-style
   + native

Added: trunk/src/search.h
===================================================================
--- trunk/src/search.h	                        (rev 0)
+++ trunk/src/search.h	2006-07-13 14:30:44 UTC (rev 551)
@@ -0,0 +1,25 @@
+/*
+ *      search.h
+ *
+ *      Copyright 2006 Nick Treleaven <nick.treleaven at btinternet.com>
+ *
+ *      This program is free software; you can redistribute it and/or modify
+ *      it under the terms of the GNU General Public License as published by
+ *      the Free Software Foundation; either version 2 of the License, or
+ *      (at your option) any later version.
+ *
+ *      This program is distributed in the hope that it will be useful,
+ *      but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *      GNU General Public License for more details.
+ *
+ *      You should have received a copy of the GNU General Public License
+ *      along with this program; if not, write to the Free Software
+ *      Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * $Id$
+ */
+
+
+gboolean search_find_in_files(const gchar *search_text, const gchar *dir);
+


Property changes on: trunk/src/search.h
___________________________________________________________________
Name: svn:keywords
   + Author Date Id Revision
Name: svn:eol-style
   + native

Modified: trunk/src/utils.c
===================================================================
--- trunk/src/utils.c	2006-07-11 17:44:42 UTC (rev 550)
+++ trunk/src/utils.c	2006-07-13 14:30:44 UTC (rev 551)
@@ -2520,6 +2520,35 @@
 }
 
 
+GIOChannel *utils_set_up_io_channel(gint fd, GIOCondition cond, GIOFunc func, gpointer data)
+{
+	GIOChannel *ioc;
+	GError *error = NULL;
+	const gchar *encoding;
+
+	ioc = g_io_channel_unix_new(fd);
+
+	g_io_channel_set_flags(ioc, G_IO_FLAG_NONBLOCK, NULL);
+	if (! g_get_charset(&encoding))
+	{	// hope this works reliably
+		g_io_channel_set_encoding(ioc, encoding, &error);
+		if (error)
+		{
+			geany_debug("%s: %s", __func__, error->message);
+			g_error_free(error);
+			return ioc;
+		}
+	}
+	// "auto-close" ;-)
+	g_io_channel_set_close_on_unref(ioc, TRUE);
+
+	g_io_add_watch(ioc, cond, func, data);
+	g_io_channel_unref(ioc);
+
+	return ioc;
+}
+
+
 void utils_update_toolbar_items(void)
 {
 	// show toolbar

Modified: trunk/src/utils.h
===================================================================
--- trunk/src/utils.h	2006-07-11 17:44:42 UTC (rev 550)
+++ trunk/src/utils.h	2006-07-13 14:30:44 UTC (rev 551)
@@ -222,6 +222,8 @@
 
 TMTag *utils_find_tm_tag(const GPtrArray *tags, const gchar *tag_name);
 
+GIOChannel *utils_set_up_io_channel(gint fd, GIOCondition cond, GIOFunc func, gpointer data);
+
 void utils_update_toolbar_items(void);
 
 #endif


This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site.




More information about the Commits mailing list