Branch: refs/heads/master Author: Colomban Wendling ban@herbesfolles.org Committer: Colomban Wendling ban@herbesfolles.org Date: Thu, 21 Dec 2017 00:34:41 UTC Commit: 69a537dbd05d9bb25dfc4a63badfa1aa4cf94e92 https://github.com/geany/geany/commit/69a537dbd05d9bb25dfc4a63badfa1aa4cf94e...
Log Message: ----------- Merge pull request #1598 from b4n/symbols/more-robust-hierarchy
Fix the symbols tree hierarchy when several tags have the same name
Modified Paths: -------------- HACKING src/editor.c src/symbols.c src/tagmanager/tm_parser.c src/tagmanager/tm_parser.h src/tagmanager/tm_tag.c src/tagmanager/tm_tag.h src/tagmanager/tm_workspace.c
Modified: HACKING 6 lines changed, 5 insertions(+), 1 deletions(-) =================================================================== @@ -667,12 +667,16 @@ Method * Add TM_PARSER_FOO to src/tagmanager/tm_parser.h. The list here must follow exactly the order in parsers.h.
-In tagmanager/src/tm_parsers.c: +In src/tagmanager/tm_parser.c: Add a map_FOO TMParserMapEntry mapping each kind's letter from foo.c's FooKinds to the appropriate TMTagType, and add the corresponding 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 +handle the new parser if applicable, by adding a TM_PARSER_FOO case entry. + In filetypes.c, init_builtin_filetypes(): Set the 2nd argument of the FT_INIT() macro for this filetype to FOO.
Modified: src/editor.c 2 lines changed, 1 insertions(+), 1 deletions(-) =================================================================== @@ -706,7 +706,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_tag_context_separator(ft->lang); + const gchar *context_sep = tm_parser_context_separator(ft->lang);
if (autocomplete_scope_shown) {
Modified: src/symbols.c 86 lines changed, 46 insertions(+), 40 deletions(-) =================================================================== @@ -229,7 +229,7 @@ GString *symbols_find_typenames_as_string(TMParserType lang, gboolean global) tag = TM_TAG(typedefs->pdata[j]); tag_lang = tag->lang;
- if (tag->name && tm_tag_langs_compatible(lang, tag_lang) && + if (tag->name && tm_parser_langs_compatible(lang, tag_lang) && strcmp(tag->name, last_name) != 0) { if (j != 0) @@ -256,7 +256,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_tag_context_separator(filetypes[ft_id]->lang); + return tm_parser_context_separator(filetypes[ft_id]->lang); }
@@ -922,30 +922,9 @@ static gchar *get_symbol_tooltip(GeanyDocument *doc, const TMTag *tag) }
-/* find the last word in "foo::bar::blah", e.g. "blah" */ -static const gchar *get_parent_name(const TMTag *tag, GeanyFiletypeID ft_id) +static const gchar *get_parent_name(const TMTag *tag) { - const gchar *scope = tag->scope; - const gchar *separator = symbols_get_context_separator(ft_id); - const gchar *str, *ptr; - - if (!scope) - return NULL; - - str = scope; - - while (1) - { - ptr = strstr(str, separator); - if (ptr) - { - str = ptr + strlen(separator); - } - else - break; - } - - return !EMPTY(str) ? str : NULL; + return !EMPTY(tag->scope) ? tag->scope : NULL; }
@@ -1147,21 +1126,46 @@ static void parents_table_tree_value_free(gpointer data)
/* adds a new element in the parent table if its key is known. */ -static void update_parents_table(GHashTable *table, const TMTag *tag, const gchar *parent_name, - const GtkTreeIter *iter) +static void update_parents_table(GHashTable *table, const TMTag *tag, const GtkTreeIter *iter) { + const gchar *name; + gchar *name_free = NULL; GTree *tree; - if (g_hash_table_lookup_extended(table, tag->name, NULL, (gpointer *) &tree) && - ! utils_str_equal(parent_name, tag->name) /* prevent Foo::Foo from making parent = child */) + + if (EMPTY(tag->scope)) + { + /* simple case, just use the tag name */ + name = tag->name; + } + else if (! tm_parser_has_full_context(tag->lang)) + { + /* if the parser doesn't use fully qualified scope, use the name alone but + * prevent Foo::Foo from making parent = child */ + if (utils_str_equal(tag->scope, tag->name)) + name = NULL; + else + name = tag->name; + } + 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 = name_free; + } + + if (name && g_hash_table_lookup_extended(table, name, NULL, (gpointer *) &tree)) { if (!tree) { tree = g_tree_new_full(tree_cmp, NULL, NULL, parents_table_tree_value_free); - g_hash_table_insert(table, tag->name, tree); + g_hash_table_insert(table, name_free ? name_free : g_strdup(name), tree); + name_free = NULL; }
g_tree_insert(tree, GINT_TO_POINTER(tag->line), g_slice_dup(GtkTreeIter, iter)); } + + g_free(name_free); }
@@ -1313,21 +1317,23 @@ static void update_tree_tags(GeanyDocument *doc, GList **tags) GList *item;
/* Build hash tables holding tags and parents */ - /* parent table is GHashTable<tag_name, GTree<line_num, GtkTreeIter>> */ - parents_table = g_hash_table_new_full(g_str_hash, g_str_equal, NULL, parents_table_value_free); + /* 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()). */ + 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>>>> */ tags_table = g_hash_table_new_full(tag_hash, tag_equal, NULL, tags_table_value_free); foreach_list(item, *tags) { TMTag *tag = item->data; - const gchar *name; + const gchar *parent_name;
tags_table_insert(tags_table, tag, item);
- name = get_parent_name(tag, doc->file_type->id); - if (name) - g_hash_table_insert(parents_table, (gpointer) name, NULL); + parent_name = get_parent_name(tag); + if (parent_name) + g_hash_table_insert(parents_table, g_strdup(parent_name), NULL); }
/* First pass, update existing rows or delete them. @@ -1354,7 +1360,7 @@ static void update_tree_tags(GeanyDocument *doc, GList **tags) const gchar *parent_name; TMTag *found = found_item->data;
- parent_name = get_parent_name(found, doc->file_type->id); + parent_name = get_parent_name(found); /* if parent is unknown, ignore it */ if (parent_name && ! g_hash_table_lookup(parents_table, parent_name)) parent_name = NULL; @@ -1376,7 +1382,7 @@ static void update_tree_tags(GeanyDocument *doc, GList **tags) g_free(tooltip); }
- update_parents_table(parents_table, found, parent_name, &iter); + update_parents_table(parents_table, found, &iter);
/* remove the updated tag from the table and list */ tags_table_remove(tags_table, found); @@ -1407,7 +1413,7 @@ static void update_tree_tags(GeanyDocument *doc, GList **tags) gchar *tooltip; GdkPixbuf *icon = get_child_icon(store, parent);
- parent_name = get_parent_name(tag, doc->file_type->id); + parent_name = get_parent_name(tag); if (parent_name) { GtkTreeIter *parent_search = parents_table_lookup(parents_table, parent_name, tag->line); @@ -1435,7 +1441,7 @@ static void update_tree_tags(GeanyDocument *doc, GList **tags) if (G_LIKELY(icon)) g_object_unref(icon);
- update_parents_table(parents_table, tag, parent_name, &iter); + update_parents_table(parents_table, tag, &iter);
if (expand) tree_view_expand_to_iter(GTK_TREE_VIEW(doc->priv->tag_tree), &iter);
Modified: src/tagmanager/tm_parser.c 88 lines changed, 88 insertions(+), 0 deletions(-) =================================================================== @@ -650,3 +650,91 @@ void tm_parser_verify_type_mappings(void) } } } + + +const gchar *tm_parser_context_separator(TMParserType lang) +{ + switch (lang) + { + case TM_PARSER_C: /* for C++ .h headers or C structs */ + case TM_PARSER_CPP: + case TM_PARSER_GLSL: /* for structs */ + /*case GEANY_FILETYPES_RUBY:*/ /* not sure what to use atm*/ + case TM_PARSER_PHP: + case TM_PARSER_POWERSHELL: + case TM_PARSER_RUST: + case TM_PARSER_ZEPHIR: + return "::"; + + /* avoid confusion with other possible separators in group/section name */ + case TM_PARSER_CONF: + case TM_PARSER_REST: + return ":::"; + + /* no context separator */ + case TM_PARSER_ASCIIDOC: + case TM_PARSER_TXT2TAGS: + return "\x03"; + + default: + return "."; + } +} + + +gboolean tm_parser_has_full_context(TMParserType lang) +{ + switch (lang) + { + /* These parsers include full hierarchy in the tag scope, separated by tm_parser_context_separator() */ + case TM_PARSER_C: + case TM_PARSER_CPP: + case TM_PARSER_CSHARP: + case TM_PARSER_D: + case TM_PARSER_FERITE: + case TM_PARSER_GLSL: + case TM_PARSER_JAVA: + case TM_PARSER_JAVASCRIPT: + case TM_PARSER_JSON: + case TM_PARSER_PHP: + case TM_PARSER_POWERSHELL: + case TM_PARSER_PYTHON: + case TM_PARSER_RUBY: + case TM_PARSER_RUST: + case TM_PARSER_SQL: + case TM_PARSER_TXT2TAGS: + case TM_PARSER_VALA: + case TM_PARSER_ZEPHIR: + return TRUE; + + /* These make use of the scope, but don't include nested hierarchy + * (either as a parser limitation or a language semantic) */ + case TM_PARSER_ASCIIDOC: + case TM_PARSER_CONF: + case TM_PARSER_ERLANG: + case TM_PARSER_F77: + case TM_PARSER_FORTRAN: + case TM_PARSER_GO: + case TM_PARSER_OBJC: + case TM_PARSER_REST: + /* Other parsers don't use scope at all (or should be somewhere above) */ + default: + return FALSE; + } +} + + +gboolean tm_parser_langs_compatible(TMParserType lang, TMParserType other) +{ + if (lang == TM_PARSER_NONE || other == TM_PARSER_NONE) + return FALSE; + if (lang == other) + return TRUE; + /* Accept CPP tags for C lang and vice versa */ + else if (lang == TM_PARSER_C && other == TM_PARSER_CPP) + return TRUE; + else if (lang == TM_PARSER_CPP && other == TM_PARSER_C) + return TRUE; + + return FALSE; +}
Modified: src/tagmanager/tm_parser.h 6 lines changed, 6 insertions(+), 0 deletions(-) =================================================================== @@ -119,6 +119,12 @@ TMTagType tm_parser_get_tag_type(gchar kind, TMParserType lang);
gchar tm_parser_get_tag_kind(TMTagType type, TMParserType lang);
+const gchar *tm_parser_context_separator(TMParserType lang); + +gboolean tm_parser_has_full_context(TMParserType lang); + +gboolean tm_parser_langs_compatible(TMParserType lang, TMParserType other); + #endif /* GEANY_PRIVATE */
G_END_DECLS
Modified: src/tagmanager/tm_tag.c 47 lines changed, 1 insertions(+), 46 deletions(-) =================================================================== @@ -664,35 +664,6 @@ tm_get_current_tag (GPtrArray * file_tags, const gulong line, const TMTagType ta return matching_tag; }
-const gchar *tm_tag_context_separator(TMParserType lang) -{ - switch (lang) - { - case TM_PARSER_C: /* for C++ .h headers or C structs */ - case TM_PARSER_CPP: - case TM_PARSER_GLSL: /* for structs */ - /*case GEANY_FILETYPES_RUBY:*/ /* not sure what to use atm*/ - case TM_PARSER_PHP: - case TM_PARSER_POWERSHELL: - case TM_PARSER_RUST: - case TM_PARSER_ZEPHIR: - return "::"; - - /* avoid confusion with other possible separators in group/section name */ - case TM_PARSER_CONF: - case TM_PARSER_REST: - return ":::"; - - /* no context separator */ - case TM_PARSER_ASCIIDOC: - case TM_PARSER_TXT2TAGS: - return "\x03"; - - default: - return "."; - } -} - gboolean tm_tag_is_anon(const TMTag *tag) { guint i; @@ -708,22 +679,6 @@ gboolean tm_tag_is_anon(const TMTag *tag) }
-gboolean tm_tag_langs_compatible(TMParserType lang, TMParserType other) -{ - if (lang == TM_PARSER_NONE || other == TM_PARSER_NONE) - return FALSE; - if (lang == other) - return TRUE; - /* Accept CPP tags for C lang and vice versa */ - else if (lang == TM_PARSER_C && other == TM_PARSER_CPP) - return TRUE; - else if (lang == TM_PARSER_CPP && other == TM_PARSER_C) - return TRUE; - - return FALSE; -} - - #ifdef TM_DEBUG /* various debugging functions */
/* @@ -825,7 +780,7 @@ void tm_tags_array_print(GPtrArray *tags, FILE *fp) */ gint tm_tag_scope_depth(const TMTag *t) { - const gchar *context_sep = tm_tag_context_separator(t->lang); + const gchar *context_sep = tm_parser_context_separator(t->lang); gint depth; char *s; if(!(t && t->scope))
Modified: src/tagmanager/tm_tag.h 4 lines changed, 0 insertions(+), 4 deletions(-) =================================================================== @@ -139,12 +139,8 @@ TMTag *tm_tag_ref(TMTag *tag);
gboolean tm_tags_equal(const TMTag *a, const TMTag *b);
-const gchar *tm_tag_context_separator(TMParserType lang); - gboolean tm_tag_is_anon(const TMTag *tag);
-gboolean tm_tag_langs_compatible(TMParserType lang, TMParserType other); - #ifdef TM_DEBUG /* various debugging functions */
const char *tm_tag_type_name(const TMTag *tag);
Modified: src/tagmanager/tm_workspace.c 12 lines changed, 6 insertions(+), 6 deletions(-) =================================================================== @@ -675,7 +675,7 @@ static void fill_find_tags_array(GPtrArray *dst, const GPtrArray *src, for (i = 0; i < num; ++i) { if ((type & (*tag)->type) && - tm_tag_langs_compatible(lang, (*tag)->lang) && + tm_parser_langs_compatible(lang, (*tag)->lang) && (!scope || g_strcmp0((*tag)->scope, scope) == 0)) { g_ptr_array_add(dst, *tag); @@ -722,7 +722,7 @@ static void fill_find_tags_array_prefix(GPtrArray *dst, const GPtrArray *src, tag = tm_tags_find(src, name, TRUE, &count); for (i = 0; i < count && num < max_num; ++i) { - if (tm_tag_langs_compatible(lang, (*tag)->lang) && + if (tm_parser_langs_compatible(lang, (*tag)->lang) && !tm_tag_is_anon(*tag) && (!last || g_strcmp0(last->name, (*tag)->name) != 0)) { @@ -778,7 +778,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_tag_context_separator(type_tag->lang), type_tag->name, NULL); + scope = g_strconcat(type_tag->scope, tm_parser_context_separator(type_tag->lang), type_tag->name, NULL); else scope = g_strdup(type_tag->name);
@@ -788,7 +788,7 @@ find_scope_members_tags (const GPtrArray *all, TMTag *type_tag, gboolean namespa
if (tag && (tag->type & member_types) && tag->scope && tag->scope[0] != '\0' && - tm_tag_langs_compatible(tag->lang, type_tag->lang) && + tm_parser_langs_compatible(tag->lang, type_tag->lang) && strcmp(scope, tag->scope) == 0 && (!namespace || !tm_tag_is_anon(tag))) { @@ -813,7 +813,7 @@ static gchar *strip_type(const gchar *scoped_name, TMParserType lang) if (scoped_name != NULL) { /* remove scope prefix */ - const gchar *sep = tm_tag_context_separator(lang); + const gchar *sep = tm_parser_context_separator(lang); const gchar *base = g_strrstr(scoped_name, sep); gchar *name = base ? g_strdup(base + strlen(sep)) : g_strdup(scoped_name);
@@ -909,7 +909,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_tag_context_separator(lang); + const gchar *sep = tm_parser_context_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).