Branch: refs/heads/master Author: Jiří Techet techet@gmail.com Committer: GitHub noreply@github.com Date: Fri, 11 Nov 2022 18:48:13 UTC Commit: f1c36655683ac727782e293054a4926d6040045c https://github.com/geany/geany/commit/f1c36655683ac727782e293054a4926d604004...
Log Message: ----------- Merge pull request #3269 from techee/autocomplete_header2
Sort autocompletion tags also based on their presence in included files
Modified Paths: -------------- src/symbols.c src/tagmanager/tm_parser.c src/tagmanager/tm_parser.h src/tagmanager/tm_workspace.c src/tagmanager/tm_workspace.h
Modified: src/symbols.c 2 lines changed, 1 insertions(+), 1 deletions(-) =================================================================== @@ -1136,7 +1136,7 @@ gboolean symbols_recreate_tag_list(GeanyDocument *doc, gint sort_mode)
g_return_val_if_fail(DOC_VALID(doc), FALSE);
- tags = get_tag_list(doc, ~tm_tag_local_var_t); + tags = get_tag_list(doc, ~(tm_tag_local_var_t | tm_tag_include_t)); if (tags == NULL) return FALSE;
Modified: src/tagmanager/tm_parser.c 4 lines changed, 2 insertions(+), 2 deletions(-) =================================================================== @@ -69,7 +69,7 @@ static GHashTable *subparser_map = NULL; {'u', tm_tag_union_t}, /* union */ \ {'v', tm_tag_variable_t}, /* variable */ \ {'x', tm_tag_externvar_t}, /* externvar */ \ - {'h', tm_tag_undef_t}, /* header */ \ + {'h', tm_tag_include_t}, /* header */ \ {'l', tm_tag_local_var_t}, /* local */ \ {'z', tm_tag_local_var_t}, /* parameter */ \ {'L', tm_tag_undef_t}, /* label */ \ @@ -81,7 +81,7 @@ static TMParserMapEntry map_C[] = { /* Used also by other languages than C - keep all the tm_tag_* here even though * they aren't used by C as they might be used by some other language */ static TMParserMapGroup group_C[] = { - {_("Namespaces"), TM_ICON_NAMESPACE, tm_tag_namespace_t | tm_tag_package_t}, + {_("Namespaces"), TM_ICON_NAMESPACE, tm_tag_namespace_t | tm_tag_package_t | tm_tag_include_t}, {_("Classes"), TM_ICON_CLASS, tm_tag_class_t}, {_("Interfaces"), TM_ICON_STRUCT, tm_tag_interface_t}, {_("Functions"), TM_ICON_METHOD, tm_tag_prototype_t | tm_tag_method_t | tm_tag_function_t},
Modified: src/tagmanager/tm_parser.h 3 lines changed, 2 insertions(+), 1 deletions(-) =================================================================== @@ -42,7 +42,8 @@ typedef enum tm_tag_macro_with_arg_t = 131072, /**< Parameterized macro */ tm_tag_local_var_t = 262144, /**< Local variable (inside function) */ tm_tag_other_t = 524288, /**< Other (non C/C++/Java tag) */ - tm_tag_max_t = 1048575 /**< Maximum value of TMTagType */ + tm_tag_include_t = 1048576, /**< C/C++ included header file name */ + tm_tag_max_t = 2097151 /**< Maximum value of TMTagType */ } TMTagType;
Modified: src/tagmanager/tm_workspace.c 199 lines changed, 184 insertions(+), 15 deletions(-) =================================================================== @@ -64,6 +64,12 @@ static TMTagType TM_GLOBAL_TYPE_MASK = static TMWorkspace *theWorkspace = NULL;
+static void free_ptr_array(gpointer arr) +{ + g_ptr_array_free(arr, TRUE); +} + + static gboolean tm_create_workspace(void) { theWorkspace = g_new(TMWorkspace, 1); @@ -73,6 +79,8 @@ static gboolean tm_create_workspace(void) theWorkspace->source_files = g_ptr_array_new(); theWorkspace->typename_array = g_ptr_array_new(); theWorkspace->global_typename_array = g_ptr_array_new(); + theWorkspace->source_file_map = g_hash_table_new_full(g_str_hash, g_str_equal, NULL, + free_ptr_array);
tm_ctags_init(); tm_parser_verify_type_mappings(); @@ -92,6 +100,7 @@ void tm_workspace_free(void) g_message("Workspace destroyed"); #endif
+ g_hash_table_destroy(theWorkspace->source_file_map); for (i=0; i < theWorkspace->source_files->len; ++i) tm_source_file_free(theWorkspace->source_files->pdata[i]); g_ptr_array_free(theWorkspace->source_files, TRUE); @@ -171,24 +180,34 @@ static void update_source_file(TMSourceFile *source_file, guchar* text_buf, }
-/** Adds a source file to the workspace, parses it and updates the workspace tags. - @param source_file The source file to add to the workspace. -*/ -GEANY_API_SYMBOL -void tm_workspace_add_source_file(TMSourceFile *source_file) +void tm_workspace_add_source_file_noupdate(TMSourceFile *source_file) { + GPtrArray *file_arr; + g_return_if_fail(source_file != NULL);
g_ptr_array_add(theWorkspace->source_files, source_file); - update_source_file(source_file, NULL, 0, FALSE, TRUE); + + file_arr = g_hash_table_lookup(theWorkspace->source_file_map, source_file->short_name); + if (!file_arr) + { + file_arr = g_ptr_array_new(); + g_hash_table_insert(theWorkspace->source_file_map, source_file->short_name, file_arr); + } + g_ptr_array_add(file_arr, source_file); }
-void tm_workspace_add_source_file_noupdate(TMSourceFile *source_file) +/** Adds a source file to the workspace, parses it and updates the workspace tags. + @param source_file The source file to add to the workspace. +*/ +GEANY_API_SYMBOL +void tm_workspace_add_source_file(TMSourceFile *source_file) { g_return_if_fail(source_file != NULL);
- g_ptr_array_add(theWorkspace->source_files, source_file); + tm_workspace_add_source_file_noupdate(source_file); + update_source_file(source_file, NULL, 0, FALSE, TRUE); }
@@ -211,6 +230,15 @@ void tm_workspace_update_source_file_buffer(TMSourceFile *source_file, guchar* t }
+static void remove_source_file_map(TMSourceFile *source_file) +{ + GPtrArray *file_arr = g_hash_table_lookup(theWorkspace->source_file_map, source_file->short_name); + + if (file_arr) + g_ptr_array_remove_fast(file_arr, source_file); +} + + /** Removes a source file from the workspace if it exists. This function also removes the tags belonging to this file from the workspace. To completely free the TMSourceFile pointer call tm_source_file_free() on it. @@ -229,6 +257,7 @@ void tm_workspace_remove_source_file(TMSourceFile *source_file) { tm_tags_remove_file_tags(source_file, theWorkspace->tags_array); tm_tags_remove_file_tags(source_file, theWorkspace->typename_array); + remove_source_file_map(source_file); g_ptr_array_remove_index_fast(theWorkspace->source_files, i); return; } @@ -326,6 +355,7 @@ void tm_workspace_remove_source_files(GPtrArray *source_files) { if (theWorkspace->source_files->pdata[j] == source_file) { + remove_source_file_map(source_file); g_ptr_array_remove_index_fast(theWorkspace->source_files, j); break; } @@ -510,7 +540,7 @@ static gboolean create_global_tags_preprocessed(const char *pre_process_cmd, }
tm_tags_sort(source_file->tags_array, global_tags_sort_attrs, TRUE, FALSE); - filtered_tags = tm_tags_extract(source_file->tags_array, ~tm_tag_local_var_t); + filtered_tags = tm_tags_extract(source_file->tags_array, ~(tm_tag_local_var_t | tm_tag_include_t)); ret = tm_source_file_write_tags_file(tags_file, filtered_tags); g_ptr_array_free(filtered_tags, TRUE); tm_source_file_free(source_file); @@ -543,7 +573,7 @@ static gboolean create_global_tags_direct(GList *source_files, const char *tags_ } }
- filtered_tags = tm_tags_extract(tags, ~tm_tag_local_var_t); + filtered_tags = tm_tags_extract(tags, ~(tm_tag_local_var_t | tm_tag_include_t)); tm_tags_sort(filtered_tags, global_tags_sort_attrs, TRUE, FALSE);
if (filtered_tags->len > 0) @@ -646,13 +676,41 @@ gboolean tm_workspace_is_autocomplete_tag(TMTag *tag, gboolean valid_local = !tag->local || current_file == tag->file;
return valid && valid_local && - !tm_tag_is_anon(tag) && tm_parser_langs_compatible(lang, tag->lang); + !tm_tag_is_anon(tag) && tm_parser_langs_compatible(lang, tag->lang) && + !(tag->type & tm_tag_include_t); }
+#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; @@ -672,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); }
@@ -725,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); @@ -742,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;
@@ -755,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) @@ -768,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) @@ -793,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; }
@@ -1227,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 @@ -1243,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)
Modified: src/tagmanager/tm_workspace.h 1 lines changed, 1 insertions(+), 0 deletions(-) =================================================================== @@ -32,6 +32,7 @@ typedef struct TMWorkspace (just pointers to source file tags, the tag objects are owned by the source files). @elementtype{TMTag} */ GPtrArray *typename_array; /* Typename tags for syntax highlighting (pointers owned by source files) */ GPtrArray *global_typename_array; /* Like above for global tags */ + GHashTable *source_file_map; /* File name -> GPtrArray<TMSourceFile> map to speed up lookups based on file name */ } TMWorkspace;
-------------- This E-Mail was brought to you by github_commit_mail.py (Source: https://github.com/geany/infrastructure).