25 |
|
|
26 |
#include <gtk/gtk.h> |
#include <gtk/gtk.h> |
27 |
#include <stdio.h> |
#include <stdio.h> |
28 |
|
#include <stdlib.h> |
29 |
#include <string.h> |
#include <string.h> |
30 |
#include <ctype.h> |
#include <ctype.h> |
31 |
#include <sys/stat.h> |
#include <sys/stat.h> |
32 |
#include "main.h" |
#include <sys/types.h> |
33 |
|
#include <sys/wait.h> |
34 |
|
#include <unistd.h> |
35 |
|
#include <wordexp.h> |
36 |
#include "tools.h" |
#include "tools.h" |
37 |
#include "editor.h" |
#include "editor.h" |
38 |
#include "struct.h" |
#include "struct.h" |
39 |
#include "msgbar.h" |
#include "msgbar.h" |
40 |
#include "prefs.h" |
#include "prefs.h" |
41 |
|
#include "main.h" |
42 |
#include "search.h" |
#include "search.h" |
43 |
|
#include "filesops.h" |
44 |
|
|
45 |
extern GArray *FileProperties; |
extern GArray *FileProperties; |
46 |
extern GtkWidget *MainNotebook; |
extern GtkWidget *MainNotebook; |
47 |
|
extern GtkWidget *MainWindow; |
48 |
|
extern GtkWidget *MainVBox; |
49 |
extern gint OpenedFilesCnt; |
extern gint OpenedFilesCnt; |
50 |
extern t_settings Settings; |
extern t_settings Settings; |
|
static gboolean SearchIsVisible = FALSE; |
|
51 |
static gboolean GotoLineIsVisible = FALSE; |
static gboolean GotoLineIsVisible = FALSE; |
52 |
static t_search_prefs *SearchPrefs; |
|
53 |
static GtkWidget *SearchEntry; |
static GtkWidget *SearchDisplay = NULL; |
54 |
static GtkWidget *ReplaceEntry; |
static GtkWidget *SearchTree = NULL; |
55 |
static GtkWidget *List; |
|
56 |
|
struct line_match |
57 |
|
{ |
58 |
|
gint line; |
59 |
|
gchar *text; |
60 |
|
}; |
61 |
|
|
62 |
|
struct file_results |
63 |
|
{ |
64 |
|
GtkWidget *buffer; // NULL if not from a buffer or buffer is closed |
65 |
|
gchar *path; // Full path of file/buffer |
66 |
|
|
67 |
|
GPtrArray *results; |
68 |
|
}; |
69 |
|
|
70 |
|
void ensure_search_display (void) |
71 |
|
{ |
72 |
|
START_FCN |
73 |
|
|
74 |
|
if (!SearchDisplay) |
75 |
|
{ |
76 |
|
SearchDisplay = gtk_vpaned_new (); |
77 |
|
GtkCellRenderer *renderer; |
78 |
|
GtkWidget *scroller; |
79 |
|
|
80 |
|
g_signal_connect_swapped (G_OBJECT (SearchDisplay), "destroy", |
81 |
|
G_CALLBACK (g_nullify_pointer), &SearchDisplay); |
82 |
|
|
83 |
|
g_object_ref (MainNotebook); |
84 |
|
gtk_container_remove (GTK_CONTAINER (MainVBox), MainNotebook); |
85 |
|
|
86 |
|
gtk_paned_pack1 (GTK_PANED (SearchDisplay), MainNotebook, TRUE, TRUE); |
87 |
|
g_object_unref (MainNotebook); |
88 |
|
|
89 |
|
scroller = gtk_scrolled_window_new (NULL, NULL); |
90 |
|
gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (scroller), |
91 |
|
GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); |
92 |
|
|
93 |
|
SearchTree = gtk_tree_view_new (); |
94 |
|
|
95 |
|
gtk_container_add (GTK_CONTAINER (scroller), SearchTree); |
96 |
|
gtk_paned_pack2 (GTK_PANED (SearchDisplay), scroller, FALSE, TRUE); |
97 |
|
|
98 |
|
/* add the column */ |
99 |
|
renderer = gtk_cell_renderer_text_new (); |
100 |
|
gtk_tree_view_insert_column_with_attributes (GTK_TREE_VIEW (SearchTree), |
101 |
|
-1, "Match", |
102 |
|
renderer, "text", |
103 |
|
0, |
104 |
|
NULL); |
105 |
|
|
106 |
|
gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (SearchTree), FALSE); |
107 |
|
gtk_tree_view_set_search_column (GTK_TREE_VIEW (SearchTree), 0); |
108 |
|
|
109 |
|
gtk_container_add (GTK_CONTAINER (MainVBox), SearchDisplay); |
110 |
|
gtk_widget_show_all (SearchDisplay); |
111 |
|
} |
112 |
|
|
113 |
|
END_FCN |
114 |
|
} |
115 |
|
|
116 |
|
void display_search_results (GArray *array) |
117 |
|
{ |
118 |
|
gint i, j; |
119 |
|
GtkTreeStore *store; |
120 |
|
|
121 |
|
START_FCN |
122 |
|
|
123 |
|
ensure_search_display (); |
124 |
|
|
125 |
|
store = gtk_tree_store_new (1, G_TYPE_STRING); |
126 |
|
|
127 |
|
for (i = 0; i < array->len; i++) |
128 |
|
{ |
129 |
|
GtkTreeIter iter, parent; |
130 |
|
gint max_size; |
131 |
|
struct line_match *match; |
132 |
|
GPtrArray *results; |
133 |
|
gchar *max_line; |
134 |
|
|
135 |
|
gtk_tree_store_append (store, &parent, NULL); |
136 |
|
gtk_tree_store_set (store, &parent, 0, |
137 |
|
str_get_last_part ( |
138 |
|
g_array_index (array, struct file_results, i).path, |
139 |
|
PATH_SEP, TRUE), |
140 |
|
-1); |
141 |
|
|
142 |
|
results = g_array_index (array, struct file_results, i).results; |
143 |
|
|
144 |
|
// calculate the maximum number of digits in any of the line numbers |
145 |
|
match = g_ptr_array_index (results, results->len - 1); |
146 |
|
max_line = g_strdup_printf ("%i", match->line); |
147 |
|
max_size = strlen (max_line); |
148 |
|
g_free (max_line); |
149 |
|
|
150 |
|
for (j = 0; j < results->len; j++) |
151 |
|
{ |
152 |
|
gchar *output; |
153 |
|
|
154 |
|
match = g_ptr_array_index (results, j); |
155 |
|
|
156 |
|
gtk_tree_store_append (store, &iter, &parent); |
157 |
|
output = g_strdup_printf ("%*i %s", max_size, match->line, match->text); |
158 |
|
gtk_tree_store_set (store, &iter, 0, output, -1); |
159 |
|
g_free (output); |
160 |
|
} |
161 |
|
} |
162 |
|
|
163 |
|
gtk_tree_view_set_model (GTK_TREE_VIEW (SearchTree), GTK_TREE_MODEL (store)); |
164 |
|
g_object_unref (store); |
165 |
|
gtk_widget_show_all (SearchTree); |
166 |
|
|
167 |
|
END_FCN |
168 |
|
} |
169 |
|
|
170 |
/* A sort of 'strcmp' for the characters: it returns '0' if the characteres |
/* A sort of 'strcmp' for the characters: it returns '0' if the characteres |
171 |
are the same */ |
are the same */ |
293 |
void goto_search (GtkList *MyList, |
void goto_search (GtkList *MyList, |
294 |
GtkWidget *Widget) |
GtkWidget *Widget) |
295 |
{ |
{ |
296 |
gint CurrentPage; |
} |
297 |
|
|
298 |
if (!OpenedFilesCnt) |
|
299 |
{ |
|
300 |
print_msg (_("Cannot refer to file: you closed all files!")); |
/* Used to set up Search preferences */ |
301 |
return; |
|
302 |
} |
void refresh_search (GtkWidget *Widget, gchar *Data) |
303 |
CurrentPage = gtk_notebook_get_current_page (GTK_NOTEBOOK(MainNotebook)); |
{ |
304 |
if (!strcmp (SearchPrefs -> FileName, FPROPS(CurrentPage, Name))) |
} |
305 |
{ |
|
306 |
gchar *string, *msg; |
/* expands a reg exp file pattern to a list of files */ |
307 |
gint Line, Begin, End, length; |
/* this returned list is an array of strings, with |pre| |
308 |
GtkTextIter start, end; |
NULL entries before the results, a bunch of results, |
309 |
GtkTextBuffer *EditorBuffer; |
and an ending NULL. */ |
310 |
|
gchar **get_files_for_search (const gchar *regexp, gint pre) |
311 |
gtk_label_get (GTK_LABEL(GTK_BIN(Widget) -> child), &string); |
{ |
312 |
sscanf (string, "%*d. Line %d (%d-%d)", &Line, &Begin, &End); |
gchar **answer; |
313 |
EditorBuffer = gtk_text_view_get_buffer(GTK_TEXT_VIEW( |
wordexp_t word; |
314 |
FPROPS(CurrentPage, Text))); |
|
315 |
length = gtk_text_buffer_get_char_count(EditorBuffer); |
START_FCN |
316 |
if (End <= length) |
|
317 |
{ |
/* note: I feel that this is the place to make sure |
318 |
gchar *selection; |
the user is not trying to screw us with funny |
319 |
|
syntax and reserved symbols. we should do some checking. */ |
320 |
gtk_text_buffer_get_iter_at_offset(EditorBuffer, &start, Begin); |
|
321 |
gtk_text_buffer_get_iter_at_offset(EditorBuffer, &end, End); |
word.we_offs = pre; |
322 |
gtk_text_buffer_move_mark_by_name(EditorBuffer, |
if (wordexp (regexp, &word, WRDE_DOOFFS)) |
323 |
"insert", &start); |
{ |
324 |
gtk_text_buffer_move_mark_by_name(EditorBuffer, |
gint i; |
325 |
"selection_bound", &end); |
|
326 |
selection = gtk_text_buffer_get_text(EditorBuffer, |
answer = g_malloc (sizeof (gchar *) * (pre + 1)); |
327 |
&start, &end, FALSE); |
|
328 |
if (SearchPrefs -> CaseSen) |
for (i = 0; i < pre; i++) |
|
{ |
|
|
if (strcmp (selection, SearchPrefs -> StringToSearch)) |
|
329 |
{ |
{ |
330 |
print_msg (_("You should refresh the search.")); |
answer[i] = NULL; |
|
return; |
|
331 |
} |
} |
332 |
} |
answer[i] = NULL; |
|
else |
|
|
if (strcasecmp (selection, SearchPrefs -> StringToSearch)) |
|
|
{ |
|
|
print_msg (_("You should refresh the search.")); |
|
|
return; |
|
|
} |
|
|
msg = g_strdup_printf (_("Line %d (%d-%d) selected..."), |
|
|
Line, Begin, End); |
|
|
show_on_screen (GTK_TEXT_VIEW (FPROPS(CurrentPage, Text)), start); |
|
|
|
|
|
print_msg (msg); |
|
|
g_free (msg); |
|
|
g_free (selection); |
|
333 |
} |
} |
334 |
else |
else |
335 |
print_msg |
{ |
336 |
(_("Apparently you deleted the part you try to reach now!")); |
gint i; |
337 |
/* g_free (string); |
|
338 |
... causes seg fault, I don't know why... */ |
// fill out our array |
339 |
} |
answer = g_malloc (sizeof (gchar *) * |
340 |
else |
(word.we_wordc + word.we_offs + 1)); |
341 |
print_msg (_("The current search didn't operate on this file...")); |
for (i = word.we_offs; i < word.we_offs + word.we_wordc; i++) |
342 |
(void)MyList; /* avoid the "unused parameter" warning */ |
{ |
343 |
|
answer[i] = g_strdup (word.we_wordv[i]); |
344 |
|
} |
345 |
|
answer[i] = NULL; |
346 |
|
} |
347 |
|
|
348 |
|
wordfree (&word); |
349 |
|
|
350 |
|
END_FCN |
351 |
|
return answer; |
352 |
} |
} |
353 |
|
|
354 |
|
// returns stdout |
355 |
|
gchar *run_program_with_args (const gchar *prog, gchar *const args[], const gchar *input) |
356 |
|
{ |
357 |
|
int in[2]; |
358 |
|
int out[2]; |
359 |
|
pid_t pid; |
360 |
|
gchar *result = NULL; |
361 |
|
|
362 |
|
START_FCN |
363 |
|
|
364 |
|
pipe (in); |
365 |
|
pipe (out); |
366 |
|
pid = fork (); |
367 |
|
|
368 |
|
if (pid == (pid_t) 0) |
369 |
|
{ |
370 |
|
/* this is the child process */ |
371 |
|
close (in[1]); |
372 |
|
close (out[0]); |
373 |
|
|
374 |
|
/* connect pipe to stdin and stdout */ |
375 |
|
dup2 (in[0], STDIN_FILENO); |
376 |
|
dup2 (out[1], STDOUT_FILENO); |
377 |
|
|
378 |
|
execvp (prog, args); |
379 |
|
exit (0); |
380 |
|
} |
381 |
|
else |
382 |
|
{ |
383 |
|
FILE *stream_out; |
384 |
|
gulong size; |
385 |
|
size_t read; |
386 |
|
|
387 |
|
/* this is the parent process */ |
388 |
|
close (in[0]); |
389 |
|
close (out[1]); |
390 |
|
|
391 |
|
if (input) |
392 |
|
{ |
393 |
|
FILE *stream_in; |
394 |
|
|
395 |
|
stream_in = fdopen (in[1], "w"); |
396 |
|
if (stream_in) |
397 |
|
{ |
398 |
|
fwrite (input, strlen (input), 1, stream_in); |
399 |
|
fflush (stream_in); |
400 |
|
fclose (stream_in); |
401 |
|
} |
402 |
|
} |
403 |
|
|
404 |
|
close (in[1]); |
405 |
|
|
406 |
|
stream_out = fdopen (out[0], "r"); |
407 |
|
|
408 |
|
size = 200; |
409 |
|
result = (gchar *) g_malloc (size); |
410 |
|
while ((read = fread (result + size - 200, 1, 200, stream_out)) >= 200) |
411 |
|
{ |
412 |
|
size += 200; |
413 |
|
result = (gchar *) g_realloc (result, size); |
414 |
|
} |
415 |
|
result[size - 200 + read] = '\0'; |
416 |
|
fflush (stream_out); |
417 |
|
|
418 |
|
close (out[0]); |
419 |
|
} |
420 |
|
|
421 |
|
END_FCN |
422 |
|
|
423 |
|
return result; |
424 |
|
} |
425 |
|
|
426 |
void search_window_not_visible (void) |
struct line_match *parse_grep_output_line (gchar *line) |
427 |
{ |
{ |
428 |
SearchIsVisible = FALSE; |
struct line_match *rv = (struct line_match *) g_malloc (sizeof (struct line_match)); |
429 |
|
gchar *colon; |
430 |
|
|
431 |
|
START_FCN |
432 |
|
|
433 |
|
colon = strchr (line, ':'); |
434 |
|
if (colon) |
435 |
|
{ |
436 |
|
colon[0] = '\0'; |
437 |
|
rv->line = atoi (line); |
438 |
|
colon[0] = ':'; |
439 |
|
colon++; |
440 |
|
rv->text = g_strdup (colon); |
441 |
|
} |
442 |
|
else |
443 |
|
{ |
444 |
|
rv->line = 0; |
445 |
|
rv->text = g_strdup (line); |
446 |
|
} |
447 |
|
|
448 |
|
END_FCN |
449 |
|
|
450 |
|
return rv; |
451 |
} |
} |
452 |
|
|
453 |
|
struct file_results parse_grep_output (gchar *output, GtkWidget *widget, const gchar *filename) |
454 |
|
{ |
455 |
|
struct file_results rv; |
456 |
|
gchar *next; |
457 |
|
|
458 |
|
START_FCN |
459 |
|
|
460 |
|
rv.buffer = widget; |
461 |
|
if (widget) |
462 |
|
g_signal_connect_swapped (G_OBJECT (widget), "destroy", |
463 |
|
G_CALLBACK (g_nullify_pointer), &rv.buffer); |
464 |
|
rv.path = g_strdup (filename); |
465 |
|
rv.results = g_ptr_array_new (); |
466 |
|
|
467 |
|
while ((next = strchr (output, '\n'))) |
468 |
|
{ |
469 |
|
next[0] = '\0'; |
470 |
|
g_ptr_array_add (rv.results, parse_grep_output_line (output)); |
471 |
|
next[0] = '\n'; |
472 |
|
output = next + 1; |
473 |
|
} |
474 |
|
|
475 |
|
if (rv.results->len == 0) |
476 |
|
{ |
477 |
|
g_ptr_array_free (rv.results, FALSE); |
478 |
|
rv.results = NULL; |
479 |
|
} |
480 |
|
|
481 |
|
END_FCN |
482 |
|
|
483 |
|
return rv; |
484 |
|
} |
485 |
|
|
486 |
/* Used to set up Search preferences */ |
struct file_results run_grep_on_file (gchar *pattern, gchar *filename, gint flags) |
487 |
|
{ |
488 |
|
gchar *args[5]; |
489 |
|
gint i = 0; |
490 |
|
gchar *answers; |
491 |
|
struct file_results rv; |
492 |
|
|
493 |
|
START_FCN |
494 |
|
|
495 |
|
args[i++] = "grep"; |
496 |
|
if (pattern) args[i++] = pattern; |
497 |
|
args[i++] = "-n"; |
498 |
|
args[i++] = filename; |
499 |
|
args[i++] = NULL; |
500 |
|
|
501 |
|
answers = run_program_with_args ("grep", args, NULL); |
502 |
|
|
503 |
|
rv = parse_grep_output (answers, NULL, filename); |
504 |
|
|
505 |
|
g_free (answers); |
506 |
|
|
507 |
|
END_FCN |
508 |
|
|
509 |
|
return rv; |
510 |
|
} |
511 |
|
|
512 |
void refresh_search (GtkWidget *Widget, gchar *Data) |
struct file_results run_grep_on_text (gchar *pattern, gint page, gint flags) |
513 |
{ |
{ |
514 |
if (!strcmp (Data, "cursor")) |
gchar *args[5]; |
515 |
SearchPrefs -> BeginCursorPos = TRUE; |
gint i = 0; |
516 |
else if (!strcmp (Data, "begin")) |
gchar *answers; |
517 |
SearchPrefs -> BeginCursorPos = FALSE; |
struct file_results rv; |
518 |
else if (!strcmp (Data, "case_sen")) |
gchar *text; |
519 |
{ |
|
520 |
if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON(Widget))) |
START_FCN |
521 |
SearchPrefs -> CaseSen = TRUE; |
|
522 |
else |
text = get_text (FPROPS (page, Buffer)); |
523 |
SearchPrefs -> CaseSen = FALSE; |
|
524 |
} |
args[i++] = "grep"; |
525 |
/* TODO: implement the regexp feature */ |
if (pattern) args[i++] = pattern; |
526 |
/* else if (!strcmp (Data, "reg_exp")) |
args[i++] = "-n"; |
527 |
{ |
args[i++] = "-"; |
528 |
if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON(Widget))) |
args[i++] = NULL; |
529 |
SearchPrefs -> RegExp = TRUE; |
|
530 |
else |
answers = run_program_with_args ("grep", args, text); |
531 |
SearchPrefs -> RegExp = FALSE; |
|
532 |
} */ |
rv = parse_grep_output (answers, FPROPS (page, Text), FPROPS (page, Name)); |
533 |
else if (!strcmp (Data, "search")) |
|
534 |
{ |
g_free (answers); |
535 |
gchar *msg; |
g_free (text); |
536 |
gint SearchBegin, i, CurrentPage; |
|
537 |
t_search_results *search_res; |
END_FCN |
538 |
GtkWidget *ListItem; |
|
539 |
|
return rv; |
540 |
if (!OpenedFilesCnt) |
} |
|
{ |
|
|
print_msg (_("Cannot refer to file: you closed all files!")); |
|
|
return; |
|
|
} |
|
|
SearchPrefs -> StringToSearch = gtk_entry_get_text |
|
|
(GTK_ENTRY(SearchEntry)); |
|
|
if (!strlen(SearchPrefs -> StringToSearch)) |
|
|
return; |
|
|
CurrentPage = gtk_notebook_get_current_page (GTK_NOTEBOOK(MainNotebook)); |
|
|
SearchPrefs -> FileName = g_strdup (FPROPS(CurrentPage, Name)); |
|
|
if (SearchPrefs -> BeginCursorPos) |
|
|
SearchBegin = get_position (FPROPS(CurrentPage, Buffer)); |
|
|
else |
|
|
SearchBegin = 0; |
|
|
gtk_list_clear_items (GTK_LIST(List), 0, -1); |
|
|
search_res = find (CurrentPage, |
|
|
SearchPrefs -> CaseSen, |
|
|
SearchPrefs -> RegExp, |
|
|
SearchBegin, |
|
|
SearchPrefs -> StringToSearch); |
|
|
for (i = 1; i <= search_res[0].Line; i++) |
|
|
{ |
|
|
gchar *str_temp; |
|
|
|
|
|
str_temp = g_strdup_printf (_("%d. Line %d (%d-%d)"), i, |
|
|
search_res[i].Line, |
|
|
search_res[i].Begin, |
|
|
search_res[i].End); |
|
|
ListItem = gtk_list_item_new_with_label (str_temp); |
|
|
gtk_container_add (GTK_CONTAINER(List), ListItem); |
|
|
g_free (str_temp); |
|
|
} |
|
|
gtk_list_select_item (GTK_LIST(List), 0); |
|
|
gtk_widget_show_all (List); |
|
|
gtk_entry_set_text (GTK_ENTRY(SearchEntry), |
|
|
SearchPrefs -> StringToSearch); |
|
|
if (search_res[0].Line == 0) |
|
|
msg = g_strdup_printf(_("String \"%s\" could not be found."), SearchPrefs -> StringToSearch); |
|
|
else |
|
|
{ |
|
|
gtk_window_set_focus(GTK_WINDOW(gtk_widget_get_toplevel(Widget)), |
|
|
GTK_WIDGET(GTK_LIST(List)->children->data)); |
|
|
if (search_res[0].Line == 1) |
|
|
msg = g_strdup_printf(_("Found one string (\"%s\")."), |
|
|
SearchPrefs -> StringToSearch); |
|
|
else |
|
|
msg = g_strdup_printf (_("Found %d strings (\"%s\")."), |
|
|
search_res[0].Line, |
|
|
SearchPrefs -> StringToSearch); |
|
|
} |
|
|
print_msg (msg); |
|
|
g_free (msg); |
|
|
g_free (search_res); |
|
|
} |
|
|
else if (!strcmp (Data, "rep_all")) |
|
|
{ |
|
|
if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON(Widget))) |
|
|
{ |
|
|
SearchPrefs -> RepAll = TRUE; |
|
|
} |
|
|
else |
|
|
{ |
|
|
SearchPrefs -> RepAll = FALSE; |
|
|
} |
|
|
} |
|
|
else if (!strcmp (Data, "rep_all_buffers")) |
|
|
{ |
|
|
if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON(Widget))) |
|
|
{ |
|
|
SearchPrefs -> RepAll = TRUE; |
|
|
} |
|
|
else |
|
|
{ |
|
|
SearchPrefs -> RepAll = FALSE; |
|
|
} |
|
|
} |
|
|
else if (!strcmp (Data, "replace")) |
|
|
{ |
|
|
const gchar *ReplaceString; |
|
|
gint SearchBegin, CurrentPage; |
|
541 |
|
|
542 |
if (!OpenedFilesCnt) |
void search_callback (GtkDialog *dialog, gint response, gpointer data) |
543 |
{ |
{ |
544 |
print_msg(_("Cannot refer to file: you closed all files!")); |
START_FCN |
545 |
return; |
|
546 |
} |
if (response == GTK_RESPONSE_ACCEPT) |
547 |
SearchPrefs -> StringToSearch = gtk_entry_get_text |
{ |
548 |
(GTK_ENTRY(SearchEntry)); |
GtkWidget *widget; |
549 |
if (!strlen(SearchPrefs -> StringToSearch)) |
gint where; |
550 |
return; |
gint page; |
551 |
ReplaceString = gtk_entry_get_text (GTK_ENTRY(ReplaceEntry)); |
gchar *pattern = NULL; |
552 |
CurrentPage = gtk_notebook_get_current_page (GTK_NOTEBOOK(MainNotebook)); |
gchar *files = NULL; |
553 |
if (SearchPrefs -> BeginCursorPos) |
gchar **expanded_files; |
554 |
{ |
gint i; |
555 |
GtkTextBuffer *EditorBuffer; |
struct file_results output; |
556 |
GtkTextIter current; |
GArray *array = g_array_new (FALSE, FALSE, sizeof (struct file_results)); |
557 |
|
|
558 |
EditorBuffer = gtk_text_view_get_buffer( |
widget = g_object_get_data (G_OBJECT (dialog), "text"); |
559 |
GTK_TEXT_VIEW(FPROPS(CurrentPage, Text))); |
|
560 |
gtk_text_buffer_get_iter_at_mark (EditorBuffer, ¤t, |
pattern = g_strdup (gtk_entry_get_text (GTK_ENTRY (widget))); |
561 |
gtk_text_buffer_get_insert (EditorBuffer)); |
|
562 |
SearchBegin = gtk_text_iter_get_offset(¤t); |
where = 0; |
563 |
} |
if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON ( |
564 |
else |
g_object_get_data (G_OBJECT (dialog), "where_current")))) |
565 |
SearchBegin = 0; |
{ |
566 |
if (SearchPrefs -> RepAllBuffers) |
where = 0; |
567 |
{ |
} |
568 |
gchar *msg; |
else if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON ( |
569 |
gint i; |
g_object_get_data (G_OBJECT (dialog), "where_all")))) |
|
gint rep_nb = 0; |
|
|
for (i = 0; i < OpenedFilesCnt; i++) |
|
|
{ |
|
|
rep_nb += replace_all (i, |
|
|
SearchPrefs -> CaseSen, |
|
|
SearchPrefs -> RegExp, |
|
|
(i == CurrentPage) ? SearchBegin : 0, |
|
|
SearchPrefs -> StringToSearch, |
|
|
ReplaceString); |
|
|
} |
|
|
if (rep_nb == 0) |
|
|
msg = g_strdup_printf |
|
|
("The string \"%s\" hasn't been found...", |
|
|
SearchPrefs -> StringToSearch); |
|
|
else if (rep_nb == 1) |
|
|
msg = g_strdup_printf |
|
|
("The string \"%s\" has been replaced by \"%s\"...", |
|
|
SearchPrefs -> StringToSearch, ReplaceString); |
|
|
else |
|
|
msg = g_strdup_printf |
|
|
("%d \"%s\" strings have been replaced by \"%s\"...", |
|
|
rep_nb, SearchPrefs -> StringToSearch, ReplaceString); |
|
|
print_msg (msg); |
|
|
g_free (msg); |
|
|
} |
|
|
else if (SearchPrefs -> RepAll) |
|
|
{ |
|
|
gchar *msg; |
|
|
gint rep_nb; |
|
|
|
|
|
rep_nb = replace_all (CurrentPage, |
|
|
SearchPrefs -> CaseSen, |
|
|
SearchPrefs -> RegExp, |
|
|
SearchBegin, |
|
|
SearchPrefs -> StringToSearch, |
|
|
ReplaceString); |
|
|
if (rep_nb == 0) |
|
|
msg = g_strdup_printf |
|
|
("The string \"%s\" hasn't been found...", |
|
|
SearchPrefs -> StringToSearch); |
|
|
else if (rep_nb == 1) |
|
|
msg = g_strdup_printf |
|
|
("The string \"%s\" has been replaced by \"%s\"...", |
|
|
SearchPrefs -> StringToSearch, ReplaceString); |
|
|
else |
|
|
msg = g_strdup_printf |
|
|
("%d \"%s\" strings have been replaced by \"%s\"...", |
|
|
rep_nb, SearchPrefs -> StringToSearch, ReplaceString); |
|
|
print_msg (msg); |
|
|
g_free (msg); |
|
|
} |
|
|
else |
|
|
{ |
|
|
t_search_results *search_res; |
|
|
|
|
|
search_res = find (CurrentPage, |
|
|
SearchPrefs -> CaseSen, |
|
|
SearchPrefs -> RegExp, |
|
|
SearchBegin, |
|
|
SearchPrefs -> StringToSearch); |
|
|
if (search_res[0].Line) |
|
|
{ |
|
|
GtkTextBuffer *EditorBuffer; |
|
|
GtkTextIter start, end; |
|
|
gchar *buffer; |
|
|
|
|
|
EditorBuffer = gtk_text_view_get_buffer( |
|
|
GTK_TEXT_VIEW(FPROPS(CurrentPage, Text))); |
|
|
buffer = get_selection (EditorBuffer); |
|
|
if (!g_ascii_strcasecmp (buffer, SearchPrefs -> StringToSearch)) |
|
570 |
{ |
{ |
571 |
replace_selection(FPROPS(CurrentPage, Buffer), ReplaceString); |
where = 1; |
572 |
print_msg ("Selection replaced..."); |
} |
573 |
} |
else if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON ( |
574 |
else |
g_object_get_data (G_OBJECT (dialog), "where_files")))) |
575 |
{ |
{ |
576 |
gtk_text_buffer_get_iter_at_offset(EditorBuffer, |
where = 2; |
|
&start, search_res[1].Begin); |
|
|
gtk_text_buffer_get_iter_at_offset(EditorBuffer, |
|
|
&end, search_res[1].End); |
|
|
gtk_text_buffer_move_mark_by_name(EditorBuffer, |
|
|
"insert", &start); |
|
|
gtk_text_buffer_move_mark_by_name(EditorBuffer, |
|
|
"selection_bound", &end); |
|
577 |
} |
} |
578 |
g_free (buffer); |
|
579 |
} |
switch (where) |
580 |
else |
{ |
581 |
{ |
case 0: |
582 |
if (BEEP) gdk_beep (); |
page = gtk_notebook_get_current_page (GTK_NOTEBOOK (MainNotebook)); |
583 |
print_msg ("End of Search..."); |
|
584 |
} |
output = run_grep_on_text (pattern, page, 0); |
585 |
g_free (search_res); |
if (output.results) |
586 |
} |
g_array_append_val (array, output); |
587 |
gtk_entry_set_text (GTK_ENTRY(SearchEntry), |
|
588 |
SearchPrefs -> StringToSearch); |
break; |
589 |
gtk_entry_set_text (GTK_ENTRY(ReplaceEntry), ReplaceString); |
case 1: |
590 |
} |
for (i = 0; i < OpenedFilesCnt; i++) |
591 |
|
{ |
592 |
|
output = run_grep_on_text (pattern, i, 0); |
593 |
|
if (output.results) |
594 |
|
g_array_append_val (array, output); |
595 |
|
} |
596 |
|
|
597 |
|
break; |
598 |
|
case 2: |
599 |
|
widget = g_object_get_data (G_OBJECT (dialog), "files"); |
600 |
|
files = g_strdup (gtk_entry_get_text (GTK_ENTRY (widget))); |
601 |
|
expanded_files = get_files_for_search (files, 0); |
602 |
|
|
603 |
|
for (i = 0; expanded_files[i]; i++) |
604 |
|
{ |
605 |
|
output = run_grep_on_file (pattern, expanded_files[i], 0); |
606 |
|
if (output.results) |
607 |
|
g_array_append_val (array, output); |
608 |
|
} |
609 |
|
|
610 |
|
g_strfreev (expanded_files); |
611 |
|
g_free (files); |
612 |
|
break; |
613 |
|
} |
614 |
|
|
615 |
|
display_search_results (array); |
616 |
|
|
617 |
|
for (i = 0; i < array->len; i++) |
618 |
|
{ |
619 |
|
g_free (g_array_index (array, struct file_results, i).path); |
620 |
|
g_ptr_array_free (g_array_index (array, struct file_results, i).results, TRUE); |
621 |
|
} |
622 |
|
|
623 |
|
g_array_free (array, FALSE); |
624 |
|
} |
625 |
|
|
626 |
|
gtk_widget_destroy (GTK_WIDGET (dialog)); |
627 |
|
|
628 |
|
END_FCN |
629 |
} |
} |
630 |
|
|
|
|
|
631 |
/* Display a Search Dialog window */ |
/* Display a Search Dialog window */ |
632 |
|
|
633 |
void search (gboolean Replace) |
void search (void) |
634 |
{ |
{ |
635 |
GtkWidget *SearchWindow; |
static GtkWidget *SearchWindow = NULL; |
636 |
GtkWidget *VBox1, *VBox2; |
GtkWidget *main_vbox, *vbox, *hbox; |
637 |
GtkWidget *Frame; |
GtkWidget *widget, *radio1; |
638 |
GtkWidget *ScrolledWindow; |
|
639 |
GtkWidget *Button; |
if (SearchWindow) |
640 |
GSList *Group; |
{ |
641 |
gboolean homogenous = FALSE; |
gtk_window_present (GTK_WINDOW (SearchWindow)); |
642 |
|
return; |
643 |
if (SearchIsVisible) return; |
} |
644 |
SearchPrefs = g_malloc (sizeof(t_search_prefs)); |
|
645 |
SearchPrefs -> BeginCursorPos = TRUE; |
SearchWindow = gtk_dialog_new_with_buttons ( |
646 |
SearchPrefs -> CaseSen = FALSE; |
"Search", |
647 |
SearchPrefs -> RegExp = FALSE; |
GTK_WINDOW (MainWindow), |
648 |
SearchWindow = gtk_dialog_new (); |
GTK_DIALOG_DESTROY_WITH_PARENT | GTK_DIALOG_NO_SEPARATOR, |
649 |
gtk_window_set_policy (GTK_WINDOW(SearchWindow), FALSE, FALSE, FALSE); |
GTK_STOCK_CANCEL, GTK_RESPONSE_REJECT, |
650 |
g_signal_connect (G_OBJECT(SearchWindow), "delete_event", |
GTK_STOCK_FIND, GTK_RESPONSE_ACCEPT, |
651 |
(GtkSignalFunc) search_window_not_visible, NULL); |
NULL); |
652 |
g_signal_connect_swapped (G_OBJECT(SearchWindow), "delete_event", |
gtk_widget_realize (SearchWindow); |
653 |
|
gtk_window_set_resizable (GTK_WINDOW (SearchWindow), FALSE); |
654 |
|
gdk_window_set_functions (SearchWindow->window, GDK_FUNC_MOVE | GDK_FUNC_MINIMIZE); |
655 |
|
g_signal_connect_swapped (G_OBJECT(SearchWindow), "delete-event", |
656 |
(GtkSignalFunc) gtk_widget_destroy, |
(GtkSignalFunc) gtk_widget_destroy, |
657 |
G_OBJECT(SearchWindow)); |
G_OBJECT(SearchWindow)); |
|
g_signal_connect (G_OBJECT(SearchWindow), "destroy", |
|
|
(GtkSignalFunc) search_window_not_visible, NULL); |
|
658 |
g_signal_connect_swapped (G_OBJECT (SearchWindow), "destroy", |
g_signal_connect_swapped (G_OBJECT (SearchWindow), "destroy", |
659 |
(GtkSignalFunc) gtk_widget_destroy, |
G_CALLBACK (g_nullify_pointer), |
660 |
G_OBJECT(SearchWindow)); |
&SearchWindow); |
661 |
if (Replace) |
|
662 |
{ |
main_vbox = gtk_vbox_new (FALSE, 12); |
663 |
gtk_window_set_title (GTK_WINDOW(SearchWindow), |
gtk_box_set_spacing (GTK_BOX (GTK_DIALOG (SearchWindow)->vbox), 12); |
664 |
"Search and Replace Text"); |
gtk_container_set_border_width (GTK_CONTAINER (main_vbox), 6); |
665 |
SearchPrefs -> RepAll = FALSE; |
gtk_container_set_border_width (GTK_CONTAINER (SearchWindow), 6); |
666 |
} |
gtk_container_add (GTK_CONTAINER (GTK_DIALOG (SearchWindow)->vbox), main_vbox); |
667 |
else |
|
668 |
{ |
gtk_dialog_set_default_response (GTK_DIALOG (SearchWindow), GTK_RESPONSE_ACCEPT); |
669 |
gtk_window_set_title (GTK_WINDOW(SearchWindow), "Search Text"); |
|
670 |
homogenous = TRUE; |
g_signal_connect (G_OBJECT (SearchWindow), "response", G_CALLBACK (search_callback), NULL); |
671 |
} |
|
672 |
VBox1 = gtk_vbox_new (homogenous, 5); |
hbox = gtk_hbox_new (FALSE, 12); |
673 |
gtk_container_set_border_width (GTK_CONTAINER(VBox1), 10); |
gtk_container_add (GTK_CONTAINER (main_vbox), hbox); |
674 |
gtk_box_pack_start (GTK_BOX(GTK_DIALOG(SearchWindow) -> vbox), |
|
675 |
VBox1, FALSE, FALSE, 0); |
widget = gtk_label_new_with_mnemonic ("_Search for:"); |
676 |
Frame = gtk_frame_new ("Search"); |
gtk_container_add (GTK_CONTAINER (hbox), widget); |
677 |
gtk_box_pack_start (GTK_BOX(VBox1), Frame, TRUE, TRUE, 0); |
|
678 |
VBox2 = gtk_vbox_new (FALSE, 5); |
widget = gtk_entry_new (); |
679 |
gtk_container_set_border_width (GTK_CONTAINER(VBox2), 5); |
gtk_container_add (GTK_CONTAINER (hbox), widget); |
680 |
gtk_container_add (GTK_CONTAINER(Frame), VBox2); |
g_object_set_data (G_OBJECT (SearchWindow), "text", widget); |
681 |
SearchEntry = gtk_entry_new (); |
|
682 |
gtk_entry_set_activates_default (GTK_ENTRY(SearchEntry), TRUE); |
vbox = gtk_vbox_new (FALSE, 6); |
683 |
gtk_box_pack_start (GTK_BOX(VBox2), SearchEntry, FALSE, FALSE, 0); |
gtk_box_pack_start (GTK_BOX (main_vbox), vbox, FALSE, FALSE, 0); |
684 |
Button = gtk_radio_button_new_with_mnemonic (NULL, "Start at cursor _position"); |
|
685 |
gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON(Button), TRUE); |
radio1 = gtk_radio_button_new_with_mnemonic (NULL, "Search in current _buffer"); |
686 |
g_signal_connect (G_OBJECT(Button), "toggled", |
gtk_container_add (GTK_CONTAINER (vbox), radio1); |
687 |
(GtkSignalFunc)refresh_search, "cursor"); |
g_object_set_data (G_OBJECT (SearchWindow), "where_current", radio1); |
688 |
gtk_box_pack_start (GTK_BOX(VBox2), Button, FALSE, FALSE, 0); |
|
689 |
Group = gtk_radio_button_group (GTK_RADIO_BUTTON(Button)); |
widget = gtk_radio_button_new_with_mnemonic_from_widget ( |
690 |
Button = gtk_radio_button_new_with_mnemonic |
GTK_RADIO_BUTTON (radio1), |
691 |
(Group, "Start at _beginning of the document"); |
"Search in _all open buffers"); |
692 |
g_signal_connect (G_OBJECT(Button), "toggled", |
gtk_container_add (GTK_CONTAINER (vbox), widget); |
693 |
(GtkSignalFunc)refresh_search, "begin"); |
g_object_set_data (G_OBJECT (SearchWindow), "where_all", widget); |
694 |
gtk_box_pack_start (GTK_BOX(VBox2), Button, FALSE, FALSE, 0); |
|
695 |
Button = gtk_check_button_new_with_mnemonic ("Case _sensitive"); |
hbox = gtk_hbox_new (FALSE, 12); |
696 |
g_signal_connect (G_OBJECT(Button), "toggled", |
gtk_container_add (GTK_CONTAINER (vbox), hbox); |
697 |
(GtkSignalFunc)refresh_search, "case_sen"); |
|
698 |
gtk_box_pack_start (GTK_BOX(VBox2), Button, FALSE, FALSE, 0); |
widget = gtk_radio_button_new_with_mnemonic_from_widget ( |
699 |
|
GTK_RADIO_BUTTON (radio1), |
700 |
/* TODO: implement the regexp feature */ |
"Search in these _files: "); |
701 |
/* Button = gtk_check_button_new_with_label ("Regular expression search"); |
gtk_container_add (GTK_CONTAINER (hbox), widget); |
702 |
g_signal_connect (G_OBJECT(Button), "toggled", |
g_object_set_data (G_OBJECT (SearchWindow), "where_files", widget); |
703 |
(GtkSignalFunc)refresh_search, "reg_exp"); |
|
704 |
gtk_box_pack_start (GTK_BOX(VBox2), Button, FALSE, FALSE, 0); */ |
widget = gtk_entry_new (); |
705 |
|
gtk_container_add (GTK_CONTAINER (hbox), widget); |
706 |
Button = gtk_button_new_from_stock (GTK_STOCK_CANCEL); |
g_object_set_data (G_OBJECT (SearchWindow), "files", widget); |
707 |
g_signal_connect (G_OBJECT(Button), "clicked", |
|
708 |
(GtkSignalFunc) search_window_not_visible, NULL); |
widget = gtk_check_button_new_with_mnemonic ("Match c_ase"); |
709 |
g_signal_connect_swapped (G_OBJECT(Button), "clicked", |
gtk_box_pack_start (GTK_BOX (main_vbox), widget, FALSE, FALSE, 0); |
710 |
(GtkSignalFunc) gtk_widget_destroy, |
g_object_set_data (G_OBJECT (SearchWindow), "case", widget); |
711 |
G_OBJECT(SearchWindow)); |
|
712 |
GTK_WIDGET_SET_FLAGS (Button, GTK_CAN_DEFAULT); |
widget = gtk_check_button_new_with_mnemonic ("Match whole wor_d only"); |
713 |
gtk_box_pack_start (GTK_BOX(GTK_DIALOG(SearchWindow) -> action_area), |
gtk_box_pack_start (GTK_BOX (main_vbox), widget, FALSE, FALSE, 0); |
714 |
Button, TRUE, TRUE, 0); |
g_object_set_data (G_OBJECT (SearchWindow), "word", widget); |
715 |
|
|
716 |
if (Replace) |
widget = gtk_check_button_new_with_mnemonic ("_Wrap around"); |
717 |
{ |
gtk_box_pack_start (GTK_BOX (main_vbox), widget, FALSE, FALSE, 0); |
718 |
Frame = gtk_frame_new ("Replace"); |
g_object_set_data (G_OBJECT (SearchWindow), "wrap", widget); |
719 |
gtk_box_pack_start (GTK_BOX(VBox1), Frame, TRUE, TRUE, 0); |
|
720 |
VBox2 = gtk_vbox_new (FALSE, 5); |
widget = gtk_check_button_new_with_mnemonic ("Text is a _regular expression"); |
721 |
gtk_container_set_border_width (GTK_CONTAINER(VBox2), 5); |
gtk_box_pack_start (GTK_BOX (main_vbox), widget, FALSE, FALSE, 0); |
722 |
gtk_container_add (GTK_CONTAINER(Frame), VBox2); |
g_object_set_data (G_OBJECT (SearchWindow), "regexp", widget); |
723 |
ReplaceEntry = gtk_entry_new (); |
|
724 |
gtk_entry_set_activates_default (GTK_ENTRY(ReplaceEntry), TRUE); |
widget = gtk_check_button_new_with_mnemonic ("Search s_ubdirectories"); |
725 |
gtk_box_pack_start (GTK_BOX(VBox2), ReplaceEntry, FALSE, FALSE, 0); |
gtk_box_pack_start (GTK_BOX (main_vbox), widget, FALSE, FALSE, 0); |
726 |
Button = gtk_check_button_new_with_mnemonic ("Replace _all"); |
g_object_set_data (G_OBJECT (SearchWindow), "subdirs", widget); |
727 |
g_signal_connect (G_OBJECT(Button), "toggled", |
|
|
(GtkSignalFunc)refresh_search, "rep_all"); |
|
|
gtk_box_pack_start (GTK_BOX(VBox2), Button, FALSE, FALSE, 0); |
|
|
Button = gtk_check_button_new_with_mnemonic ("Replace all in _every buffer"); |
|
|
gtk_signal_connect (GTK_OBJECT(Button), "toggled", |
|
|
(GtkSignalFunc)refresh_search, "rep_all_buffers"); |
|
|
gtk_box_pack_start (GTK_BOX(VBox2), Button, FALSE, FALSE, 0); |
|
|
Button = gtk_button_new_from_stock (GTK_STOCK_FIND_AND_REPLACE); |
|
|
// gtk_button_set_label (GTK_BUTTON (Button), "Replace"); |
|
|
g_signal_connect (G_OBJECT(Button), "clicked", |
|
|
(GtkSignalFunc)refresh_search, "replace"); |
|
|
print_msg ("Display Search and Replace window..."); |
|
|
} |
|
|
else |
|
|
{ |
|
|
Frame = gtk_frame_new ("Results"); |
|
|
gtk_box_pack_start (GTK_BOX(VBox1), Frame, TRUE, TRUE, 0); |
|
|
VBox2 = gtk_vbox_new (FALSE, 5); |
|
|
gtk_container_set_border_width (GTK_CONTAINER(VBox2), 5); |
|
|
gtk_container_add (GTK_CONTAINER(Frame), VBox2); |
|
|
ScrolledWindow = gtk_scrolled_window_new (NULL, NULL); |
|
|
gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW(ScrolledWindow), |
|
|
GTK_POLICY_AUTOMATIC, |
|
|
GTK_POLICY_AUTOMATIC); |
|
|
gtk_box_pack_start (GTK_BOX(VBox2), ScrolledWindow, TRUE, TRUE, 0); |
|
|
List = gtk_list_new (); |
|
|
gtk_list_set_selection_mode (GTK_LIST(List), GTK_SELECTION_BROWSE); |
|
|
g_signal_connect (G_OBJECT(List), "select_child", |
|
|
(GtkSignalFunc)goto_search, NULL); |
|
|
gtk_scrolled_window_add_with_viewport |
|
|
(GTK_SCROLLED_WINDOW(ScrolledWindow), List); |
|
|
gtk_container_set_focus_vadjustment |
|
|
(GTK_CONTAINER (List), |
|
|
gtk_scrolled_window_get_vadjustment |
|
|
(GTK_SCROLLED_WINDOW (ScrolledWindow))); |
|
|
gtk_container_set_focus_hadjustment |
|
|
(GTK_CONTAINER (List), |
|
|
gtk_scrolled_window_get_hadjustment |
|
|
(GTK_SCROLLED_WINDOW (ScrolledWindow))); |
|
|
Button = gtk_button_new_from_stock (GTK_STOCK_FIND); |
|
|
g_signal_connect (G_OBJECT(Button), "clicked", |
|
|
(GtkSignalFunc)refresh_search, "search"); |
|
|
print_msg ("Display Search window..."); |
|
|
} |
|
|
GTK_WIDGET_SET_FLAGS (Button, GTK_CAN_DEFAULT); |
|
|
gtk_box_pack_start (GTK_BOX(GTK_DIALOG(SearchWindow) -> action_area), |
|
|
Button, TRUE, TRUE, 0); |
|
|
gtk_widget_grab_default (Button); |
|
728 |
gtk_widget_show_all (SearchWindow); |
gtk_widget_show_all (SearchWindow); |
|
SearchIsVisible = TRUE; |
|
729 |
} |
} |
730 |
|
|
731 |
void show_on_screen (GtkTextView *Text, GtkTextIter start) |
void show_on_screen (GtkTextView *Text, GtkTextIter start) |