diff options
| author | Victor Kareh <[email protected]> | 2025-09-21 19:09:14 +0000 |
|---|---|---|
| committer | GitHub <[email protected]> | 2025-09-21 19:09:14 +0000 |
| commit | f3998312f42dbd8b76eba71b976015b0813769f7 (patch) | |
| tree | 41b4fd62889a774b2d1e4d19e2a86c3acb14ab07 /libcaja-private | |
| parent | f093cfa7e4cbb27280576d39d63e5000df9f0d7c (diff) | |
| download | caja-f3998312f42dbd8b76eba71b976015b0813769f7.tar.bz2 caja-f3998312f42dbd8b76eba71b976015b0813769f7.tar.xz | |
File search improvements (#1851)
* search: Respect hidden files setting when searching
When starting a search, check the current window's hidden files mode and
apply the same setting to search results. This ensures search results
match the visibility of files in the current directory view.
* search: Add support for globs
Add globbing when searching for files. Caja will autodetect if the query
contains a glob and change its search to use that instead of substrings.
Example:
- "*.txt" finds all text files
- "photo-?.jpg" finds numbered photo files
- "data[0-9]*.csv" finds numbered data files
* search: Add location tooltips for search results
Display file location in tooltips when hovering over search results in
both icon and list views. This can help users tell where files are
located since search happens across subdirectories.
Diffstat (limited to 'libcaja-private')
| -rw-r--r-- | libcaja-private/caja-file.c | 9 | ||||
| -rw-r--r-- | libcaja-private/caja-search-directory.c | 6 | ||||
| -rw-r--r-- | libcaja-private/caja-search-directory.h | 3 | ||||
| -rw-r--r-- | libcaja-private/caja-search-engine-simple.c | 80 | ||||
| -rw-r--r-- | libcaja-private/caja-search-engine.c | 10 | ||||
| -rw-r--r-- | libcaja-private/caja-search-engine.h | 2 |
6 files changed, 98 insertions, 12 deletions
diff --git a/libcaja-private/caja-file.c b/libcaja-private/caja-file.c index faea7993..2fc9c030 100644 --- a/libcaja-private/caja-file.c +++ b/libcaja-private/caja-file.c @@ -149,7 +149,8 @@ static GQuark attribute_name_q, attribute_where_q, attribute_link_target_q, attribute_volume_q, - attribute_free_space_q; + attribute_free_space_q, + attribute_location_q; static void caja_file_info_iface_init (CajaFileInfoIface *iface); static char * caja_file_get_owner_as_string (CajaFile *file, @@ -6504,7 +6505,7 @@ caja_file_get_deep_directory_count_as_string (CajaFile *file) * set includes "name", "type", "mime_type", "size", "size_on_disk", "deep_size", "deep_size_on_disk", * "deep_directory_count", "deep_file_count", "deep_total_count", "date_modified", "date_changed", * "date_accessed", "date_permissions", "owner", "group", "permissions", "octal_permissions", "uri", "where", - * "link_target", "volume", "free_space", "selinux_context", "trashed_on", "trashed_orig_path" + * "link_target", "location", "volume", "free_space", "selinux_context", "trashed_on", "trashed_orig_path" * * Returns: Newly allocated string ready to display to the user, or NULL * if the value is unknown or @attribute_name is not supported. @@ -6605,6 +6606,9 @@ caja_file_get_string_attribute_q (CajaFile *file, GQuark attribute_q) if (attribute_q == attribute_link_target_q) { return caja_file_get_symbolic_link_target_path (file); } + if (attribute_q == attribute_location_q) { + return caja_file_get_parent_uri_for_display (file); + } if (attribute_q == attribute_volume_q) { return caja_file_get_volume_name (file); } @@ -8624,6 +8628,7 @@ caja_file_class_init (CajaFileClass *class) attribute_link_target_q = g_quark_from_static_string ("link_target"); attribute_volume_q = g_quark_from_static_string ("volume"); attribute_free_space_q = g_quark_from_static_string ("free_space"); + attribute_location_q = g_quark_from_static_string ("location"); G_OBJECT_CLASS (class)->finalize = finalize; G_OBJECT_CLASS (class)->constructor = caja_file_constructor; diff --git a/libcaja-private/caja-search-directory.c b/libcaja-private/caja-search-directory.c index da2e133b..fbd3f17e 100644 --- a/libcaja-private/caja-search-directory.c +++ b/libcaja-private/caja-search-directory.c @@ -846,6 +846,12 @@ caja_search_directory_get_query (CajaSearchDirectory *search) return NULL; } +CajaSearchEngine * +caja_search_directory_get_engine (CajaSearchDirectory *search) +{ + return search->details->engine; +} + CajaSearchDirectory * caja_search_directory_new_from_saved_search (const char *uri) { diff --git a/libcaja-private/caja-search-directory.h b/libcaja-private/caja-search-directory.h index 4214f097..95c7d07a 100644 --- a/libcaja-private/caja-search-directory.h +++ b/libcaja-private/caja-search-directory.h @@ -27,6 +27,7 @@ #include "caja-directory.h" #include "caja-query.h" +#include "caja-search-engine.h" #define CAJA_TYPE_SEARCH_DIRECTORY caja_search_directory_get_type() #define CAJA_SEARCH_DIRECTORY(obj) \ @@ -70,4 +71,6 @@ CajaQuery *caja_search_directory_get_query (CajaSearchDirectory *search); void caja_search_directory_set_query (CajaSearchDirectory *search, CajaQuery *query); +CajaSearchEngine *caja_search_directory_get_engine (CajaSearchDirectory *search); + #endif /* CAJA_SEARCH_DIRECTORY_H */ diff --git a/libcaja-private/caja-search-engine-simple.c b/libcaja-private/caja-search-engine-simple.c index aae74d23..dd87b56c 100644 --- a/libcaja-private/caja-search-engine-simple.c +++ b/libcaja-private/caja-search-engine-simple.c @@ -24,12 +24,14 @@ #include <config.h> #include <string.h> #include <glib.h> +#include <fnmatch.h> #include <gio/gio.h> #include <eel/eel-gtk-macros.h> #include "caja-search-engine-simple.h" +#include "caja-global-preferences.h" #define BATCH_SIZE 500 @@ -42,6 +44,7 @@ typedef struct GList *mime_types; GList *tags; char **words; + gboolean use_globs; GQueue *directories; /* GFiles */ @@ -51,6 +54,7 @@ typedef struct GList *uri_hits; gint64 timestamp; gint64 size; + gboolean search_hidden_files; } SearchThreadData; struct CajaSearchEngineSimpleDetails @@ -60,6 +64,7 @@ struct CajaSearchEngineSimpleDetails SearchThreadData *active_search; gboolean query_finished; + gboolean show_hidden_files; }; G_DEFINE_TYPE (CajaSearchEngineSimple, @@ -68,6 +73,18 @@ G_DEFINE_TYPE (CajaSearchEngineSimple, static CajaSearchEngineClass *parent_class = NULL; +static gboolean +text_has_glob (const char *text) +{ + if (!text) + return FALSE; + + return (strchr (text, '*') != NULL || + strchr (text, '?') != NULL || + strchr (text, '[') != NULL || + strchr (text, ']') != NULL); +} + static void finalize (GObject *object) { @@ -113,12 +130,23 @@ search_thread_data_new (CajaSearchEngineSimple *engine, g_queue_push_tail (data->directories, location); text = caja_query_get_text (query); - normalized = g_utf8_normalize (text, -1, G_NORMALIZE_NFD); - lower = g_utf8_strdown (normalized, -1); - data->words = g_strsplit (lower, " ", -1); + data->use_globs = text && text_has_glob (text); + + if (data->use_globs) + { + /* For globs, keep original case and don't normalize */ + data->words = g_strsplit (text, " ", -1); + } + else + { + /* For substring matching, normalize and lowercase */ + normalized = g_utf8_normalize (text, -1, G_NORMALIZE_NFD); + lower = g_utf8_strdown (normalized, -1); + data->words = g_strsplit (lower, " ", -1); + g_free (lower); + g_free (normalized); + } g_free (text); - g_free (lower); - g_free (normalized); data->tags = caja_query_get_tags (query); data->mime_types = caja_query_get_mime_types (query); @@ -126,6 +154,8 @@ search_thread_data_new (CajaSearchEngineSimple *engine, data->size = caja_query_get_size (query); data->contained_text = caja_query_get_contained_text (query); + data->search_hidden_files = engine->details->show_hidden_files; + data->cancellable = g_cancellable_new (); return data; @@ -483,7 +513,7 @@ visit_directory (GFile *dir, SearchThreadData *data) while ((info = g_file_enumerator_next_file (enumerator, data->cancellable, NULL)) != NULL) { - if (g_file_info_get_is_hidden (info)) + if (g_file_info_get_is_hidden (info) && !data->search_hidden_files) { goto next; } @@ -499,12 +529,31 @@ visit_directory (GFile *dir, SearchThreadData *data) g_free (normalized); hit = TRUE; - for (i = 0; data->words[i] != NULL; i++) + if (data->use_globs) { - if (strstr (lower_name, data->words[i]) == NULL) + /* Use glob pattern matching with case-insensitive comparison */ + for (i = 0; data->words[i] != NULL; i++) { - hit = FALSE; - break; + char *lower_pattern = g_utf8_strdown (data->words[i], -1); + if (fnmatch (lower_pattern, lower_name, 0) != 0) + { + hit = FALSE; + g_free (lower_pattern); + break; + } + g_free (lower_pattern); + } + } + else + { + /* Use substring matching */ + for (i = 0; data->words[i] != NULL; i++) + { + if (strstr (lower_name, data->words[i]) == NULL) + { + hit = FALSE; + break; + } } } g_free (lower_name); @@ -721,6 +770,15 @@ caja_search_engine_simple_set_query (CajaSearchEngine *engine, CajaQuery *query) } static void +caja_search_engine_simple_set_show_hidden_files (CajaSearchEngine *engine, gboolean show_hidden_files) +{ + CajaSearchEngineSimple *simple; + + simple = CAJA_SEARCH_ENGINE_SIMPLE (engine); + simple->details->show_hidden_files = show_hidden_files; +} + +static void caja_search_engine_simple_class_init (CajaSearchEngineSimpleClass *class) { GObjectClass *gobject_class; @@ -733,6 +791,7 @@ caja_search_engine_simple_class_init (CajaSearchEngineSimpleClass *class) engine_class = CAJA_SEARCH_ENGINE_CLASS (class); engine_class->set_query = caja_search_engine_simple_set_query; + engine_class->set_show_hidden_files = caja_search_engine_simple_set_show_hidden_files; engine_class->start = caja_search_engine_simple_start; engine_class->stop = caja_search_engine_simple_stop; engine_class->is_indexed = caja_search_engine_simple_is_indexed; @@ -742,6 +801,7 @@ static void caja_search_engine_simple_init (CajaSearchEngineSimple *engine) { engine->details = g_new0 (CajaSearchEngineSimpleDetails, 1); + engine->details->show_hidden_files = g_settings_get_boolean (caja_preferences, CAJA_PREFERENCES_SHOW_HIDDEN_FILES); } CajaSearchEngine * diff --git a/libcaja-private/caja-search-engine.c b/libcaja-private/caja-search-engine.c index d8d9d9a8..9dd6ab2e 100644 --- a/libcaja-private/caja-search-engine.c +++ b/libcaja-private/caja-search-engine.c @@ -125,6 +125,16 @@ caja_search_engine_set_query (CajaSearchEngine *engine, CajaQuery *query) } void +caja_search_engine_set_show_hidden_files (CajaSearchEngine *engine, gboolean show_hidden_files) +{ + g_return_if_fail (CAJA_IS_SEARCH_ENGINE (engine)); + + if (CAJA_SEARCH_ENGINE_GET_CLASS (engine)->set_show_hidden_files != NULL) { + CAJA_SEARCH_ENGINE_GET_CLASS (engine)->set_show_hidden_files (engine, show_hidden_files); + } +} + +void caja_search_engine_start (CajaSearchEngine *engine) { g_return_if_fail (CAJA_IS_SEARCH_ENGINE (engine)); diff --git a/libcaja-private/caja-search-engine.h b/libcaja-private/caja-search-engine.h index 90bd6593..773901a1 100644 --- a/libcaja-private/caja-search-engine.h +++ b/libcaja-private/caja-search-engine.h @@ -46,6 +46,7 @@ typedef struct /* VTable */ void (*set_query) (CajaSearchEngine *engine, CajaQuery *query); + void (*set_show_hidden_files) (CajaSearchEngine *engine, gboolean show_hidden_files); void (*start) (CajaSearchEngine *engine); void (*stop) (CajaSearchEngine *engine); gboolean (*is_indexed) (CajaSearchEngine *engine); @@ -63,6 +64,7 @@ gboolean caja_search_engine_enabled (void); CajaSearchEngine* caja_search_engine_new (void); void caja_search_engine_set_query (CajaSearchEngine *engine, CajaQuery *query); +void caja_search_engine_set_show_hidden_files (CajaSearchEngine *engine, gboolean show_hidden_files); void caja_search_engine_start (CajaSearchEngine *engine); void caja_search_engine_stop (CajaSearchEngine *engine); gboolean caja_search_engine_is_indexed (CajaSearchEngine *engine); |
