[geany/geany] 5a369a: Merge pull request #3055 from techee/tagfilter-new

Enrico Tröger git-noreply at xxxxx
Sun Jan 23 23:06:51 UTC 2022


Branch:      refs/heads/master
Author:      Enrico Tröger <enrico.troeger at uvena.de>
Committer:   GitHub <noreply at github.com>
Date:        Sun, 23 Jan 2022 23:06:51 UTC
Commit:      5a369a41e3cb6fd1bc57e602fa567e8c0d153bfc
             https://github.com/geany/geany/commit/5a369a41e3cb6fd1bc57e602fa567e8c0d153bfc

Log Message:
-----------
Merge pull request #3055 from techee/tagfilter-new

Filter for symbol tree - improved version


Modified Paths:
--------------
    HACKING
    data/geany.glade
    doc/geany.txt
    src/callbacks.c
    src/callbacks.h
    src/document.c
    src/documentprivate.h
    src/editor.c
    src/symbols.c
    src/tagmanager/tm_parser.c
    src/tagmanager/tm_parser.h
    src/tagmanager/tm_tag.c
    src/tagmanager/tm_workspace.c

Modified: HACKING
2 lines changed, 1 insertions(+), 1 deletions(-)
===================================================================
@@ -676,7 +676,7 @@ MAP_ENTRY(FOO) to parser_map.
 (You may want to make the symbols.c change before doing this).
 
 In src/tagmanager/tm_parser.c:
-Update tm_parser_context_separator() and tm_parser_has_full_context() to
+Update tm_parser_scope_separator() and tm_parser_has_full_scope() to
 handle the new parser if applicable, by adding a TM_PARSER_FOO case entry.
 
 In filetypes.c, init_builtin_filetypes():


Modified: data/geany.glade
45 lines changed, 39 insertions(+), 6 deletions(-)
===================================================================
@@ -8245,17 +8245,50 @@
                     <signal name="switch-page" handler="on_tv_notebook_switch_page" swapped="no"/>
                     <signal name="switch-page" handler="on_tv_notebook_switch_page_after" after="yes" swapped="no"/>
                     <child>
-                      <object class="GtkScrolledWindow" id="scrolledwindow2">
+                      <object class="GtkVBox" id="vbox46">
                         <property name="visible">True</property>
-                        <property name="can_focus">True</property>
-                        <property name="hscrollbar_policy">automatic</property>
-                        <property name="vscrollbar_policy">automatic</property>
+                        <property name="can_focus">False</property>
+                        <child>
+                          <object class="GtkEntry" id="entry_tagfilter">
+                            <property name="visible">True</property>
+                            <property name="can_focus">True</property>
+                            <property name="tooltip_text" translatable="yes">Filter the symbol list using the entered text. Separate multiple filters with a space.</property>
+                            <property name="invisible_char">•</property>
+                            <property name="primary_icon_stock">gtk-find</property>
+                            <property name="secondary_icon_stock">gtk-clear</property>
+                            <property name="primary_icon_activatable">False</property>
+                            <property name="secondary_icon_activatable">True</property>
+                            <property name="primary_icon_sensitive">True</property>
+                            <property name="secondary_icon_sensitive">True</property>
+                            <signal name="changed" handler="on_entry_tagfilter_changed" swapped="no"/>
+                            <signal name="activate" handler="on_entry_tagfilter_activate" swapped="no"/>
+                            <signal name="icon-press" handler="on_entry_tagfilter_icon_press" swapped="no"/>
+                          </object>
+                          <packing>
+                            <property name="expand">False</property>
+                            <property name="fill">True</property>
+                            <property name="position">0</property>
+                          </packing>
+                        </child>
                         <child>
-                          <object class="GtkTreeView" id="treeview2">
+                          <object class="GtkScrolledWindow" id="scrolledwindow2">
                             <property name="visible">True</property>
                             <property name="can_focus">True</property>
