Skip to content

Commit

Permalink
Add tests for edit_replace_cmd().
Browse files Browse the repository at this point in the history
  * (status_msg_init): add MC_MOCKABLE attribute.
  * (status_msg_deinit): likewise.
  * (edit_search_update_callback): likewise.
  * (edit_dialog_replace_show): add MC_MOCKABLE and make public.
  * (edit_dialog_replace_prompt_show): likewise.
  * (edit_search_options): make public.
  * (B_REPLACE_ALL, B_REPLACE_ONE, B_SKIP_REPLACE): likewise.
  * (macros_list): init explicitly.
  * tests/src/editor/mc.charsets: add ASCII charset.
  * tests/src/editor/edit_replace_cmd.c: new file.
  * tests/src/editor/Makefile.am: add new test.

Signed-off-by: Andrew Borodin <[email protected]>
  • Loading branch information
aborodin committed Feb 9, 2025
1 parent 3922b5f commit d2f5487
Show file tree
Hide file tree
Showing 7 changed files with 531 additions and 159 deletions.
7 changes: 4 additions & 3 deletions lib/widget/wtools.h
Original file line number Diff line number Diff line change
Expand Up @@ -84,9 +84,10 @@ gboolean mc_error_message (GError **mcerror, int *code);
status_msg_t *status_msg_create (const char *title, double delay, status_msg_cb init_cb,
status_msg_update_cb update_cb, status_msg_cb deinit_cb);
void status_msg_destroy (status_msg_t *sm);
void status_msg_init (status_msg_t *sm, const char *title, double delay, status_msg_cb init_cb,
status_msg_update_cb update_cb, status_msg_cb deinit_cb);
void status_msg_deinit (status_msg_t *sm);
MC_MOCKABLE void status_msg_init (status_msg_t *sm, const char *title, double delay,
status_msg_cb init_cb, status_msg_update_cb update_cb,
status_msg_cb deinit_cb);
MC_MOCKABLE void status_msg_deinit (status_msg_t *sm);
int status_msg_common_update (status_msg_t *sm);

void simple_status_msg_init_cb (status_msg_t *sm);
Expand Down
299 changes: 146 additions & 153 deletions src/editor/editsearch.c
Original file line number Diff line number Diff line change
Expand Up @@ -47,29 +47,7 @@

/*** global variables ****************************************************************************/

/*** file scope macro definitions ****************************************************************/

#define B_REPLACE_ALL (B_USER + 1)
#define B_REPLACE_ONE (B_USER + 2)
#define B_SKIP_REPLACE (B_USER + 3)

/*** file scope type declarations ****************************************************************/

typedef struct edit_search_options_t
{
mc_search_type_t type;
gboolean case_sens;
gboolean backwards;
gboolean only_in_selection;
gboolean whole_words;
gboolean all_codepages;
} edit_search_options_t;

/*** forward declarations (file scope functions) *************************************************/

/*** file scope variables ************************************************************************/

