Branch: refs/heads/master Author: Jiří Techet techet@gmail.com Committer: Jiří Techet techet@gmail.com Date: Thu, 03 Nov 2022 22:43:38 UTC Commit: 151bf64384799ed0f13b74ee7617460ac11dd430 https://github.com/geany/geany/commit/151bf64384799ed0f13b74ee7617460ac11dd4...
Log Message: ----------- Sort autocompletion tags also based on their presence in included files
This patch extends the current sorting of the tags which looks this way:
- sort local vars first (with highest line number first), - followed by tags from current file, - followed by workspace tags, - followed by global tags
by two new entries so it looks this way:
- sort local vars first (with highest line number first), - followed by tags from current file, - NEW: followed by tags from header, - NEW: followed by tags from other included files, - followed by workspace tags, - followed by global tags
Sorting tags from included files seems to be a natural heuristic as users explicitly included these and want their symbols to be present in the current file. As a special case, symbols from the header of the current source file (included file with the same base name as the current file) are listed in front of symbols from other included files as headers tend to be tightly coupled with corresponding source files in C/C++.
Modified Paths: -------------- src/tagmanager/tm_workspace.c
Modified: src/tagmanager/tm_workspace.c 146 lines changed, 142 insertions(+), 4 deletions(-) =================================================================== @@ -681,9 +681,36 @@ gboolean tm_workspace_is_autocomplete_tag(TMTag *tag, }
+#if ! GLIB_CHECK_VERSION(2, 54, 0) +static gboolean +g_ptr_array_find (GPtrArray *haystack, + gconstpointer needle, + guint *index_) +{ + guint i; + + g_return_val_if_fail (haystack != NULL, FALSE); + + for (i = 0; i < haystack->len; i++) + { + if (g_direct_equal (g_ptr_array_index (haystack, i), needle)) + { + if (index_ != NULL) + *index_ = i; + return TRUE; + } + } + + return FALSE; +} +#endif + + typedef struct { TMSourceFile *file; + GPtrArray *header_candidates; + GHashTable *includes; guint line; const gchar *scope; } CopyInfo; @@ -703,10 +730,12 @@ static gboolean is_non_local_tag(TMTag *tag, CopyInfo *info) return !is_local_tag(tag, info); }
-/* non-local tag not from current file */ +/* non-local tag not from current file, header, or included files */ static gboolean is_workspace_tag(TMTag *tag, CopyInfo *info) { return tag->file != info->file && + (!info->header_candidates || !g_ptr_array_find(info->header_candidates, tag->file, NULL)) && + !g_hash_table_lookup(info->includes, tag->file) && is_non_local_tag(tag, info); }
@@ -756,6 +785,32 @@ static void fill_find_tags_array_prefix(GPtrArray *dst, const char *name, copy_tags(dst, found, count, name_table, max_num - dst->len, is_non_local_tag, info); } } + if (dst->len < max_num && info->header_candidates) + { + guint i; + + for (i = 0; i < info->header_candidates->len; i++) + { + TMSourceFile *hdr = info->header_candidates->pdata[i]; + found = tm_tags_find(hdr->tags_array, name, TRUE, &count); + if (found) + copy_tags(dst, found, count, name_table, max_num - dst->len, is_non_local_tag, info); + } + } + if (dst->len < max_num) + { + GHashTableIter iter; + gpointer key; + + g_hash_table_iter_init(&iter, info->includes); + while (g_hash_table_iter_next(&iter, &key, NULL)) + { + TMSourceFile *include_file = key; + found = tm_tags_find(include_file->tags_array, name, TRUE, &count); + if (found) + copy_tags(dst, found, count, name_table, max_num - dst->len, is_non_local_tag, info); + } + } if (dst->len < max_num) { found = tm_tags_find(theWorkspace->tags_array, name, TRUE, &count); @@ -773,9 +828,67 @@ static void fill_find_tags_array_prefix(GPtrArray *dst, const char *name, }
+/* return TMSourceFile files corresponding to files included in 'source'; + * in addition, fill header_candidates with TMSourceFiles that could be the header + * of 'source' based on the file name */ +static GHashTable *get_includes(TMSourceFile *source, GPtrArray **header_candidates) +{ + GHashTable *includes = g_hash_table_new(NULL, NULL); + GPtrArray *headers; + gchar *src_basename, *ptr; + guint i; + + *header_candidates = NULL; + + if (!source || + (source->lang != TM_PARSER_C && source->lang != TM_PARSER_CPP)) + return includes; + + src_basename = g_strdup(source->short_name); + if (ptr = strrchr(src_basename, '.')) + *ptr = '\0'; + + headers = tm_tags_extract(source->tags_array, tm_tag_include_t); + + for (i = 0; i < headers->len; i++) + { + TMTag *hdr_tag = headers->pdata[i]; + gchar *hdr_name = g_path_get_basename(hdr_tag->name); + GPtrArray *tm_files = g_hash_table_lookup(theWorkspace->source_file_map, hdr_name); + + if (tm_files && tm_files->len > 0) + { + guint j; + + if (!*header_candidates) + { + gchar *hdr_basename = g_strdup(hdr_name); + if (ptr = strrchr(hdr_basename, '.')) + *ptr = '\0'; + + if (g_strcmp0(hdr_basename, src_basename) == 0) + *header_candidates = tm_files; + g_free(hdr_basename); + } + + for (j = 0; j < tm_files->len; j++) + g_hash_table_add(includes, tm_files->pdata[j]); + } + + g_free(hdr_name); + } + + g_ptr_array_free(headers, TRUE); + g_free(src_basename); + return includes; +} + + typedef struct { TMSourceFile *file; + GPtrArray *header_candidates; + GHashTable *includes; gboolean sort_by_name; } SortInfo;
@@ -786,9 +899,12 @@ static gint sort_found_tags(gconstpointer a, gconstpointer b, gpointer user_data const TMTag *t1 = *((TMTag **) a); const TMTag *t2 = *((TMTag **) b);
- /* sort local vars first (with highest line number first), followed - * by tags from current file, followed by workspace tags, followed by - * global tags */ + /* sort local vars first (with highest line number first), + * followed by tags from current file, + * followed by tags from header, + * followed by tags from other included files, + * followed by workspace tags, + * followed by global tags */ if (t1->type & tm_tag_local_var_t && t2->type & tm_tag_local_var_t) return info->sort_by_name ? g_strcmp0(t1->name, t2->name) : t2->line - t1->line; else if (t1->type & tm_tag_local_var_t) @@ -799,6 +915,18 @@ static gint sort_found_tags(gconstpointer a, gconstpointer b, gpointer user_data return -1; else if (t2->file == info->file && t1->file != info->file) return 1; + else if (info->header_candidates && + g_ptr_array_find(info->header_candidates, t1->file, NULL) && + !g_ptr_array_find(info->header_candidates, t2->file, NULL)) + return -1; + else if (info->header_candidates && + g_ptr_array_find(info->header_candidates, t2->file, NULL) && + !g_ptr_array_find(info->header_candidates, t1->file, NULL)) + return 1; + else if (g_hash_table_lookup(info->includes, t1->file) && !g_hash_table_lookup(info->includes, t2->file)) + return -1; + else if (g_hash_table_lookup(info->includes, t2->file) && !g_hash_table_lookup(info->includes, t1->file)) + return 1; else if (t1->file && !t2->file) return -1; else if (t2->file && !t1->file) @@ -824,20 +952,28 @@ GPtrArray *tm_workspace_find_prefix(const char *prefix, { TMTagAttrType attrs[] = { tm_tag_attr_name_t, 0 }; GPtrArray *tags = g_ptr_array_new(); + GPtrArray *header_candidates; SortInfo sort_info; CopyInfo copy_info; + GHashTable *includes = get_includes(current_file, &header_candidates);
copy_info.file = current_file; + copy_info.header_candidates = header_candidates; + copy_info.includes = includes; copy_info.line = current_line; copy_info.scope = current_scope; fill_find_tags_array_prefix(tags, prefix, ©_info, max_num);
/* sort based on how "close" the tag is to current line with local * variables first */ sort_info.file = current_file; + sort_info.header_candidates = header_candidates; + sort_info.includes = includes; sort_info.sort_by_name = TRUE; g_ptr_array_sort_with_data(tags, sort_found_tags, &sort_info);
+ g_hash_table_destroy(includes); + return tags; }
@@ -1258,6 +1394,7 @@ tm_workspace_find_scope_members (TMSourceFile *source_file, const char *name,
info.file = source_file; info.sort_by_name = FALSE; + info.includes = get_includes(source_file, &info.header_candidates); g_ptr_array_sort_with_data(tags, sort_found_tags, &info);
/* Start searching inside the source file, continue with workspace tags and @@ -1274,6 +1411,7 @@ tm_workspace_find_scope_members (TMSourceFile *source_file, const char *name, member, current_scope);
g_ptr_array_free(tags, TRUE); + g_hash_table_destroy(info.includes); }
if (member_tags)
-------------- This E-Mail was brought to you by github_commit_mail.py (Source: https://github.com/geany/infrastructure).