From a705b67288f61907a7ea5f4b81e92759846e1c9d Mon Sep 17 00:00:00 2001 From: Andrew Borodin Date: Sun, 10 Apr 2022 16:59:37 +0300 Subject: [PATCH] Implement more option for panel filter: "Files only", "Case sensitive", and "Using shell patterns". Signed-off-by: Andrew Borodin --- src/filemanager/dir.c | 33 +++++++++++++++++----- src/filemanager/dir.h | 25 +++++++++++++++-- src/filemanager/panel.c | 61 ++++++++++++++++++++++++----------------- src/filemanager/panel.h | 13 ++------- 4 files changed, 87 insertions(+), 45 deletions(-) diff --git a/src/filemanager/dir.c b/src/filemanager/dir.c index cfa631e8f..5862da6f9 100644 --- a/src/filemanager/dir.c +++ b/src/filemanager/dir.c @@ -6,7 +6,7 @@ Written by: Slava Zanko , 2013 - Andrew Borodin , 2013 + Andrew Borodin , 2013-2022 This file is part of the Midnight Commander. @@ -145,10 +145,11 @@ clean_sort_keys (dir_list * list, int start, int count) */ static gboolean -handle_dirent (struct vfs_dirent *dp, const char *filter, struct stat *buf1, gboolean * link_to_dir, - gboolean * stale_link) +handle_dirent (struct vfs_dirent *dp, const file_filter_t * filter, struct stat *buf1, + gboolean * link_to_dir, gboolean * stale_link) { vfs_path_t *vpath; + gboolean ok = TRUE; if (DIR_IS_DOT (dp->d_name) || DIR_IS_DOTDOT (dp->d_name)) return FALSE; @@ -176,8 +177,15 @@ handle_dirent (struct vfs_dirent *dp, const char *filter, struct stat *buf1, gbo vfs_path_free (vpath, TRUE); - return (S_ISDIR (buf1->st_mode) || *link_to_dir || filter == NULL - || mc_search (filter, NULL, dp->d_name, MC_SEARCH_T_GLOB)); + if (filter != NULL && filter->handler != NULL) + { + gboolean files_only = (filter->flags & SELECT_FILES_ONLY) != 0; + + ok = ((S_ISDIR (buf1->st_mode) || *link_to_dir) && files_only) + || mc_search_run (filter->handler, dp->d_name, 0, strlen (dp->d_name), NULL); + } + + return ok; } /* --------------------------------------------------------------------------------------------- */ @@ -620,7 +628,7 @@ handle_path (const char *path, struct stat * buf1, gboolean * link_to_dir, gbool gboolean dir_list_load (dir_list * list, const vfs_path_t * vpath, GCompareFunc sort, - const dir_sort_options_t * sort_op, const char *filter) + const dir_sort_options_t * sort_op, const file_filter_t * filter) { DIR *dirp; struct vfs_dirent *dp; @@ -693,7 +701,7 @@ if_link_is_exe (const vfs_path_t * full_name_vpath, const file_entry_t * file) gboolean dir_list_reload (dir_list * list, const vfs_path_t * vpath, GCompareFunc sort, - const dir_sort_options_t * sort_op, const char *filter) + const dir_sort_options_t * sort_op, const file_filter_t * filter) { DIR *dirp; struct vfs_dirent *dp; @@ -814,3 +822,14 @@ dir_list_reload (dir_list * list, const vfs_path_t * vpath, GCompareFunc sort, } /* --------------------------------------------------------------------------------------------- */ + +void +file_filter_clear (file_filter_t * filter) +{ + MC_PTR_FREE (filter->value); + mc_search_free (filter->handler); + filter->handler = NULL; + /* keep filter->flags */ +} + +/* --------------------------------------------------------------------------------------------- */ diff --git a/src/filemanager/dir.h b/src/filemanager/dir.h index 8189db5a9..f6a65ee42 100644 --- a/src/filemanager/dir.h +++ b/src/filemanager/dir.h @@ -8,6 +8,7 @@ #include #include "lib/global.h" +#include "lib/search.h" #include "lib/util.h" #include "lib/vfs/vfs.h" @@ -23,6 +24,16 @@ typedef enum DIR_CLOSE } dir_list_cb_state_t; +/* selection flags */ +typedef enum +{ + SELECT_FILES_ONLY = 1 << 0, + SELECT_MATCH_CASE = 1 << 1, + SELECT_SHELL_PATTERNS = 1 << 2 +} select_flags_t; + +#define FILE_FILTER_DEFAULT_FLAGS (SELECT_FILES_ONLY | SELECT_MATCH_CASE | SELECT_SHELL_PATTERNS) + /* dir_list callback */ typedef void (*dir_list_cb_fn) (dir_list_cb_state_t state, void *data); @@ -51,6 +62,14 @@ typedef struct dir_sort_options_struct gboolean exec_first; /**< executables are at top of list */ } dir_sort_options_t; +/* filter */ +typedef struct +{ + char *value; + mc_search_t *handler; + select_flags_t flags; +} file_filter_t; + /*** global variables defined in .c file *********************************************************/ /*** declarations of public functions ************************************************************/ @@ -60,9 +79,9 @@ gboolean dir_list_append (dir_list * list, const char *fname, const struct stat gboolean link_to_dir, gboolean stale_link); gboolean dir_list_load (dir_list * list, const vfs_path_t * vpath, GCompareFunc sort, - const dir_sort_options_t * sort_op, const char *filter); + const dir_sort_options_t * sort_op, const file_filter_t * filter); gboolean dir_list_reload (dir_list * list, const vfs_path_t * vpath, GCompareFunc sort, - const dir_sort_options_t * sort_op, const char *filter); + const dir_sort_options_t * sort_op, const file_filter_t * filter); void dir_list_sort (dir_list * list, GCompareFunc sort, const dir_sort_options_t * sort_op); gboolean dir_list_init (dir_list * list); void dir_list_clean (dir_list * list); @@ -83,6 +102,8 @@ int sort_inode (file_entry_t * a, file_entry_t * b); gboolean if_link_is_exe (const vfs_path_t * full_name, const file_entry_t * file); +void file_filter_clear (file_filter_t * filter); + /*** inline functions ****************************************************************************/ static inline gboolean diff --git a/src/filemanager/panel.c b/src/filemanager/panel.c index 1c2c80466..9396e7363 100644 --- a/src/filemanager/panel.c +++ b/src/filemanager/panel.c @@ -991,7 +991,7 @@ display_mini_info (WPanel * panel) { Widget *w = WIDGET (panel); - if (!panels_options.show_mini_info) + if (!panels_options.show_mini_info || panel->selected < 0) return; widget_gotoyx (w, panel_lines (panel) + 3, 1); @@ -1497,6 +1497,8 @@ panel_destroy (WPanel * p) } g_free (p->dir_history.name); + file_filter_clear (&p->filter); + g_slist_free_full (p->format, (GDestroyNotify) format_item_free); g_slist_free_full (p->status_format, (GDestroyNotify) format_item_free); @@ -1592,10 +1594,10 @@ panel_print_header (const WPanel * panel) g_string_append (format_txt, fi->title); - if (panel->filter != NULL && strcmp (fi->id, "name") == 0) + if (panel->filter.handler != NULL && strcmp (fi->id, "name") == 0) { g_string_append (format_txt, " ["); - g_string_append (format_txt, panel->filter); + g_string_append (format_txt, panel->filter.value); g_string_append (format_txt, "]"); } @@ -2529,7 +2531,7 @@ mark_file_left (WPanel * panel) static mc_search_t * panel_select_unselect_files_dialog (select_flags_t * flags, const char *title, - const char *history_name, const char *help_section) + const char *history_name, const char *help_section, char **str) { gboolean files_only = (*flags & SELECT_FILES_ONLY) != 0; gboolean case_sens = (*flags & SELECT_MATCH_CASE) != 0; @@ -2563,6 +2565,8 @@ panel_select_unselect_files_dialog (select_flags_t * flags, const char *title, if (reg_exp == NULL || *reg_exp == '\0') { g_free (reg_exp); + if (str != NULL) + *str = NULL; return SELECT_RESET; } @@ -2571,7 +2575,10 @@ panel_select_unselect_files_dialog (select_flags_t * flags, const char *title, search->is_entire_line = TRUE; search->is_case_sensitive = case_sens; - g_free (reg_exp); + if (str != NULL) + *str = reg_exp; + else + g_free (reg_exp); if (!mc_search_prepare (search)) { @@ -2603,7 +2610,7 @@ panel_select_unselect_files (WPanel * panel, const char *title, const char *hist int i; search = panel_select_unselect_files_dialog (&panels_options.select_flags, title, history_name, - help_section); + help_section, NULL); if (search == NULL || search == SELECT_RESET || search == SELECT_ERROR) return; @@ -2663,17 +2670,19 @@ panel_select_invert_files (WPanel * panel) static void panel_do_set_filter (WPanel * panel) { - char *reg_exp; - const char *x; + file_filter_t ff = {.value = NULL,.handler = NULL,.flags = panel->filter.flags }; - x = panel->filter != NULL ? panel->filter : easy_patterns ? "*" : "."; + ff.handler = + panel_select_unselect_files_dialog (&ff.flags, _("Filter"), MC_HISTORY_FM_PANEL_FILTER, + "[Filter...]", &ff.value); - reg_exp = input_dialog_help (_("Filter"), - _("Set expression for filtering filenames"), - "[Filter...]", MC_HISTORY_FM_PANEL_FILTER, x, FALSE, - INPUT_COMPLETE_FILENAMES); - if (reg_exp != NULL) - panel_set_filter (panel, reg_exp); + if (ff.handler == NULL || ff.handler == SELECT_ERROR) + return; + + if (ff.handler == SELECT_RESET) + ff.handler = NULL; + + panel_set_filter (panel, &ff); } /* --------------------------------------------------------------------------------------------- */ @@ -3339,7 +3348,7 @@ panel_do_cd_int (WPanel * panel, const vfs_path_t * new_dir_vpath, enum cd_enum panel_clean_dir (panel); if (!dir_list_load (&panel->dir, panel->cwd_vpath, panel->sort_field->sort_routine, - &panel->sort_info, panel->filter)) + &panel->sort_info, &panel->filter)) message (D_ERROR, MSG_ERROR, _("Cannot read directory contents")); try_to_select (panel, get_parent_dir_name (panel->cwd_vpath, olddir_vpath)); @@ -4383,6 +4392,8 @@ panel_sized_empty_new (const char *panel_name, int y, int x, int lines, int cols panel->list_format = list_full; panel->user_format = g_strdup (DEFAULT_USER_FORMAT); + panel->filter.flags = FILE_FILTER_DEFAULT_FLAGS; + for (i = 0; i < LIST_FORMATS; i++) panel->user_status_format[i] = g_strdup (DEFAULT_USER_FORMAT); @@ -4473,7 +4484,7 @@ panel_sized_with_dir_new (const char *panel_name, int y, int x, int lines, int c /* Load the default format */ if (!dir_list_load (&panel->dir, panel->cwd_vpath, panel->sort_field->sort_routine, - &panel->sort_info, panel->filter)) + &panel->sort_info, &panel->filter)) message (D_ERROR, MSG_ERROR, _("Cannot read directory contents")); /* Restore old right path */ @@ -4521,7 +4532,7 @@ panel_reload (WPanel * panel) show_dir (panel); if (!dir_list_reload (&panel->dir, panel->cwd_vpath, panel->sort_field->sort_routine, - &panel->sort_info, panel->filter)) + &panel->sort_info, &panel->filter)) message (D_ERROR, MSG_ERROR, _("Cannot read directory contents")); panel->dirty = TRUE; @@ -4594,15 +4605,15 @@ set_panel_formats (WPanel * p) /* --------------------------------------------------------------------------------------------- */ void -panel_set_filter (WPanel * panel, char *filter) +panel_set_filter (WPanel * panel, const file_filter_t * filter) { - MC_PTR_FREE (panel->filter); + MC_PTR_FREE (panel->filter.value); + mc_search_free (panel->filter.handler); + panel->filter.handler = NULL; - /* Three ways to clear filter: NULL, "", "*" */ - if (filter == NULL || filter[0] == '\0' || (filter[0] == '*' && filter[1] == '\0')) - g_free (filter); - else - panel->filter = filter; + /* NULL to clear filter */ + if (filter != NULL) + panel->filter = *filter; reread_cmd (); } diff --git a/src/filemanager/panel.h b/src/filemanager/panel.h index 9945adda3..f7cbfa4b5 100644 --- a/src/filemanager/panel.h +++ b/src/filemanager/panel.h @@ -49,16 +49,7 @@ typedef enum UP_ONLY_CURRENT = 2 } panel_update_flags_t; -/* selection flags */ -typedef enum -{ - SELECT_FILES_ONLY = 1 << 0, - SELECT_MATCH_CASE = 1 << 1, - SELECT_SHELL_PATTERNS = 1 << 2 -} select_flags_t; - /* run mode and params */ - enum cd_enum { cd_parse_command, @@ -129,7 +120,7 @@ typedef struct gboolean user_mini_status; /* Is user_status_format used */ char *user_status_format[LIST_FORMATS]; /* User format for status line */ - char *filter; /* File name filter */ + file_filter_t filter; /* File name filter */ struct { @@ -179,7 +170,7 @@ vfs_path_t *remove_encoding_from_path (const vfs_path_t * vpath); void update_panels (panel_update_flags_t flags, const char *current_file); int set_panel_formats (WPanel * p); -void panel_set_filter (WPanel * panel, char *filter); +void panel_set_filter (WPanel * panel, const file_filter_t * filter); void try_to_select (WPanel * panel, const char *name);