-                            <property name="enable_search">False</property>
+                            <property name="hscrollbar_policy">automatic</property>
+                            <property name="vscrollbar_policy">automatic</property>
+                            <child>
+                              <object class="GtkTreeView" id="treeview2">
+                                <property name="visible">True</property>
+                                <property name="can_focus">True</property>
+                                <property name="enable_search">False</property>
+                              </object>
+                            </child>
                           </object>
+                          <packing>
+                            <property name="expand">True</property>
+                            <property name="fill">True</property>
+                            <property name="position">1</property>
+                          </packing>
                         </child>
                       </object>
                     </child>


Modified: doc/geany.txt
25 lines changed, 25 insertions(+), 0 deletions(-)
===================================================================
@@ -253,6 +253,31 @@ The position of the tabs can be selected in the interface preferences.
 The sizes of the sidebar and message window can be adjusted by
 dragging the dividers.
 
+Sidebar Usage
+^^^^^^^^^^^^^
+
+The sidebar has a right click menu that can control what is visible and
+has actions specific to the tab (other tabs added by plugins are
+described by that plugin documentation):
+
+* Symbols
+
+  * expand/collapse the tree
+  * control sorting order
+  * locate the symbol in documents
+
+  The symbols tab can also be filtered by typing a string into
+  the entry at the top of the tab. All symbols that contain the entered
+  string as a substring will be shown in the tree. Multiple filters can
+  be separated by a space.
+
+* Documents
+
+  * expand/collapse the tree
+  * save to or reload from files
+  * search tree based at selected file
+  * show or hide the document paths
+
 Command line options
 --------------------
 


Modified: src/callbacks.c
49 lines changed, 48 insertions(+), 1 deletions(-)
===================================================================
@@ -437,6 +437,44 @@ void on_toolbutton_search_clicked(GtkAction *action, gpointer user_data)
 }
 
 
