2 Search & replace engine of MCEditor.
4 Copyright (C) 2021-2024
5 Free Software Foundation, Inc.
8 Andrew Borodin <aborodin@vmail.ru>, 2021-2022
10 This file is part of the Midnight Commander.
12 The Midnight Commander is free software: you can redistribute it
13 and/or modify it under the terms of the GNU General Public License as
14 published by the Free Software Foundation, either version 3 of the License,
15 or (at your option) any later version.
17 The Midnight Commander is distributed in the hope that it will be useful,
18 but WITHOUT ANY WARRANTY; without even the implied warranty of
19 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 GNU General Public License for more details.
22 You should have received a copy of the GNU General Public License
23 along with this program. If not, see <http://www.gnu.org/licenses/>.
30 #include "lib/global.h"
31 #include "lib/search.h"
32 #include "lib/mcconfig.h" /* mc_config_history_get_recent_item() */
34 #include "lib/charsets.h" /* cp_source */
37 #include "lib/widget.h"
38 #include "lib/skin.h" /* BOOK_MARK_FOUND_COLOR */
40 #include "src/history.h" /* MC_HISTORY_SHARED_SEARCH */
41 #include "src/setup.h" /* verbose */
43 #include "edit-impl.h"
44 #include "editwidget.h"
46 #include "editsearch.h"
48 /*** global variables ****************************************************************************/
50 edit_search_options_t edit_search_options
= {
51 .type
= MC_SEARCH_T_NORMAL
,
54 .only_in_selection
= FALSE
,
56 .all_codepages
= FALSE
59 /*** file scope macro definitions ****************************************************************/
61 #define B_REPLACE_ALL (B_USER+1)
62 #define B_REPLACE_ONE (B_USER+2)
63 #define B_SKIP_REPLACE (B_USER+3)
65 /*** file scope type declarations ****************************************************************/
67 /*** forward declarations (file scope functions) *************************************************/
69 /*** file scope variables ************************************************************************/
71 /* --------------------------------------------------------------------------------------------- */
72 /*** file scope functions ************************************************************************/
73 /* --------------------------------------------------------------------------------------------- */
76 edit_dialog_search_show (WEdit
* edit
)
79 size_t num_of_types
= 0;
80 gchar
**list_of_types
;
83 list_of_types
= mc_search_get_types_strings_array (&num_of_types
);
86 quick_widget_t quick_widgets
[] = {
88 QUICK_LABELED_INPUT (N_("Enter search string:"), input_label_above
, INPUT_LAST_TEXT
,
89 MC_HISTORY_SHARED_SEARCH
, &search_text
, NULL
, FALSE
, FALSE
,
91 QUICK_SEPARATOR (TRUE
),
93 QUICK_RADIO (num_of_types
, (const char **) list_of_types
,
94 (int *) &edit_search_options
.type
, NULL
),
96 QUICK_CHECKBOX (N_("Cas&e sensitive"), &edit_search_options
.case_sens
, NULL
),
97 QUICK_CHECKBOX (N_("&Backwards"), &edit_search_options
.backwards
, NULL
),
98 QUICK_CHECKBOX (N_("In se&lection"), &edit_search_options
.only_in_selection
, NULL
),
99 QUICK_CHECKBOX (N_("&Whole words"), &edit_search_options
.whole_words
, NULL
),
101 QUICK_CHECKBOX (N_("&All charsets"), &edit_search_options
.all_codepages
, NULL
),
104 QUICK_START_BUTTONS (TRUE
, TRUE
),
105 QUICK_BUTTON (N_("&OK"), B_ENTER
, NULL
, NULL
),
106 QUICK_BUTTON (N_("&Find all"), B_USER
, NULL
, NULL
),
107 QUICK_BUTTON (N_("&Cancel"), B_CANCEL
, NULL
, NULL
),
112 WRect r
= { -1, -1, 0, 58 };
114 quick_dialog_t qdlg
= {
115 r
, N_("Search"), "[Input Line Keys]",
116 quick_widgets
, NULL
, NULL
119 dialog_result
= quick_dialog (&qdlg
);
122 g_strfreev (list_of_types
);
124 if (dialog_result
== B_CANCEL
|| search_text
[0] == '\0')
126 g_free (search_text
);
130 if (dialog_result
== B_USER
)
131 search_create_bookmark
= TRUE
;
137 tmp
= str_convert_to_input (search_text
);
138 g_free (search_text
);
140 search_text
= g_string_free (tmp
, FALSE
);
142 search_text
= g_strdup ("");
146 edit_search_deinit (edit
);
147 edit
->last_search_string
= search_text
;
149 return edit_search_init (edit
, edit
->last_search_string
);
152 /* --------------------------------------------------------------------------------------------- */
155 edit_dialog_replace_show (WEdit
* edit
, const char *search_default
, const char *replace_default
,
156 /*@out@ */ char **search_text
, /*@out@ */ char **replace_text
)
158 size_t num_of_types
= 0;
159 gchar
**list_of_types
;
161 if ((search_default
== NULL
) || (*search_default
== '\0'))
162 search_default
= INPUT_LAST_TEXT
;
164 list_of_types
= mc_search_get_types_strings_array (&num_of_types
);
167 quick_widget_t quick_widgets
[] = {
169 QUICK_LABELED_INPUT (N_("Enter search string:"), input_label_above
, search_default
,
170 MC_HISTORY_SHARED_SEARCH
, search_text
, NULL
, FALSE
, FALSE
,
171 INPUT_COMPLETE_NONE
),
172 QUICK_LABELED_INPUT (N_("Enter replacement string:"), input_label_above
, replace_default
,
173 "replace", replace_text
, NULL
, FALSE
, FALSE
, INPUT_COMPLETE_NONE
),
174 QUICK_SEPARATOR (TRUE
),
176 QUICK_RADIO (num_of_types
, (const char **) list_of_types
,
177 (int *) &edit_search_options
.type
, NULL
),
179 QUICK_CHECKBOX (N_("Cas&e sensitive"), &edit_search_options
.case_sens
, NULL
),
180 QUICK_CHECKBOX (N_("&Backwards"), &edit_search_options
.backwards
, NULL
),
181 QUICK_CHECKBOX (N_("In se&lection"), &edit_search_options
.only_in_selection
, NULL
),
182 QUICK_CHECKBOX (N_("&Whole words"), &edit_search_options
.whole_words
, NULL
),
184 QUICK_CHECKBOX (N_("&All charsets"), &edit_search_options
.all_codepages
, NULL
),
187 QUICK_BUTTONS_OK_CANCEL
,
192 WRect r
= { -1, -1, 0, 58 };
194 quick_dialog_t qdlg
= {
195 r
, N_("Replace"), "[Input Line Keys]",
196 quick_widgets
, NULL
, NULL
199 if (quick_dialog (&qdlg
) != B_CANCEL
)
200 edit
->replace_mode
= 0;
203 *replace_text
= NULL
;
208 g_strfreev (list_of_types
);
211 /* --------------------------------------------------------------------------------------------- */
214 edit_dialog_replace_prompt_show (WEdit
* edit
, char *from_text
, char *to_text
, int xpos
, int ypos
)
216 Widget
*w
= WIDGET (edit
);
222 char tmp
[BUF_MEDIUM
];
223 char *repl_from
, *repl_to
;
227 xpos
= w
->rect
.x
+ edit_options
.line_state_width
+ 1;
229 ypos
= w
->rect
.y
+ w
->rect
.lines
/ 2;
230 /* Sometimes menu can hide replaced text. I don't like it */
231 if ((edit
->curs_row
>= ypos
- 1) && (edit
->curs_row
<= ypos
+ dlg_height
- 1))
234 dlg_width
= WIDGET (w
->owner
)->rect
.cols
- xpos
- 1;
236 g_snprintf (tmp
, sizeof (tmp
), "\"%s\"", from_text
);
237 repl_from
= g_strdup (str_trunc (tmp
, dlg_width
- 7));
239 g_snprintf (tmp
, sizeof (tmp
), "\"%s\"", to_text
);
240 repl_to
= g_strdup (str_trunc (tmp
, dlg_width
- 7));
243 quick_widget_t quick_widgets
[] = {
245 QUICK_LABEL (repl_from
, NULL
),
246 QUICK_LABEL (N_("Replace with:"), NULL
),
247 QUICK_LABEL (repl_to
, NULL
),
248 QUICK_START_BUTTONS (TRUE
, TRUE
),
249 QUICK_BUTTON (N_("&Replace"), B_ENTER
, NULL
, NULL
),
250 QUICK_BUTTON (N_("A&ll"), B_REPLACE_ALL
, NULL
, NULL
),
251 QUICK_BUTTON (N_("&Skip"), B_SKIP_REPLACE
, NULL
, NULL
),
252 QUICK_BUTTON (N_("&Cancel"), B_CANCEL
, NULL
, NULL
),
257 WRect r
= { ypos
, xpos
, 0, -1 };
259 quick_dialog_t qdlg
= {
260 r
, N_("Confirm replace"), NULL
,
261 quick_widgets
, NULL
, NULL
264 retval
= quick_dialog (&qdlg
);
273 /* --------------------------------------------------------------------------------------------- */
276 * Get EOL symbol for searching.
278 * @param edit editor object
283 edit_search_get_current_end_line_char (const WEdit
* edit
)
294 /* --------------------------------------------------------------------------------------------- */
296 * Checking if search condition have BOL(^) or EOL ($) regexp special characters.
298 * @param search search object
299 * @return result of checks.
302 static edit_search_line_t
303 edit_get_search_line_type (const mc_search_t
* search
)
305 edit_search_line_t search_line_type
= 0;
307 if (search
->search_type
== MC_SEARCH_T_REGEX
)
309 if (search
->original
.str
->str
[0] == '^')
310 search_line_type
|= AT_START_LINE
;
312 if (search
->original
.str
->str
[search
->original
.str
->len
- 1] == '$')
313 search_line_type
|= AT_END_LINE
;
316 return search_line_type
;
319 /* --------------------------------------------------------------------------------------------- */
321 * Calculating the start position of next line.
323 * @param buf editor buffer object
324 * @param current_pos current position
325 * @param max_pos max position
326 * @param end_string_symbol end of line symbol
327 * @return start position of next line
331 edit_calculate_start_of_next_line (const edit_buffer_t
* buf
, off_t current_pos
, off_t max_pos
,
332 char end_string_symbol
)
336 for (i
= current_pos
; i
< max_pos
; i
++)
339 if (edit_buffer_get_byte (buf
, i
) == end_string_symbol
)
346 /* --------------------------------------------------------------------------------------------- */
348 * Calculating the end position of previous line.
350 * @param buf editor buffer object
351 * @param current_pos current position
352 * @param end_string_symbol end of line symbol
353 * @return end position of previous line
357 edit_calculate_end_of_previous_line (const edit_buffer_t
* buf
, off_t current_pos
,
358 char end_string_symbol
)
362 for (i
= current_pos
- 1; i
>= 0; i
--)
363 if (edit_buffer_get_byte (buf
, i
) == end_string_symbol
)
369 /* --------------------------------------------------------------------------------------------- */
371 * Calculating the start position of previous line.
373 * @param buf editor buffer object
374 * @param current_pos current position
375 * @param end_string_symbol end of line symbol
376 * @return start position of previous line
380 edit_calculate_start_of_previous_line (const edit_buffer_t
* buf
, off_t current_pos
,
381 char end_string_symbol
)
383 current_pos
= edit_calculate_end_of_previous_line (buf
, current_pos
, end_string_symbol
);
384 current_pos
= edit_calculate_end_of_previous_line (buf
, current_pos
, end_string_symbol
);
386 return (current_pos
+ 1);
389 /* --------------------------------------------------------------------------------------------- */
391 * Calculating the start position of current line.
393 * @param buf editor buffer object
394 * @param current_pos current position
395 * @param end_string_symbol end of line symbol
396 * @return start position of current line
400 edit_calculate_start_of_current_line (const edit_buffer_t
* buf
, off_t current_pos
,
401 char end_string_symbol
)
403 current_pos
= edit_calculate_end_of_previous_line (buf
, current_pos
, end_string_symbol
);
405 return (current_pos
+ 1);
408 /* --------------------------------------------------------------------------------------------- */
410 * Fixing (if needed) search start position if 'only in selection' option present.
412 * @param edit editor object
416 edit_search_fix_search_start_if_selection (WEdit
* edit
)
418 off_t start_mark
= 0;
421 if (!edit_search_options
.only_in_selection
)
424 if (!eval_marks (edit
, &start_mark
, &end_mark
))
427 if (edit_search_options
.backwards
)
429 if (edit
->search_start
> end_mark
|| edit
->search_start
<= start_mark
)
430 edit
->search_start
= end_mark
;
434 if (edit
->search_start
< start_mark
|| edit
->search_start
>= end_mark
)
435 edit
->search_start
= start_mark
;
439 /* --------------------------------------------------------------------------------------------- */
442 edit_find (edit_search_status_msg_t
* esm
, gsize
* len
)
444 WEdit
*edit
= esm
->edit
;
445 off_t search_start
= edit
->search_start
;
447 off_t start_mark
= 0;
448 off_t end_mark
= edit
->buffer
.size
;
449 char end_string_symbol
;
451 end_string_symbol
= edit_search_get_current_end_line_char (edit
);
453 /* prepare for search */
454 if (edit_search_options
.only_in_selection
)
456 if (!eval_marks (edit
, &start_mark
, &end_mark
))
458 mc_search_set_error (edit
->search
, MC_SEARCH_E_NOTFOUND
, "%s", _(STR_E_NOTFOUND
));
462 /* fix the start and the end of search block positions */
463 if ((edit
->search_line_type
& AT_START_LINE
) != 0
465 || edit_buffer_get_byte (&edit
->buffer
, start_mark
- 1) != end_string_symbol
))
467 edit_calculate_start_of_next_line (&edit
->buffer
, start_mark
, edit
->buffer
.size
,
470 if ((edit
->search_line_type
& AT_END_LINE
) != 0
471 && (end_mark
- 1 != edit
->buffer
.size
472 || edit_buffer_get_byte (&edit
->buffer
, end_mark
) != end_string_symbol
))
474 edit_calculate_end_of_previous_line (&edit
->buffer
, end_mark
, end_string_symbol
);
476 if (start_mark
>= end_mark
)
478 mc_search_set_error (edit
->search
, MC_SEARCH_E_NOTFOUND
, "%s", _(STR_E_NOTFOUND
));
482 else if (edit_search_options
.backwards
)
483 end_mark
= MAX (1, edit
->buffer
.curs1
) - 1;
486 if (edit_search_options
.backwards
)
488 /* backward search */
489 search_end
= end_mark
;
491 if ((edit
->search_line_type
& AT_START_LINE
) != 0)
493 edit_calculate_start_of_current_line (&edit
->buffer
, search_start
,
496 while (search_start
>= start_mark
)
500 if (search_end
> (off_t
) (search_start
+ edit
->search
->original
.str
->len
)
501 && mc_search_is_fixed_search_str (edit
->search
))
502 search_end
= search_start
+ edit
->search
->original
.str
->len
;
504 ok
= mc_search_run (edit
->search
, (void *) esm
, search_start
, search_end
, len
);
506 if (ok
&& edit
->search
->normal_offset
== search_start
)
509 /* We abort the search in case of a pattern error, or if the user aborts
510 the search. In other words: in all cases except "string not found". */
511 if (!ok
&& edit
->search
->error
!= MC_SEARCH_E_NOTFOUND
)
514 if ((edit
->search_line_type
& AT_START_LINE
) != 0)
516 edit_calculate_start_of_previous_line (&edit
->buffer
, search_start
,
522 mc_search_set_error (edit
->search
, MC_SEARCH_E_NOTFOUND
, "%s", _(STR_E_NOTFOUND
));
527 if ((edit
->search_line_type
& AT_START_LINE
) != 0 && search_start
!= start_mark
)
529 edit_calculate_start_of_next_line (&edit
->buffer
, search_start
, end_mark
,
532 return mc_search_run (edit
->search
, (void *) esm
, search_start
, end_mark
, len
);
535 /* --------------------------------------------------------------------------------------------- */
538 edit_replace_cmd__conv_to_display (const char *str
)
543 tmp
= str_convert_to_display (str
);
547 return g_string_free (tmp
, FALSE
);
548 g_string_free (tmp
, TRUE
);
551 return g_strdup (str
);
554 /* --------------------------------------------------------------------------------------------- */
557 edit_replace_cmd__conv_to_input (char *str
)
562 tmp
= str_convert_to_input (str
);
566 return g_string_free (tmp
, FALSE
);
567 g_string_free (tmp
, TRUE
);
570 return g_strdup (str
);
573 /* --------------------------------------------------------------------------------------------- */
576 edit_show_search_error (const WEdit
* edit
, const char *title
)
578 if (edit
->search
->error
== MC_SEARCH_E_NOTFOUND
)
579 edit_query_dialog (title
, _(STR_E_NOTFOUND
));
580 else if (edit
->search
->error_str
!= NULL
)
581 edit_query_dialog (title
, edit
->search
->error_str
);
584 /* --------------------------------------------------------------------------------------------- */
587 edit_do_search (WEdit
* edit
)
589 edit_search_status_msg_t esm
;
592 /* This shouldn't happen */
593 assert (edit
->search
!= NULL
);
595 edit_push_undo_action (edit
, KEY_PRESS
+ edit
->start_display
);
599 esm
.offset
= edit
->search_start
;
601 status_msg_init (STATUS_MSG (&esm
), _("Search"), 1.0, simple_status_msg_init_cb
,
602 edit_search_status_update_cb
, NULL
);
604 if (search_create_bookmark
)
606 gboolean found
= FALSE
;
607 long l
= 0, l_last
= -1;
610 search_create_bookmark
= FALSE
;
611 book_mark_flush (edit
, -1);
613 while (mc_search_run (edit
->search
, (void *) &esm
, q
, edit
->buffer
.size
, &len
))
616 edit
->search_start
= edit
->search
->normal_offset
;
619 l
+= edit_buffer_count_lines (&edit
->buffer
, q
, edit
->search
->normal_offset
);
621 book_mark_insert (edit
, l
, BOOK_MARK_FOUND_COLOR
);
623 q
= edit
->search
->normal_offset
+ 1;
627 edit_error_dialog (_("Search"), _(STR_E_NOTFOUND
));
629 edit_cursor_move (edit
, edit
->search_start
- edit
->buffer
.curs1
);
633 if (edit
->found_len
!= 0 && edit
->search_start
== edit
->found_start
+ 1
634 && edit_search_options
.backwards
)
635 edit
->search_start
--;
637 if (edit
->found_len
!= 0 && edit
->search_start
== edit
->found_start
- 1
638 && !edit_search_options
.backwards
)
639 edit
->search_start
++;
641 if (edit_find (&esm
, &len
))
643 edit
->found_start
= edit
->search_start
= edit
->search
->normal_offset
;
644 edit
->found_len
= len
;
646 edit_cursor_move (edit
, edit
->search_start
- edit
->buffer
.curs1
);
647 edit_scroll_screen_over_cursor (edit
);
648 if (edit_search_options
.backwards
)
649 edit
->search_start
--;
651 edit
->search_start
++;
655 edit
->search_start
= edit
->buffer
.curs1
;
656 edit_show_search_error (edit
, _("Search"));
660 status_msg_deinit (STATUS_MSG (&esm
));
662 edit
->force
|= REDRAW_COMPLETELY
;
663 edit_scroll_screen_over_cursor (edit
);
666 /* --------------------------------------------------------------------------------------------- */
669 edit_search (WEdit
* edit
)
671 if (edit_dialog_search_show (edit
))
672 edit_do_search (edit
);
675 /* --------------------------------------------------------------------------------------------- */
676 /*** public functions ****************************************************************************/
677 /* --------------------------------------------------------------------------------------------- */
680 edit_search_init (WEdit
* edit
, const char *str
)
683 edit
->search
= mc_search_new (str
, cp_source
);
685 edit
->search
= mc_search_new (str
, NULL
);
688 if (edit
->search
== NULL
)
691 edit
->search
->search_type
= edit_search_options
.type
;
693 edit
->search
->is_all_charsets
= edit_search_options
.all_codepages
;
695 edit
->search
->is_case_sensitive
= edit_search_options
.case_sens
;
696 edit
->search
->whole_words
= edit_search_options
.whole_words
;
697 edit
->search
->search_fn
= edit_search_cmd_callback
;
698 edit
->search
->update_fn
= edit_search_update_callback
;
700 edit
->search_line_type
= edit_get_search_line_type (edit
->search
);
702 edit_search_fix_search_start_if_selection (edit
);
707 /* --------------------------------------------------------------------------------------------- */
710 edit_search_deinit (WEdit
* edit
)
712 mc_search_free (edit
->search
);
713 g_free (edit
->last_search_string
);
716 /* --------------------------------------------------------------------------------------------- */
719 edit_search_cmd_callback (const void *user_data
, gsize char_offset
, int *current_char
)
721 WEdit
*edit
= ((const edit_search_status_msg_t
*) user_data
)->edit
;
723 *current_char
= edit_buffer_get_byte (&edit
->buffer
, (off_t
) char_offset
);
725 return MC_SEARCH_CB_OK
;
728 /* --------------------------------------------------------------------------------------------- */
731 edit_search_update_callback (const void *user_data
, gsize char_offset
)
733 status_msg_t
*sm
= STATUS_MSG (user_data
);
735 ((edit_search_status_msg_t
*) sm
)->offset
= (off_t
) char_offset
;
737 return (sm
->update (sm
) == B_CANCEL
? MC_SEARCH_CB_ABORT
: MC_SEARCH_CB_OK
);
740 /* --------------------------------------------------------------------------------------------- */
743 edit_search_status_update_cb (status_msg_t
* sm
)
745 simple_status_msg_t
*ssm
= SIMPLE_STATUS_MSG (sm
);
746 edit_search_status_msg_t
*esm
= (edit_search_status_msg_t
*) sm
;
747 Widget
*wd
= WIDGET (sm
->dlg
);
750 label_set_textv (ssm
->label
, _("Searching %s: %3d%%"), esm
->edit
->last_search_string
,
751 edit_buffer_calc_percent (&esm
->edit
->buffer
, esm
->offset
));
753 label_set_textv (ssm
->label
, _("Searching %s"), esm
->edit
->last_search_string
);
757 Widget
*lw
= WIDGET (ssm
->label
);
761 r
.cols
= MAX (r
.cols
, lw
->rect
.cols
+ 6);
762 widget_set_size_rect (wd
, &r
);
764 r
.x
= wd
->rect
.x
+ (wd
->rect
.cols
- r
.cols
) / 2;
765 widget_set_size_rect (lw
, &r
);
769 return status_msg_common_update (sm
);
772 /* --------------------------------------------------------------------------------------------- */
775 edit_search_cmd (WEdit
* edit
, gboolean again
)
779 else if (edit
->last_search_string
!= NULL
)
780 edit_do_search (edit
);
783 /* find last search string in history */
786 s
= mc_config_history_get_recent_item (MC_HISTORY_SHARED_SEARCH
);
789 edit
->last_search_string
= s
;
791 if (edit_search_init (edit
, edit
->last_search_string
))
793 edit_do_search (edit
);
797 /* found, but cannot init search */
798 MC_PTR_FREE (edit
->last_search_string
);
801 /* if not... then ask for an expression */
806 /* --------------------------------------------------------------------------------------------- */
807 /** call with edit = 0 before shutdown to close memory leaks */
810 edit_replace_cmd (WEdit
* edit
, gboolean again
)
812 /* 1 = search string, 2 = replace with */
813 static char *saved1
= NULL
; /* saved default[123] */
814 static char *saved2
= NULL
;
815 char *input1
= NULL
; /* user input from the dialog */
817 GString
*input2_str
= NULL
;
820 long times_replaced
= 0;
821 gboolean once_found
= FALSE
;
822 edit_search_status_msg_t esm
;
826 MC_PTR_FREE (saved1
);
827 MC_PTR_FREE (saved2
);
831 edit
->force
|= REDRAW_COMPLETELY
;
833 if (again
&& saved1
== NULL
&& saved2
== NULL
)
838 input1
= g_strdup (saved1
!= NULL
? saved1
: "");
839 input2
= g_strdup (saved2
!= NULL
? saved2
: "");
843 char *tmp_inp1
, *tmp_inp2
;
845 disp1
= edit_replace_cmd__conv_to_display (saved1
!= NULL
? saved1
: "");
846 disp2
= edit_replace_cmd__conv_to_display (saved2
!= NULL
? saved2
: "");
848 edit_push_undo_action (edit
, KEY_PRESS
+ edit
->start_display
);
850 edit_dialog_replace_show (edit
, disp1
, disp2
, &input1
, &input2
);
855 if (input1
== NULL
|| *input1
== '\0')
857 edit
->force
= REDRAW_COMPLETELY
;
863 input1
= edit_replace_cmd__conv_to_input (input1
);
864 input2
= edit_replace_cmd__conv_to_input (input2
);
869 saved1
= g_strdup (input1
);
871 saved2
= g_strdup (input2
);
873 mc_search_free (edit
->search
);
877 input2_str
= g_string_new_take (input2
);
880 if (edit
->search
== NULL
&& !edit_search_init (edit
, input1
))
882 edit
->search_start
= edit
->buffer
.curs1
;
886 if (edit
->found_len
!= 0 && edit
->search_start
== edit
->found_start
+ 1
887 && edit_search_options
.backwards
)
888 edit
->search_start
--;
890 if (edit
->found_len
!= 0 && edit
->search_start
== edit
->found_start
- 1
891 && !edit_search_options
.backwards
)
892 edit
->search_start
++;
896 esm
.offset
= edit
->search_start
;
898 status_msg_init (STATUS_MSG (&esm
), _("Search"), 1.0, simple_status_msg_init_cb
,
899 edit_search_status_update_cb
, NULL
);
905 if (!edit_find (&esm
, &len
))
907 if (!(edit
->search
->error
== MC_SEARCH_E_OK
||
908 (once_found
&& edit
->search
->error
== MC_SEARCH_E_NOTFOUND
)))
909 edit_show_search_error (edit
, _("Search"));
915 edit
->search_start
= edit
->search
->normal_offset
;
916 /* returns negative on not found or error in pattern */
918 if (edit
->search_start
>= 0 && edit
->search_start
< edit
->buffer
.size
)
923 edit
->found_start
= edit
->search_start
;
924 edit
->found_len
= len
;
926 edit_cursor_move (edit
, edit
->search_start
- edit
->buffer
.curs1
);
927 edit_scroll_screen_over_cursor (edit
);
929 if (edit
->replace_mode
== 0)
934 l
= edit
->curs_row
- WIDGET (edit
)->rect
.lines
/ 3;
936 edit_scroll_downward (edit
, l
);
938 edit_scroll_upward (edit
, -l
);
940 edit_scroll_screen_over_cursor (edit
);
941 edit
->force
|= REDRAW_PAGE
;
942 edit_render_keypress (edit
);
944 /*so that undo stops at each query */
945 edit_push_key_press (edit
);
946 /* and prompt 2/3 down */
947 disp1
= edit_replace_cmd__conv_to_display (saved1
);
948 disp2
= edit_replace_cmd__conv_to_display (saved2
);
949 prompt
= edit_dialog_replace_prompt_show (edit
, disp1
, disp2
, -1, -1);
953 if (prompt
== B_REPLACE_ALL
)
954 edit
->replace_mode
= 1;
955 else if (prompt
== B_SKIP_REPLACE
)
957 if (edit_search_options
.backwards
)
958 edit
->search_start
--;
960 edit
->search_start
++;
963 else if (prompt
== B_CANCEL
)
965 edit
->replace_mode
= -1;
970 repl_str
= mc_search_prepare_replace_str (edit
->search
, input2_str
);
972 if (edit
->search
->error
!= MC_SEARCH_E_OK
)
974 edit_show_search_error (edit
, _("Replace"));
975 if (repl_str
!= NULL
)
976 g_string_free (repl_str
, TRUE
);
980 /* delete then insert new */
981 for (i
= 0; i
< len
; i
++)
982 edit_delete (edit
, TRUE
);
984 for (i
= 0; i
< repl_str
->len
; i
++)
985 edit_insert (edit
, repl_str
->str
[i
]);
987 edit
->found_len
= repl_str
->len
;
988 g_string_free (repl_str
, TRUE
);
991 /* so that we don't find the same string again */
992 if (edit_search_options
.backwards
)
993 edit
->search_start
--;
996 edit
->search_start
+= edit
->found_len
+ (len
== 0 ? 1 : 0);
998 if (edit
->search_start
>= edit
->buffer
.size
)
1002 edit_scroll_screen_over_cursor (edit
);
1006 /* try and find from right here for next search */
1007 edit
->search_start
= edit
->buffer
.curs1
;
1008 edit_update_curs_col (edit
);
1010 edit
->force
|= REDRAW_PAGE
;
1011 edit_render_keypress (edit
);
1013 if (times_replaced
== 0)
1014 query_dialog (_("Replace"), _(STR_E_NOTFOUND
), D_NORMAL
, 1, _("&OK"));
1018 while (edit
->replace_mode
>= 0);
1020 status_msg_deinit (STATUS_MSG (&esm
));
1021 edit_scroll_screen_over_cursor (edit
);
1022 edit
->force
|= REDRAW_COMPLETELY
;
1023 edit_render_keypress (edit
);
1025 if (edit
->replace_mode
== 1 && times_replaced
!= 0)
1026 message (D_NORMAL
, _("Replace"), _("%ld replacements made"), times_replaced
);
1031 if (input2_str
!= NULL
)
1032 g_string_free (input2_str
, TRUE
);
1035 /* --------------------------------------------------------------------------------------------- */