[gedit] open-selector: improvements



commit b34a0698d5b04d1a85491f3c2996b1039cc9f52d
Author: Sebastien Lafargue <slafargue gnome org>
Date:   Sun Jan 11 19:49:57 2015 +0100

    open-selector: improvements
    
    - various fixes and cleanuup
    - refactoring
    - better items filtering
    - Case-insensitive highlighting of results
    - faster ( consolidation of some files's queries )
    
    https://bugzilla.gnome.org/show_bug.cgi?id=742787

 gedit/gedit-open-document-selector-helper.c |   28 ++-
 gedit/gedit-open-document-selector-helper.h |    4 +
 gedit/gedit-open-document-selector-store.c  |   23 +-
 gedit/gedit-open-document-selector.c        |  370 ++++++++++++++++++++++-----
 4 files changed, 345 insertions(+), 80 deletions(-)
---
diff --git a/gedit/gedit-open-document-selector-helper.c b/gedit/gedit-open-document-selector-helper.c
index 21b87ae..369d12e 100644
--- a/gedit/gedit-open-document-selector-helper.c
+++ b/gedit/gedit-open-document-selector-helper.c
@@ -26,7 +26,6 @@ gedit_open_document_selector_debug_print_list (const gchar *title,
 {
        FileItem *item;
        GList *l;
-       gchar *uri;
        glong time_sec;
        glong time_usec;
 
@@ -37,15 +36,33 @@ gedit_open_document_selector_debug_print_list (const gchar *title,
                item = (FileItem *)l->data;
                time_sec = item->access_time.tv_sec;
                time_usec = item->access_time.tv_usec;
-               uri = item->uri;
-               g_print ("%ld:%ld%s\n", time_sec, time_usec, uri);
+
+               g_print ("%ld:%ld uri:%s (%s %s)\n",
+                        time_sec,
+                        time_usec,
+                        item->uri,
+                        item->name,
+                        item->path);
        }
 }
 
+FileItem *
+gedit_open_document_selector_create_fileitem_item (void)
+{
+       FileItem *item;
+
+       item = g_slice_new0 (FileItem);
+
+       return item;
+}
+
 void
 gedit_open_document_selector_free_fileitem_item (FileItem *item)
 {
        g_free (item->uri);
+       g_free (item->name);
+       g_free (item->path);
+
        g_slice_free (FileItem, item);
 }
 
@@ -54,8 +71,11 @@ gedit_open_document_selector_copy_fileitem_item (FileItem *item)
 {
        FileItem *new_item;
 
-       new_item = g_slice_new (FileItem);
+       new_item = gedit_open_document_selector_create_fileitem_item ();
+
        new_item->uri = g_strdup (item->uri);
+       new_item->name = g_strdup (item->name);
+       new_item->path = g_strdup (item->path);
        new_item->access_time = item->access_time;
 
        return new_item;
diff --git a/gedit/gedit-open-document-selector-helper.h b/gedit/gedit-open-document-selector-helper.h
index 61a9a90..b6278c2 100644
--- a/gedit/gedit-open-document-selector-helper.h
+++ b/gedit/gedit-open-document-selector-helper.h
@@ -30,6 +30,8 @@ G_BEGIN_DECLS
 typedef struct
 {
        gchar *uri;
+       gchar *name;
+       gchar *path;
        GTimeVal access_time;
 } FileItem;
 
@@ -88,6 +90,8 @@ GList         *gedit_open_document_selector_copy_file_items_list      (const GList *file_ite
 
 void            gedit_open_document_selector_free_file_items_list      (GList *file_items_list);
 
+FileItem       *gedit_open_document_selector_create_fileitem_item      (void);
+
 void            gedit_open_document_selector_free_fileitem_item        (FileItem *item);
 
 FileItem       *gedit_open_document_selector_copy_fileitem_item        (FileItem *item);
diff --git a/gedit/gedit-open-document-selector-store.c b/gedit/gedit-open-document-selector-store.c
index 8bf92c3..81228bc 100644
--- a/gedit/gedit-open-document-selector-store.c
+++ b/gedit/gedit-open-document-selector-store.c
@@ -110,7 +110,7 @@ get_current_docs_list (GeditOpenDocumentSelectorStore *selector_store,
                        continue;
                }
 
-               item = (FileItem *)g_slice_new (FileItem);
+               item = gedit_open_document_selector_create_fileitem_item ();
 
                item->access_time.tv_sec = g_file_info_get_attribute_uint64 (info, "time::access");
                item->access_time.tv_usec = g_file_info_get_attribute_uint32 (info, "time::access-usec");
@@ -175,7 +175,6 @@ get_children_from_dir (GeditOpenDocumentSelectorStore *selector_store,
        GFileInfo *info;
        GFileType filetype;
        GFile *file;
-       gchar *uri;
        FileItem *item;
        gboolean is_text;
        gboolean is_correct_type;
@@ -183,7 +182,6 @@ get_children_from_dir (GeditOpenDocumentSelectorStore *selector_store,
        g_return_val_if_fail (G_IS_FILE (dir), NULL);
 
        file_enum = g_file_enumerate_children (dir,
-                                              "standard::name,"
                                               "standard::type,"
                                               "standard::fast-content-type,"
                                               "time::access,time::access-usec",
@@ -207,9 +205,8 @@ get_children_from_dir (GeditOpenDocumentSelectorStore *selector_store,
                    is_correct_type &&
                    (file = g_file_enumerator_get_child (file_enum, info)) != NULL)
                {
-                       item = (FileItem *)g_slice_new (FileItem);
-                       uri = g_file_get_uri (file);
-                       item->uri = uri;
+                       item = gedit_open_document_selector_create_fileitem_item ();
+                       item->uri = g_file_get_uri (file);
 
                        item->access_time.tv_sec = g_file_info_get_attribute_uint64 (info, "time::access");
                        item->access_time.tv_usec = g_file_info_get_attribute_uint32 (info, 
"time::access-usec");
@@ -458,7 +455,12 @@ convert_recent_item_list_to_fileitem_list (GList *uri_list)
 
                uri = g_strdup (gtk_recent_info_get_uri (l->data));
                file = g_file_new_for_uri (uri);
-               info = g_file_query_info (file, "time::access,time::access-usec", G_FILE_QUERY_INFO_NONE, 
NULL, NULL);
+               info = g_file_query_info (file,
+                                         "time::access,time::access-usec",
+                                         G_FILE_QUERY_INFO_NONE,
+                                         NULL,
+                                         NULL);
+
                g_object_unref (file);
 
                if (info == NULL)
@@ -467,8 +469,9 @@ convert_recent_item_list_to_fileitem_list (GList *uri_list)
                        continue;
                }
 
-               item = g_slice_new (FileItem);
+               item = gedit_open_document_selector_create_fileitem_item ();
                item->uri = uri;
+
                /* We query access time because gtk_recent_info_get_modified() doesn't give us the usec part 
*/
                item->access_time.tv_sec = g_file_info_get_attribute_uint64 (info, "time::access");
                item->access_time.tv_usec = g_file_info_get_attribute_uint32 (info, "time::access-usec");
@@ -578,12 +581,12 @@ gedit_open_document_selector_store_class_init (GeditOpenDocumentSelectorStoreCla
 static GList * (*list_func [])(GeditOpenDocumentSelectorStore *selector_store,
                                GeditOpenDocumentSelector      *selector) =
 {
-       get_local_bookmarks_list,
+       get_recent_files_list,
        get_home_dir_list,
        get_desktop_dir_list,
+       get_local_bookmarks_list,
        get_file_browser_root_dir_list,
        get_active_doc_dir_list,
-       get_recent_files_list,
        get_current_docs_list
 };
 
diff --git a/gedit/gedit-open-document-selector.c b/gedit/gedit-open-document-selector.c
index 913f409..61c0fbc 100644
--- a/gedit/gedit-open-document-selector.c
+++ b/gedit/gedit-open-document-selector.c
@@ -60,6 +60,12 @@ struct _GeditOpenDocumentSelectorPrivate
        gint populate_scheduled : 1;
 };
 
+typedef enum
+{
+       SELECTOR_TAG_NONE,
+       SELECTOR_TAG_MATCH
+} SelectorTag;
+
 enum
 {
        NAME_COLUMN,
@@ -83,36 +89,204 @@ enum
        PROP_WINDOW
 };
 
+/* Value 0xFF is reserved to mark the end of the array */
+#define BYTE_ARRAY_END 0xFF
+
 #define OPEN_DOCUMENT_SELECTOR_WIDTH 400
 #define OPEN_DOCUMENT_SELECTOR_MAX_VISIBLE_ROWS 10
 
 G_DEFINE_TYPE_WITH_PRIVATE (GeditOpenDocumentSelector, gedit_open_document_selector, GTK_TYPE_BOX)
 
+static inline const guint8 *
+get_byte_run (const guint8 *byte_array,
+              gsize        *count,
+              SelectorTag  *tag)
+{
+       guint8 tag_found;
+       gsize c = 1;
+
+       tag_found = *byte_array++;
+
+       while ( *byte_array != BYTE_ARRAY_END && *byte_array == tag_found)
+       {
+               c++;
+               byte_array++;
+       }
+
+       *count = c;
+       *tag = tag_found;
+
+       return ( *byte_array != BYTE_ARRAY_END) ? byte_array : NULL;
+}
+
+static gchar*
+get_markup_from_tagged_byte_array (const gchar  *str,
+                                   const guint8 *byte_array)
+{
+       gchar *txt;
+       GString *string;
+       gchar *result_str;
+       SelectorTag tag;
+       gsize count;
+
+       string = g_string_sized_new (255);
+
+       while (TRUE)
+       {
+               byte_array = get_byte_run (byte_array, &count, &tag);
+               txt = g_markup_escape_text (str, count);
+               if (tag == SELECTOR_TAG_MATCH)
+               {
+                       g_string_append_printf (string, "<span weight =\"heavy\" color =\"black\">%s</span>", 
txt);
+               }
+               else
+               {
+                       g_string_append (string, txt);
+               }
+
+               g_free (txt);
+
+               if (!byte_array)
+               {
+                       break;
+               }
+
+               str = (const gchar *)((gsize)str + count);
+       }
+
+       result_str = g_string_free (string, FALSE);
+       return result_str;
+}
+
+static guint8 *
+get_tagged_byte_array (const gchar *uri,
+                       GRegex      *filter_regex)
+{
+       guint8 *byte_array;
+       gsize uri_len;
+       GMatchInfo *match_info;
+       gboolean no_match = TRUE;
+
+       g_return_val_if_fail (uri != NULL, NULL);
+
+       uri_len = strlen (uri);
+       byte_array = g_malloc0 (uri_len + 1);
+       byte_array[uri_len] = BYTE_ARRAY_END;
+
+       if (g_regex_match (filter_regex, uri, 0, &match_info) == TRUE)
+       {
+               while (g_match_info_matches (match_info) == TRUE)
+               {
+                       guint8 *p;
+                       gint match_len;
+                       gint start_pos;
+                       gint end_pos;
+
+                       if (g_match_info_fetch_pos (match_info, 0, &start_pos, &end_pos) == TRUE)
+                       {
+                               match_len = end_pos - start_pos;
+                               no_match = FALSE;
+
+                               p = (guint8 *)((gsize)byte_array + start_pos);
+                               memset (p, SELECTOR_TAG_MATCH, match_len);
+                       }
+
+                       g_match_info_next (match_info, NULL);
+               }
+       }
+
+       g_match_info_free (match_info);
+
+       if (no_match)
+       {
+               g_free (byte_array);
+               return NULL;
+       }
+
+       return byte_array;
+}
+
+static void
+get_markup_for_path_and_name (GRegex       *filter_regex,
+                              const gchar  *src_path,
+                              const gchar  *src_name,
+                              gchar       **dst_path,
+                              gchar       **dst_name)
+{
+       gchar *filename;
+       gsize path_len;
+       gsize name_len;
+       gsize path_separator_len;
+       guint8 *byte_array;
+       guint8 *path_byte_array;
+       guint8 *name_byte_array;
+
+       filename = g_build_filename (src_path, src_name, NULL);
+
+       path_len = g_utf8_strlen (src_path, -1);
+       name_len = g_utf8_strlen (src_name, -1);
+       path_separator_len = g_utf8_strlen (filename, -1) - ( path_len + name_len);
+
+       byte_array = get_tagged_byte_array (filename, filter_regex);
+       if (byte_array)
+       {
+               path_byte_array = g_memdup (byte_array, path_len + 1);
+               path_byte_array[path_len] = BYTE_ARRAY_END;
+
+               /* name_byte_array is part of byte_array, so released with it */
+               name_byte_array = (guint8 *)((gsize)byte_array + path_len + path_separator_len);
+
+               *dst_path = get_markup_from_tagged_byte_array (src_path, path_byte_array);
+               *dst_name = get_markup_from_tagged_byte_array (src_name, name_byte_array);
+
+               g_free (byte_array);
+               g_free (path_byte_array);
+       }
+       else
+       {
+               *dst_path = g_strdup (src_path);
+               *dst_name = g_strdup (src_name);
+       }
+
+       g_free (filename);
+}
+
 static void
 create_row (GeditOpenDocumentSelector *selector,
-            const gchar               *uri)
+            const FileItem            *item,
+            GRegex                    *filter_regex)
 {
        GeditOpenDocumentSelectorPrivate *priv = selector->priv;
        GtkTreeIter iter;
-       gchar *name;
-       gchar *path;
-       GFile *location;
+       gchar *uri;
+       gchar *dst_path;
+       gchar *dst_name;
 
-       location = g_file_new_for_uri (uri);
+       uri =item->uri;
 
-       name = gedit_utils_basename_for_display (location);
-       path = gedit_utils_location_get_dirname_for_display (location);
+       if (filter_regex)
+       {
+               get_markup_for_path_and_name (filter_regex,
+                                             (const gchar *)item->path,
+                                             (const gchar *)item->name,
+                                             &dst_path,
+                                             &dst_name);
+       }
+       else
+       {
+               dst_path = g_strdup (item->path);
+               dst_name = g_strdup (item->name);
+       }
 
        gtk_list_store_append (priv->liststore, &iter);
        gtk_list_store_set (priv->liststore, &iter,
                            URI_COLUMN, uri,
-                           NAME_COLUMN, name,
-                           PATH_COLUMN, path,
+                           NAME_COLUMN, dst_name,
+                           PATH_COLUMN, dst_path,
                            -1);
 
-       g_free (name);
-       g_free (path);
-       g_object_unref (location);
+       g_free (dst_path);
+       g_free (dst_name);
 }
 
 static gint
@@ -127,7 +301,7 @@ sort_items_by_mru (FileItem *a,
 
        if (diff == 0)
        {
-               return b->access_time.tv_usec - a->access_time.tv_usec;
+               return (b->access_time.tv_usec - a->access_time.tv_usec);
        }
        else
        {
@@ -157,6 +331,12 @@ compute_all_items_list (GeditOpenDocumentSelector *selector)
        active_doc_dir_items = gedit_open_document_selector_copy_file_items_list ((const GList 
*)priv->active_doc_dir_items);
        current_docs_items = gedit_open_document_selector_copy_file_items_list ((const GList 
*)priv->current_docs_items);
 
+       if (priv->all_items)
+       {
+               gedit_open_document_selector_free_file_items_list (priv->all_items);
+               priv->all_items = NULL;
+       }
+
        all_items = g_list_concat (all_items, recent_items);
        all_items = g_list_concat (all_items, home_dir_items);
        all_items = g_list_concat (all_items, desktop_dir_items);
@@ -189,6 +369,100 @@ clamp_recent_items_list (GList *recent_items,
        return recent_items_capped;
 }
 
+/* Setup the fileitem, depending uri's scheme
+ * Return a string to search in.
+ */
+static gchar *
+fileitem_setup (FileItem *item)
+{
+       gchar *scheme;
+       gchar *filename;
+       gchar *candidate = NULL;
+
+       scheme = g_uri_parse_scheme (item->uri);
+       if (g_strcmp0 (scheme, "file") == 0)
+       {
+               filename = g_filename_from_uri ((const gchar *)item->uri, NULL, NULL);
+               if (filename)
+               {
+                       item->path = g_path_get_dirname (filename);
+                       item->name = g_path_get_basename (filename);
+                       candidate = g_utf8_strdown (filename, -1);
+
+                       g_free (filename);
+               }
+       }
+
+       g_free (scheme);
+
+       return candidate;
+}
+
+/* If filter == NULL then items are
+ * not checked against the filter.
+ */
+static GList *
+fileitem_list_filter (GList       *items,
+                      const gchar *filter)
+{
+       GList *new_items = NULL;
+       GList *l;
+
+       for (l = items; l != NULL; l = l->next)
+       {
+               FileItem *item;
+               gchar *candidate;
+
+               item = l->data;
+               candidate = fileitem_setup (item);
+
+               if (candidate && (filter ==  NULL || strstr (candidate, filter)))
+               {
+                       new_items = g_list_prepend (new_items,
+                                                   gedit_open_document_selector_copy_fileitem_item (item));
+               }
+
+               g_free (candidate);
+       }
+
+       new_items = g_list_reverse (new_items);
+       return new_items;
+}
+
+/* Remove duplicated, the HEAD of the list never change,
+ * the list passed in is modified.
+ */
+static void
+fileitem_list_remove_duplicates (GList *items)
+{
+       GList *l;
+       G_GNUC_UNUSED GList *dummy_ptr;
+
+       l = items;
+       while (l != NULL)
+       {
+               gchar *l_uri, *l1_uri;
+               GList *l1;
+
+               if ((l1 = l->next) == NULL)
+               {
+                       break;
+               }
+
+               l_uri = ((FileItem *)l->data)->uri;
+               l1_uri = ((FileItem *)l1->data)->uri;
+               if (g_strcmp0 (l_uri, l1_uri) == 0)
+               {
+                       gedit_open_document_selector_free_fileitem_item ((FileItem *)l1->data);
+                       dummy_ptr = g_list_delete_link (items, l1);
+               }
+               else
+               {
+                       l = l->next;
+               }
+       }
+}
+
 static gboolean
 real_populate_liststore (gpointer data)
 {
@@ -198,6 +472,7 @@ real_populate_liststore (gpointer data)
        GList *l;
        GList *filter_items = NULL;
        gchar *filter;
+       GRegex *filter_regex = NULL;
        priv->populate_liststore_is_idle = FALSE;
 
        DEBUG_SELECTOR_TIMER_DECL
@@ -210,60 +485,16 @@ real_populate_liststore (gpointer data)
        {
                DEBUG_SELECTOR (g_print ("Selector(%p): populate liststore: all lists\n", selector););
 
-               for (l = priv->all_items; l != NULL; l = l->next)
-               {
-                       FileItem *item;
-                       gchar *uri_lower;
-                       gchar *scheme;
-                       gint end_of_scheme_pos = 0;
-
-                       item = l->data;
-                       uri_lower = g_utf8_strdown (item->uri, -1);
-                       scheme = g_uri_parse_scheme (uri_lower);
-                       if (scheme)
-                       {
-                               end_of_scheme_pos = strlen (scheme) + 1;
-                               g_free (scheme);
-                       }
-
-                       if (strstr (uri_lower + end_of_scheme_pos, filter))
-                       {
-                               filter_items = g_list_prepend (filter_items,
-                                                              
gedit_open_document_selector_copy_fileitem_item (item));
-                       }
-
-                       g_free (uri_lower);
-               }
-
+               filter_items = fileitem_list_filter (priv->all_items, (const gchar *)filter);
                filter_items = g_list_sort_with_data (filter_items, (GCompareDataFunc)sort_items_by_mru, 
NULL);
-               /* Remove doubles, the HEAD of the list never change */
-               l = filter_items;
-               while (l != NULL)
-               {
-                       gchar *l_uri, *l1_uri;
-                       GList *l1;
-
-                       if ((l1 = l->next) == NULL)
-                       {
-                               break;
-                       }
+               fileitem_list_remove_duplicates (filter_items);
 
-                       l_uri = ((FileItem *)l->data)->uri;
-                       l1_uri = ((FileItem *)l1->data)->uri;
-                       if (g_strcmp0 (l_uri, l1_uri) == 0)
-                       {
-                               gedit_open_document_selector_free_fileitem_item ((FileItem *)l1->data);
-                               filter_items = g_list_delete_link (filter_items, l1);
-                       }
-                       else
-                       {
-                               l = l->next;
-                       }
-               }
+               filter_regex = g_regex_new (filter, G_REGEX_CASELESS, 0, NULL);
        }
        else
        {
                gint recent_limit;
+               GList *recent_items;
 
                DEBUG_SELECTOR (g_print ("Selector(%p): populate liststore: recent files list\n", selector););
 
@@ -271,11 +502,13 @@ real_populate_liststore (gpointer data)
 
                if (recent_limit > 0 )
                {
-                       filter_items = clamp_recent_items_list (priv->recent_items, recent_limit);
+                       recent_items = fileitem_list_filter (priv->recent_items, NULL);
+                       filter_items = clamp_recent_items_list (recent_items, recent_limit);
+                       gedit_open_document_selector_free_file_items_list (recent_items);
                }
                else
                {
-                       filter_items = gedit_open_document_selector_copy_file_items_list (priv->recent_items);
+                       filter_items = fileitem_list_filter (priv->recent_items, NULL);
                }
        }
 
@@ -293,7 +526,12 @@ real_populate_liststore (gpointer data)
                FileItem *item;
 
                item = l->data;
-               create_row (selector, (const gchar *)item->uri);
+               create_row (selector, (const FileItem *)item, filter_regex);
+       }
+
+       if (filter_regex)
+       {
+               g_regex_unref (filter_regex);
        }
 
        gedit_open_document_selector_free_file_items_list (filter_items);
@@ -821,8 +1059,8 @@ setup_treeview (GeditOpenDocumentSelector *selector)
        gtk_tree_view_column_pack_start (column, priv->name_renderer, TRUE);
        gtk_tree_view_column_pack_start (column, priv->path_renderer, TRUE);
 
-       gtk_tree_view_column_set_attributes (column, priv->name_renderer, "text", NAME_COLUMN, NULL);
-       gtk_tree_view_column_set_attributes (column, priv->path_renderer, "text", PATH_COLUMN, NULL);
+       gtk_tree_view_column_set_attributes (column, priv->name_renderer, "markup", NAME_COLUMN, NULL);
+       gtk_tree_view_column_set_attributes (column, priv->path_renderer, "markup", PATH_COLUMN, NULL);
 
        gtk_tree_view_append_column (GTK_TREE_VIEW (priv->treeview), column);
        cell_area = gtk_cell_layout_get_area (GTK_CELL_LAYOUT (column));


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]