+void on_entry_tagfilter_changed(GtkAction *action, gpointer user_data)
+{
+	GeanyDocument *doc = document_get_current();
+	GtkEntry *filter_entry;
+
+	if (!doc)
+		return;
+
+	filter_entry = GTK_ENTRY(ui_lookup_widget(main_widgets.window, "entry_tagfilter"));
+	g_free(doc->priv->tag_filter);
+	doc->priv->tag_filter = g_strdup(gtk_entry_get_text(filter_entry));
+
+	/* make sure the tree is fully re-created so it appears correctly
+	 * after applying filter */
+	if (doc->priv->tag_store)
+		gtk_tree_store_clear(doc->priv->tag_store);
+	sidebar_update_tag_list(doc, TRUE);
+}
+
+
+void on_entry_tagfilter_icon_press(GtkEntry *entry, GtkEntryIconPosition icon_pos, GdkEvent *event, gpointer user_data)
+{
+	if (event->button.button == 1)
+		gtk_entry_set_text(entry, "");
+}
+
+
+void on_entry_tagfilter_activate(GtkEntry *entry, gpointer user_data)
+{
+	GeanyDocument *doc = document_get_current();
+
+	if (!doc)
+		return;
+
+	gtk_widget_grab_focus(doc->priv->tag_tree);
+}
+
+
 /* hides toolbar from toolbar popup menu */
 static void on_hide_toolbar1_activate(GtkMenuItem *menuitem, gpointer user_data)
 {
@@ -491,14 +529,23 @@ static void on_notebook1_switch_page_after(GtkNotebook *notebook, gpointer page,
 
 	if (doc != NULL)
 	{
+		GtkEntry *filter_entry = GTK_ENTRY(ui_lookup_widget(main_widgets.window, "entry_tagfilter"));
+		const gchar *entry_text = gtk_entry_get_text(filter_entry);
+
 		sidebar_select_openfiles_item(doc);
 		ui_save_buttons_toggle(doc->changed);
 		ui_set_window_title(doc);
 		ui_update_statusbar(doc, -1);
 		ui_update_popup_reundo_items(doc);
 		ui_document_show_hide(doc); /* update the document menu */
 		build_menu_update(doc);
-		sidebar_update_tag_list(doc, FALSE);
+		if (g_strcmp0(entry_text, doc->priv->tag_filter) != 0)
+		{
+			/* calls sidebar_update_tag_list() in on_entry_tagfilter_changed() */
+			gtk_entry_set_text(filter_entry, doc->priv->tag_filter);
+		}
+		else
+			sidebar_update_tag_list(doc, TRUE);
 		document_highlight_tags(doc);
 
 		document_check_disk_status(doc, TRUE);


Modified: src/callbacks.h
6 lines changed, 6 insertions(+), 0 deletions(-)
===================================================================
@@ -72,6 +72,12 @@ void on_toolbar_search_entry_changed(GtkAction *action, const gchar *text, gpoin
 
 void on_toolbar_search_entry_activate(GtkAction *action, const gchar *text, gpointer user_data);
 
+void on_entry_tagfilter_changed(GtkAction *action, gpointer user_data);
+
+void on_entry_tagfilter_icon_press(GtkEntry *entry, GtkEntryIconPosition icon_pos, GdkEvent *event, gpointer user_data);
+
+void on_entry_tagfilter_activate(GtkEntry *entry, gpointer user_data);
+
 void on_toggle_case1_activate(GtkMenuItem *menuitem, gpointer user_data);
 
 void on_find_usage1_activate(GtkMenuItem *menuitem, gpointer user_data);


Modified: src/document.c
2 lines changed, 2 insertions(+), 0 deletions(-)
===================================================================
@@ -647,6 +647,7 @@ static GeanyDocument *document_create(const gchar *utf8_filename)
 
 	/* initialize default document settings */
 	doc->priv = g_new0(GeanyDocumentPrivate, 1);
+	doc->priv->tag_filter = g_strdup("");
 	doc->id = ++doc_id_counter;
 	doc->index = new_idx;
 	doc->file_name = g_strdup(utf8_filename);
@@ -734,6 +735,7 @@ static gboolean remove_page(guint page_num)
 	}
 	g_free(doc->encoding);
 	g_free(doc->priv->saved_encoding.encoding);
+	g_free(doc->priv->tag_filter);
 	g_free(doc->file_name);
 	g_free(doc->real_path);
 	if (doc->tm_file)


Modified: src/documentprivate.h
2 lines changed, 2 insertions(+), 0 deletions(-)
===================================================================
@@ -112,6 +112,8 @@ typedef struct GeanyDocumentPrivate
 	GtkWidget		*info_bars[NUM_MSG_TYPES];
 	/* Keyed Data List to attach arbitrary data to the document */
 	GData			*data;
+	/* Text used for filtering symbol tree. */
+	gchar			*tag_filter;
 }
 GeanyDocumentPrivate;
 


Modified: src/editor.c
6 lines changed, 3 insertions(+), 3 deletions(-)
===================================================================
@@ -645,7 +645,7 @@ static void show_tags_list(GeanyEditor *editor, const GPtrArray *tags, gsize roo
 static gint scope_autocomplete_suffix(ScintillaObject *sci, TMParserType lang,
 	gint pos, gboolean *scope_sep)
 {
-	const gchar *sep = tm_parser_context_separator(lang);
+	const gchar *sep = tm_parser_scope_separator(lang);
 	const gsize max_len = 3;
 	gboolean is_scope_sep;
 	gchar *buf;
@@ -708,7 +708,7 @@ static gboolean autocomplete_scope(GeanyEditor *editor, const gchar *root, gsize
 	gboolean scope_sep_typed = FALSE;
 	gboolean ret = FALSE;
 	const gchar *current_scope;
-	const gchar *context_sep = tm_parser_context_separator(ft->lang);
+	const gchar *context_sep = tm_parser_scope_separator(ft->lang);
 	gint autocomplete_suffix_len;
 
 	if (autocomplete_scope_shown)
@@ -1866,7 +1866,7 @@ static gchar *find_calltip(const gchar *word, GeanyFiletype *ft)
 	{
 		const TMTagType arg_types = tm_tag_function_t | tm_tag_prototype_t |
 			tm_tag_method_t | tm_tag_macro_with_arg_t;
-		const gchar *scope_sep = tm_parser_context_separator(ft->lang);
+		const gchar *scope_sep = tm_parser_scope_separator(ft->lang);
 		gchar *scope = EMPTY(tag->scope) ? g_strdup(tag->name) :
 			g_strjoin(scope_sep, tag->scope, tag->name, NULL);
 


Modified: src/symbols.c
54 lines changed, 43 insertions(+), 11 deletions(-)
===================================================================
@@ -265,7 +265,7 @@ GString *symbols_find_typenames_as_string(TMParserType lang, gboolean global)
 GEANY_API_SYMBOL
 const gchar *symbols_get_context_separator(gint ft_id)
 {
-	return tm_parser_context_separator(filetypes[ft_id]->lang);
+	return tm_parser_scope_separator(filetypes[ft_id]->lang);
 }
 
 
@@ -319,26 +319,58 @@ static gint compare_symbol_lines(gconstpointer a, gconstpointer b)
 static GList *get_tag_list(GeanyDocument *doc, TMTagType tag_types)
 {
 	GList *tag_names = NULL;
-	guint i;
+	guint i, j;
+	gchar **tf_strv;
 
 	g_return_val_if_fail(doc, NULL);
 
 	if (! doc->tm_file || ! doc->tm_file->tags_array)
 		return NULL;
 
+	tf_strv = g_strsplit_set(doc->priv->tag_filter, " ", -1);
+
 	for (i = 0; i < doc->tm_file->tags_array->len; ++i)
 	{
 		TMTag *tag = TM_TAG(doc->tm_file->tags_array->pdata[i]);
 
-		if (G_UNLIKELY(tag == NULL))
-			return NULL;
-
 		if (tag->type & tag_types)
 		{
-			tag_names = g_list_prepend(tag_names, tag);
+			gboolean filtered = FALSE;
+			gchar **val;
+			gchar *full_tagname = g_strconcat(tag->scope ? tag->scope : "",
+				tag->scope ? tm_parser_scope_separator_printable(tag->lang) : "",
+				tag->name, NULL);
+			gchar *normalized_tagname = g_utf8_normalize(full_tagname, -1, G_NORMALIZE_ALL);
+
+			foreach_strv(val, tf_strv)
+			{
+				gchar *normalized_val = g_utf8_normalize(*val, -1, G_NORMALIZE_ALL);
+
+				if (normalized_tagname != NULL && normalized_val != NULL)
+				{
+					gchar *case_normalized_tagname = g_utf8_casefold(normalized_tagname, -1);
+					gchar *case_normalized_val = g_utf8_casefold(normalized_val, -1);
+
+					filtered = strstr(case_normalized_tagname, case_normalized_val) == NULL;
+					g_free(case_normalized_tagname);
+					g_free(case_normalized_val);
+				}
+				g_free(normalized_val);
+
+				if (filtered)
+					break;
+			}
+			if (!filtered)
+				tag_names = g_list_prepend(tag_names, tag);
+
+			g_free(normalized_tagname);
+			g_free(full_tagname);
 		}
 	}
 	tag_names = g_list_sort(tag_names, compare_symbol_lines);
+
+	g_strfreev(tf_strv);
+
 	return tag_names;
 }
 
@@ -940,7 +972,7 @@ static const gchar *get_symbol_name(GeanyDocument *doc, const TMTag *tag, gboole
 	if (!found_parent && scope &&
 		strpbrk(scope, GEANY_WORDCHARS) == scope)
 	{
-		const gchar *sep = symbols_get_context_separator(doc->file_type->id);
+		const gchar *sep = tm_parser_scope_separator_printable(tag->lang);
 
 		g_string_append(buffer, scope);
 		g_string_append(buffer, sep);
@@ -1196,7 +1228,7 @@ static void update_parents_table(GHashTable *table, const TMTag *tag, const GtkT
 		/* simple case, just use the tag name */
 		name = tag->name;
 	}
-	else if (! tm_parser_has_full_context(tag->lang))
+	else if (! tm_parser_has_full_scope(tag->lang))
 	{
 		/* if the parser doesn't use fully qualified scope, use the name alone but
 		 * prevent Foo::Foo from making parent = child */
@@ -1208,7 +1240,7 @@ static void update_parents_table(GHashTable *table, const TMTag *tag, const GtkT
 	else
 	{
 		/* build the fully qualified scope as get_parent_name() would return it for a child tag */
-		name_free = g_strconcat(tag->scope, tm_parser_context_separator(tag->lang), tag->name, NULL);
+		name_free = g_strconcat(tag->scope, tm_parser_scope_separator(tag->lang), tag->name, NULL);
 		name = name_free;
 	}
 
@@ -1378,7 +1410,7 @@ static void update_tree_tags(GeanyDocument *doc, GList **tags)
 	/* Build hash tables holding tags and parents */
 	/* parent table is GHashTable<tag_name, GTree<line_num, GtkTreeIter>>
 	 * where tag_name might be a fully qualified name (with scope) if the language
-	 * parser reports scope properly (see tm_parser_has_full_context()). */
+	 * parser reports scope properly (see tm_parser_has_full_scope()). */
 	parents_table = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, parents_table_value_free);
 	/* tags table is another representation of the @tags list,
 	 * GHashTable<TMTag, GTree<line_num, GList<GList<TMTag>>>> */
@@ -2431,7 +2463,7 @@ static gint get_current_tag_name(GeanyDocument *doc, gchar **tagname, TMTagType
 			{
 				if (tag->scope)
 					*tagname = g_strconcat(tag->scope,
-							symbols_get_context_separator(doc->file_type->id), tag->name, NULL);
+							tm_parser_scope_separator(tag->lang), tag->name, NULL);
 				else
 					*tagname = g_strdup(tag->name);
 


Modified: src/tagmanager/tm_parser.c
26 lines changed, 21 insertions(+), 5 deletions(-)
===================================================================
@@ -835,7 +835,7 @@ void tm_parser_verify_type_mappings(void)
  * zero otherwise. */
 gint tm_parser_scope_autocomplete_suffix(TMParserType lang, const gchar *str)
 {
-	const gchar *sep = tm_parser_context_separator(lang);
+	const gchar *sep = tm_parser_scope_separator(lang);
 
 	if (g_str_has_suffix(str, sep))
 		return strlen(sep);
@@ -971,7 +971,7 @@ gchar *tm_parser_format_function(TMParserType lang, const gchar *fname, const gc
 	if (scope)
 	{
 		g_string_append(str, scope);
-		g_string_append(str, tm_parser_context_separator(lang));
+		g_string_append(str, tm_parser_scope_separator_printable(lang));
 	}
 	g_string_append(str, fname);
 	g_string_append_c(str, ' ');
@@ -1017,7 +1017,7 @@ gchar *tm_parser_format_function(TMParserType lang, const gchar *fname, const gc
 }
 
 
-const gchar *tm_parser_context_separator(TMParserType lang)
+const gchar *tm_parser_scope_separator(TMParserType lang)
 {
 	switch (lang)
 	{
@@ -1046,11 +1046,27 @@ const gchar *tm_parser_context_separator(TMParserType lang)
 }
 
 
-gboolean tm_parser_has_full_context(TMParserType lang)
+const gchar *tm_parser_scope_separator_printable(TMParserType lang)
 {
 	switch (lang)
 	{
-		/* These parsers include full hierarchy in the tag scope, separated by tm_parser_context_separator() */
+		case TM_PARSER_TXT2TAGS:
+		case TM_PARSER_ASCIIDOC:
+		case TM_PARSER_CONF:
+		case TM_PARSER_REST:
+			return " > ";
+
+		default:
+			return tm_parser_scope_separator(lang);
+	}
+}
+
+
+gboolean tm_parser_has_full_scope(TMParserType lang)
+{
+	switch (lang)
+	{
+		/* These parsers include full hierarchy in the tag scope, separated by tm_parser_scope_separator() */
 		case TM_PARSER_ACTIONSCRIPT:
 		case TM_PARSER_C:
 		case TM_PARSER_CPP:


Modified: src/tagmanager/tm_parser.h
6 lines changed, 4 insertions(+), 2 deletions(-)
===================================================================
@@ -140,9 +140,11 @@ gchar *tm_parser_format_variable(TMParserType lang, const gchar *name, const gch
 gchar *tm_parser_format_function(TMParserType lang, const gchar *fname, const gchar *args,
 	const gchar *retval, const gchar *scope);
 
-const gchar *tm_parser_context_separator(TMParserType lang);
+const gchar *tm_parser_scope_separator(TMParserType lang);
 
-gboolean tm_parser_has_full_context(TMParserType lang);
+const gchar *tm_parser_scope_separator_printable(TMParserType lang);
+
+gboolean tm_parser_has_full_scope(TMParserType lang);
 
 gboolean tm_parser_langs_compatible(TMParserType lang, TMParserType other);
 


Modified: src/tagmanager/tm_tag.c
2 lines changed, 1 insertions(+), 1 deletions(-)
===================================================================
@@ -781,7 +781,7 @@ void tm_tags_array_print(GPtrArray *tags, FILE *fp)
 */
 gint tm_tag_scope_depth(const TMTag *t)
 {
-	const gchar *context_sep = tm_parser_context_separator(t->lang);
+	const gchar *context_sep = tm_parser_scope_separator(t->lang);
 	gint depth;
 	char *s;
 	if(!(t && t->scope))


Modified: src/tagmanager/tm_workspace.c
6 lines changed, 3 insertions(+), 3 deletions(-)
===================================================================
@@ -750,7 +750,7 @@ find_scope_members_tags (const GPtrArray *all, TMTag *type_tag, gboolean namespa
 		member_types = tm_tag_max_t;
 
 	if (type_tag->scope && *(type_tag->scope))
-		scope = g_strconcat(type_tag->scope, tm_parser_context_separator(type_tag->lang), type_tag->name, NULL);
+		scope = g_strconcat(type_tag->scope, tm_parser_scope_separator(type_tag->lang), type_tag->name, NULL);
 	else
 		scope = g_strdup(type_tag->name);
 
@@ -785,7 +785,7 @@ static gchar *strip_type(const gchar *scoped_name, TMParserType lang)
 	if (scoped_name != NULL)
 	{
 		/* remove scope prefix */
-		const gchar *sep = tm_parser_context_separator(lang);
+		const gchar *sep = tm_parser_scope_separator(lang);
 		const gchar *base = g_strrstr(scoped_name, sep);
 		gchar *name = base ? g_strdup(base + strlen(sep)) : g_strdup(scoped_name);
 
@@ -881,7 +881,7 @@ find_scope_members (const GPtrArray *tags_array, const gchar *name, TMSourceFile
 static gboolean member_at_method_scope(const GPtrArray *tags, const gchar *method_scope, TMTag *member_tag,
 	TMParserType lang)
 {
-	const gchar *sep = tm_parser_context_separator(lang);
+	const gchar *sep = tm_parser_scope_separator(lang);
 	gboolean ret = FALSE;
 	gchar **comps;
 	guint len;



--------------
This E-Mail was brought to you by github_commit_mail.py (Source: https://github.com/geany/infrastructure).


More information about the Commits mailing list