Branch: refs/heads/master Author: Enrico Tröger enrico.troeger@uvena.de Committer: GitHub noreply@github.com Date: Sun, 23 Jan 2022 23:06:51 UTC Commit: 5a369a41e3cb6fd1bc57e602fa567e8c0d153bfc https://github.com/geany/geany/commit/5a369a41e3cb6fd1bc57e602fa567e8c0d153b...
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).