[gedit] open-selector: improvements
- From: Sebastien Lafargue <slafargue src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gedit] open-selector: improvements
- Date: Mon, 12 Jan 2015 18:06:36 +0000 (UTC)
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]