static edit_search_options_t edit_search_options = {
edit_search_options_t edit_search_options = {
.type = MC_SEARCH_T_NORMAL,
.case_sens = FALSE,
.backwards = FALSE,
Expand All @@ -78,6 +56,21 @@ static edit_search_options_t edit_search_options = {
.all_codepages = FALSE,
};

/*** file scope macro definitions ****************************************************************/

/*** file scope type declarations ****************************************************************/

/*** forward declarations (file scope functions) *************************************************/

MC_MOCKABLE void edit_dialog_replace_show (WEdit *edit, const char *search_default,
const char *replace_default, char **search_text,
char **replace_text);

MC_MOCKABLE int edit_dialog_replace_prompt_show (WEdit *edit, char *from_text, char *to_text,
int xpos, int ypos);

/*** file scope variables ************************************************************************/

/* --------------------------------------------------------------------------------------------- */
/*** file scope functions ************************************************************************/
/* --------------------------------------------------------------------------------------------- */
Expand Down Expand Up @@ -165,136 +158,6 @@ edit_dialog_search_show (WEdit *edit)

/* --------------------------------------------------------------------------------------------- */

static void
edit_dialog_replace_show (WEdit *edit, const char *search_default, const char *replace_default,
/*@out@ */ char **search_text, /*@out@ */ char **replace_text)
{
size_t num_of_types = 0;
gchar **list_of_types;

if ((search_default == NULL) || (*search_default == '\0'))
search_default = INPUT_LAST_TEXT;

list_of_types = mc_search_get_types_strings_array (&num_of_types);

{
quick_widget_t quick_widgets[] = {
// clang-format off
QUICK_LABELED_INPUT (N_ ("Enter search string:"), input_label_above, search_default,
MC_HISTORY_SHARED_SEARCH, search_text, NULL, FALSE, FALSE,
INPUT_COMPLETE_NONE),
QUICK_LABELED_INPUT (N_ ("Enter replacement string:"), input_label_above,
replace_default, "replace", replace_text, NULL, FALSE, FALSE,
INPUT_COMPLETE_NONE),
QUICK_SEPARATOR (TRUE),
QUICK_START_COLUMNS,
QUICK_RADIO (num_of_types, (const char **) list_of_types,
(int *) &edit_search_options.type, NULL),
QUICK_NEXT_COLUMN,
QUICK_CHECKBOX (N_ ("Cas&e sensitive"), &edit_search_options.case_sens, NULL),
QUICK_CHECKBOX (N_ ("&Backwards"), &edit_search_options.backwards, NULL),
QUICK_CHECKBOX (N_ ("In se&lection"), &edit_search_options.only_in_selection, NULL),
QUICK_CHECKBOX (N_ ("&Whole words"), &edit_search_options.whole_words, NULL),
#ifdef HAVE_CHARSET
QUICK_CHECKBOX (N_ ("&All charsets"), &edit_search_options.all_codepages, NULL),
#endif
QUICK_STOP_COLUMNS,
QUICK_BUTTONS_OK_CANCEL,
QUICK_END,
// clang-format on
};

WRect r = { -1, -1, 0, 58 };

quick_dialog_t qdlg = {
.rect = r,
.title = N_ ("Replace"),
.help = "[Input Line Keys]",
.widgets = quick_widgets,
.callback = NULL,
.mouse_callback = NULL,
};

if (quick_dialog (&qdlg) != B_CANCEL)
edit->replace_mode = 0;
else
{
*replace_text = NULL;
*search_text = NULL;
}
}

g_strfreev (list_of_types);
}

/* --------------------------------------------------------------------------------------------- */

static int
edit_dialog_replace_prompt_show (WEdit *edit, char *from_text, char *to_text, int xpos, int ypos)
{
Widget *w = WIDGET (edit);

// dialog size
int dlg_height = 10;
int dlg_width;

char tmp[BUF_MEDIUM];
char *repl_from, *repl_to;
int retval;

if (xpos == -1)
xpos = w->rect.x + edit_options.line_state_width + 1;
if (ypos == -1)
ypos = w->rect.y + w->rect.lines / 2;
// Sometimes menu can hide replaced text. I don't like it
if ((edit->curs_row >= ypos - 1) && (edit->curs_row <= ypos + dlg_height - 1))
ypos -= dlg_height;

dlg_width = WIDGET (w->owner)->rect.cols - xpos - 1;

g_snprintf (tmp, sizeof (tmp), "\"%s\"", from_text);
repl_from = g_strdup (str_trunc (tmp, dlg_width - 7));

g_snprintf (tmp, sizeof (tmp), "\"%s\"", to_text);
repl_to = g_strdup (str_trunc (tmp, dlg_width - 7));

{
quick_widget_t quick_widgets[] = {
// clang-format off
QUICK_LABEL (repl_from, NULL),
QUICK_LABEL (N_ ("Replace with:"), NULL),
QUICK_LABEL (repl_to, NULL),
QUICK_START_BUTTONS (TRUE, TRUE),
QUICK_BUTTON (N_ ("&Replace"), B_ENTER, NULL, NULL),
QUICK_BUTTON (N_ ("A&ll"), B_REPLACE_ALL, NULL, NULL),
QUICK_BUTTON (N_ ("&Skip"), B_SKIP_REPLACE, NULL, NULL),
QUICK_BUTTON (N_ ("&Cancel"), B_CANCEL, NULL, NULL),
QUICK_END,
// clang-format on
};

WRect r = { ypos, xpos, 0, -1 };

quick_dialog_t qdlg = {
.rect = r,
.title = N_ ("Confirm replace"),
.help = NULL,
.widgets = quick_widgets,
.callback = NULL,
.mouse_callback = NULL,
};

retval = quick_dialog (&qdlg);
}

g_free (repl_from);
g_free (repl_to);

return retval;
}

/* --------------------------------------------------------------------------------------------- */

/**
* Get EOL symbol for searching.
*
Expand Down Expand Up @@ -824,6 +687,136 @@ edit_search_cmd (WEdit *edit, gboolean again)
}
}

/* --------------------------------------------------------------------------------------------- */

void
edit_dialog_replace_show (WEdit *edit, const char *search_default, const char *replace_default,
/*@out@ */ char **search_text, /*@out@ */ char **replace_text)
{
size_t num_of_types = 0;
gchar **list_of_types;

if ((search_default == NULL) || (*search_default == '\0'))
search_default = INPUT_LAST_TEXT;

list_of_types = mc_search_get_types_strings_array (&num_of_types);

{
quick_widget_t quick_widgets[] = {
// clang-format off
QUICK_LABELED_INPUT (N_ ("Enter search string:"), input_label_above, search_default,
MC_HISTORY_SHARED_SEARCH, search_text, NULL, FALSE, FALSE,
INPUT_COMPLETE_NONE),
QUICK_LABELED_INPUT (N_ ("Enter replacement string:"), input_label_above,
replace_default, "replace", replace_text, NULL, FALSE, FALSE,
INPUT_COMPLETE_NONE),
QUICK_SEPARATOR (TRUE),
QUICK_START_COLUMNS,
QUICK_RADIO (num_of_types, (const char **) list_of_types,
(int *) &edit_search_options.type, NULL),
QUICK_NEXT_COLUMN,
QUICK_CHECKBOX (N_ ("Cas&e sensitive"), &edit_search_options.case_sens, NULL),
QUICK_CHECKBOX (N_ ("&Backwards"), &edit_search_options.backwards, NULL),
QUICK_CHECKBOX (N_ ("In se&lection"), &edit_search_options.only_in_selection, NULL),
QUICK_CHECKBOX (N_ ("&Whole words"), &edit_search_options.whole_words, NULL),
#ifdef HAVE_CHARSET
QUICK_CHECKBOX (N_ ("&All charsets"), &edit_search_options.all_codepages, NULL),
#endif
QUICK_STOP_COLUMNS,
QUICK_BUTTONS_OK_CANCEL,
QUICK_END,
// clang-format on
};

WRect r = { -1, -1, 0, 58 };

quick_dialog_t qdlg = {
.rect = r,
.title = N_ ("Replace"),
.help = "[Input Line Keys]",
.widgets = quick_widgets,
.callback = NULL,
.mouse_callback = NULL,
};

if (quick_dialog (&qdlg) != B_CANCEL)
edit->replace_mode = 0;
else
{
*replace_text = NULL;
*search_text = NULL;
}
}

g_strfreev (list_of_types);
}

/* --------------------------------------------------------------------------------------------- */

int
edit_dialog_replace_prompt_show (WEdit *edit, char *from_text, char *to_text, int xpos, int ypos)
{
Widget *w = WIDGET (edit);

// dialog size
int dlg_height = 10;
int dlg_width;

char tmp[BUF_MEDIUM];
char *repl_from, *repl_to;
int retval;

if (xpos == -1)
xpos = w->rect.x + edit_options.line_state_width + 1;
if (ypos == -1)
ypos = w->rect.y + w->rect.lines / 2;
// Sometimes menu can hide replaced text. I don't like it
if ((edit->curs_row >= ypos - 1) && (edit->curs_row <= ypos + dlg_height - 1))
ypos -= dlg_height;

dlg_width = WIDGET (w->owner)->rect.cols - xpos - 1;

g_snprintf (tmp, sizeof (tmp), "\"%s\"", from_text);
repl_from = g_strdup (str_trunc (tmp, dlg_width - 7));

g_snprintf (tmp, sizeof (tmp), "\"%s\"", to_text);
repl_to = g_strdup (str_trunc (tmp, dlg_width - 7));

{
quick_widget_t quick_widgets[] = {
// clang-format off
QUICK_LABEL (repl_from, NULL),
QUICK_LABEL (N_ ("Replace with:"), NULL),
QUICK_LABEL (repl_to, NULL),
QUICK_START_BUTTONS (TRUE, TRUE),
QUICK_BUTTON (N_ ("&Replace"), B_ENTER, NULL, NULL),
QUICK_BUTTON (N_ ("A&ll"), B_REPLACE_ALL, NULL, NULL),
QUICK_BUTTON (N_ ("&Skip"), B_SKIP_REPLACE, NULL, NULL),
QUICK_BUTTON (N_ ("&Cancel"), B_CANCEL, NULL, NULL),
QUICK_END,
// clang-format on
};

WRect r = { ypos, xpos, 0, -1 };

quick_dialog_t qdlg = {
.rect = r,
.title = N_ ("Confirm replace"),
.help = NULL,
.widgets = quick_widgets,
.callback = NULL,
.mouse_callback = NULL,
};

retval = quick_dialog (&qdlg);
}

g_free (repl_from);
g_free (repl_to);

return retval;
}

/* --------------------------------------------------------------------------------------------- */
/** call with edit = 0 before shutdown to close memory leaks */

Expand Down
19 changes: 18 additions & 1 deletion src/editor/editsearch.h
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,24 @@

/*** typedefs(not structures) and defined constants **********************************************/

#define B_REPLACE_ALL (B_USER + 1)
#define B_REPLACE_ONE (B_USER + 2)
#define B_SKIP_REPLACE (B_USER + 3)

/*** enums ***************************************************************************************/

/*** structures declarations (and typedefs of structures)*****************************************/

typedef struct edit_search_options_t
{
mc_search_type_t type;
gboolean case_sens;
gboolean backwards;
gboolean only_in_selection;
gboolean whole_words;
gboolean all_codepages;
} edit_search_options_t;

typedef struct
{
simple_status_msg_t status_msg; // base class
Expand All @@ -18,14 +32,17 @@ typedef struct

/*** global variables defined in .c file *********************************************************/

extern edit_search_options_t edit_search_options;

/*** declarations of public functions ************************************************************/

gboolean edit_search_init (WEdit *edit, const char *s);
void edit_search_deinit (WEdit *edit);

mc_search_cbret_t edit_search_cmd_callback (const void *user_data, off_t char_offset,
int *current_char);
mc_search_cbret_t edit_search_update_callback (const void *user_data, off_t char_offset);
MC_MOCKABLE mc_search_cbret_t edit_search_update_callback (const void *user_data,
off_t char_offset);
int edit_search_status_update_cb (status_msg_t *sm);

void edit_search_cmd (WEdit *edit, gboolean again);
Expand Down
2 changes: 1 addition & 1 deletion src/setup.c
Original file line number Diff line number Diff line change
Expand Up @@ -211,7 +211,7 @@ int macro_index = -1;
/* macro stuff */
struct macro_action_t record_macro_buf[MAX_MACRO_LENGTH];

GArray *macros_list;
GArray *macros_list = NULL;
#endif

/*** file scope macro definitions ****************************************************************/
Expand Down
Loading

0 comments on commit d2f5487

Please sign in to comment.