3 * Copyright (c) 2001-2002, Biswapesh Chattopadhyay
4 * Copyright 2005 The Geany contributors
6 * This source code is released for free distribution under the terms of the
7 * GNU General Public License.
12 * @file tm_workspace.h
13 The TMWorkspace structure is meant to be used as a singleton to store application
16 The workspace is intended to contain a list of global tags
17 and a set of individual source files.
24 #include <sys/types.h>
27 #include <glib/gstdio.h>
29 #include "tm_workspace.h"
32 #include "tm_parser.h"
35 /* when changing, always keep the three sort criteria below in sync */
36 static TMTagAttrType workspace_tags_sort_attrs
[] =
38 tm_tag_attr_name_t
, tm_tag_attr_file_t
, tm_tag_attr_line_t
,
39 tm_tag_attr_type_t
, tm_tag_attr_scope_t
, tm_tag_attr_arglist_t
, 0
42 /* for file tags the file is always identical, don't use for sorting */
43 static TMTagAttrType file_tags_sort_attrs
[] =
45 tm_tag_attr_name_t
, tm_tag_attr_line_t
,
46 tm_tag_attr_type_t
, tm_tag_attr_scope_t
, tm_tag_attr_arglist_t
, 0
49 /* global tags don't have file/line information */
50 static TMTagAttrType global_tags_sort_attrs
[] =
53 tm_tag_attr_type_t
, tm_tag_attr_scope_t
, tm_tag_attr_arglist_t
, 0
56 static TMTagType TM_TYPE_WITH_MEMBERS
=
57 tm_tag_class_t
| tm_tag_struct_t
| tm_tag_union_t
|
58 tm_tag_enum_t
| tm_tag_interface_t
;
60 static TMTagType TM_GLOBAL_TYPE_MASK
=
61 tm_tag_class_t
| tm_tag_enum_t
| tm_tag_interface_t
|
62 tm_tag_struct_t
| tm_tag_typedef_t
| tm_tag_union_t
| tm_tag_namespace_t
;
64 static TMWorkspace
*theWorkspace
= NULL
;
67 static gboolean
tm_create_workspace(void)
69 theWorkspace
= g_new(TMWorkspace
, 1);
70 theWorkspace
->tags_array
= g_ptr_array_new();
72 theWorkspace
->global_tags
= g_ptr_array_new();
73 theWorkspace
->source_files
= g_ptr_array_new();
74 theWorkspace
->typename_array
= g_ptr_array_new();
75 theWorkspace
->global_typename_array
= g_ptr_array_new();
78 tm_parser_verify_type_mappings();
84 /* Frees the workspace structure and all child source files. Use only when
85 exiting from the main program.
87 void tm_workspace_free(void)
92 g_message("Workspace destroyed");
95 for (i
=0; i
< theWorkspace
->source_files
->len
; ++i
)
96 tm_source_file_free(theWorkspace
->source_files
->pdata
[i
]);
97 g_ptr_array_free(theWorkspace
->source_files
, TRUE
);
98 tm_tags_array_free(theWorkspace
->global_tags
, TRUE
);
99 g_ptr_array_free(theWorkspace
->tags_array
, TRUE
);
100 g_ptr_array_free(theWorkspace
->typename_array
, TRUE
);
101 g_ptr_array_free(theWorkspace
->global_typename_array
, TRUE
);
102 g_free(theWorkspace
);
107 /* Since TMWorkspace is a singleton, you should not create multiple
108 workspaces, but get a pointer to the workspace whenever required. The first
109 time a pointer is requested, or a source file is added to the workspace,
110 a workspace is created. Subsequent calls to the function will return the
113 const TMWorkspace
*tm_get_workspace(void)
115 if (NULL
== theWorkspace
)
116 tm_create_workspace();
121 static void tm_workspace_merge_tags(GPtrArray
**big_array
, GPtrArray
*small_array
)
123 GPtrArray
*new_tags
= tm_tags_merge(*big_array
, small_array
, workspace_tags_sort_attrs
, FALSE
);
124 /* tags owned by TMSourceFile - free just the pointer array */
125 g_ptr_array_free(*big_array
, TRUE
);
126 *big_array
= new_tags
;
130 static void merge_extracted_tags(GPtrArray
**dest
, GPtrArray
*src
, TMTagType tag_types
)
134 arr
= tm_tags_extract(src
, tag_types
);
135 tm_workspace_merge_tags(dest
, arr
);
136 g_ptr_array_free(arr
, TRUE
);
140 static void update_source_file(TMSourceFile
*source_file
, guchar
* text_buf
,
141 gsize buf_size
, gboolean use_buffer
, gboolean update_workspace
)
144 g_message("Source file updating based on source file %s", source_file
->file_name
);
147 if (update_workspace
)
149 /* tm_source_file_parse() deletes the tag objects - remove the tags from
150 * workspace while they exist and can be scanned */
151 tm_tags_remove_file_tags(source_file
, theWorkspace
->tags_array
);
152 tm_tags_remove_file_tags(source_file
, theWorkspace
->typename_array
);
154 tm_source_file_parse(source_file
, text_buf
, buf_size
, use_buffer
);
155 tm_tags_sort(source_file
->tags_array
, file_tags_sort_attrs
, FALSE
, TRUE
);
156 if (update_workspace
)
159 g_message("Updating workspace from source file");
161 tm_workspace_merge_tags(&theWorkspace
->tags_array
, source_file
->tags_array
);
163 merge_extracted_tags(&(theWorkspace
->typename_array
), source_file
->tags_array
, TM_GLOBAL_TYPE_MASK
);
167 g_message("Skipping workspace update because update_workspace is %s",
168 update_workspace
?"TRUE":"FALSE");
174 /** Adds a source file to the workspace, parses it and updates the workspace tags.
175 @param source_file The source file to add to the workspace.
178 void tm_workspace_add_source_file(TMSourceFile
*source_file
)
180 g_return_if_fail(source_file
!= NULL
);
182 g_ptr_array_add(theWorkspace
->source_files
, source_file
);
183 update_source_file(source_file
, NULL
, 0, FALSE
, TRUE
);
187 void tm_workspace_add_source_file_noupdate(TMSourceFile
*source_file
)
189 g_return_if_fail(source_file
!= NULL
);
191 g_ptr_array_add(theWorkspace
->source_files
, source_file
);
195 /* Updates the source file by reparsing the text-buffer passed as parameter.
196 Ctags will use a parsing based on buffer instead of on files.
197 You should call this function when you don't want a previous saving of the file
198 you're editing. It's useful for a "real-time" updating of the tags.
199 The tags array and the tags themselves are destroyed and re-created, hence any
200 other tag arrays pointing to these tags should be rebuilt as well. All sorting
201 information is also lost.
202 @param source_file The source file to update with a buffer.
203 @param text_buf A text buffer. The user should take care of allocate and free it after
205 @param buf_size The size of text_buf.
207 void tm_workspace_update_source_file_buffer(TMSourceFile
*source_file
, guchar
* text_buf
,
210 update_source_file(source_file
, text_buf
, buf_size
, TRUE
, TRUE
);
214 /** Removes a source file from the workspace if it exists. This function also removes
215 the tags belonging to this file from the workspace. To completely free the TMSourceFile
216 pointer call tm_source_file_free() on it.
217 @param source_file Pointer to the source file to be removed.
220 void tm_workspace_remove_source_file(TMSourceFile
*source_file
)
224 g_return_if_fail(source_file
!= NULL
);
226 for (i
=0; i
< theWorkspace
->source_files
->len
; ++i
)
228 if (theWorkspace
->source_files
->pdata
[i
] == source_file
)
230 tm_tags_remove_file_tags(source_file
, theWorkspace
->tags_array
);
231 tm_tags_remove_file_tags(source_file
, theWorkspace
->typename_array
);
232 g_ptr_array_remove_index_fast(theWorkspace
->source_files
, i
);
239 /* Recreates workspace tag array from all member TMSourceFile objects. Use if you
240 want to globally refresh the workspace. This function does not call tm_source_file_update()
241 which should be called before this function on source files which need to be
244 static void tm_workspace_update(void)
247 TMSourceFile
*source_file
;
250 g_message("Recreating workspace tags array");
253 g_ptr_array_set_size(theWorkspace
->tags_array
, 0);
256 g_message("Total %d objects", theWorkspace
->source_files
->len
);
258 for (i
=0; i
< theWorkspace
->source_files
->len
; ++i
)
260 source_file
= theWorkspace
->source_files
->pdata
[i
];
262 g_message("Adding tags of %s", source_file
->file_name
);
264 if (source_file
->tags_array
->len
> 0)
266 for (j
= 0; j
< source_file
->tags_array
->len
; ++j
)
268 g_ptr_array_add(theWorkspace
->tags_array
,
269 source_file
->tags_array
->pdata
[j
]);
274 g_message("Total: %d tags", theWorkspace
->tags_array
->len
);
276 tm_tags_sort(theWorkspace
->tags_array
, workspace_tags_sort_attrs
, TRUE
, FALSE
);
278 g_ptr_array_free(theWorkspace
->typename_array
, TRUE
);
279 theWorkspace
->typename_array
= tm_tags_extract(theWorkspace
->tags_array
, TM_GLOBAL_TYPE_MASK
);
283 /** Adds multiple source files to the workspace and updates the workspace tag arrays.
284 This is more efficient than calling tm_workspace_add_source_file() and
285 tm_workspace_update_source_file() separately for each of the files.
286 @param source_files @elementtype{TMSourceFile} The source files to be added to the workspace.
289 void tm_workspace_add_source_files(GPtrArray
*source_files
)
293 g_return_if_fail(source_files
!= NULL
);
295 for (i
= 0; i
< source_files
->len
; i
++)
297 TMSourceFile
*source_file
= source_files
->pdata
[i
];
299 tm_workspace_add_source_file_noupdate(source_file
);
300 update_source_file(source_file
, NULL
, 0, FALSE
, FALSE
);
303 tm_workspace_update();
307 /** Removes multiple source files from the workspace and updates the workspace tag
308 arrays. This is more efficient than calling tm_workspace_remove_source_file()
309 separately for each of the files. To completely free the TMSourceFile pointers
310 call tm_source_file_free() on each of them.
311 @param source_files @elementtype{TMSourceFile} The source files to be removed from the workspace.
314 void tm_workspace_remove_source_files(GPtrArray
*source_files
)
318 g_return_if_fail(source_files
!= NULL
);
320 //TODO: sort both arrays by pointer value and remove in single pass
321 for (i
= 0; i
< source_files
->len
; i
++)
323 TMSourceFile
*source_file
= source_files
->pdata
[i
];
325 for (j
= 0; j
< theWorkspace
->source_files
->len
; j
++)
327 if (theWorkspace
->source_files
->pdata
[j
] == source_file
)
329 g_ptr_array_remove_index_fast(theWorkspace
->source_files
, j
);
335 tm_workspace_update();
339 /* Loads the global tag list from the specified file. The global tag list should
340 have been first created using tm_workspace_create_global_tags().
341 @param tags_file The file containing global tags.
342 @return TRUE on success, FALSE on failure.
343 @see tm_workspace_create_global_tags()
345 gboolean
tm_workspace_load_global_tags(const char *tags_file
, TMParserType mode
)
347 GPtrArray
*file_tags
, *new_tags
;
349 file_tags
= tm_source_file_read_tags_file(tags_file
, mode
);
353 tm_tags_sort(file_tags
, global_tags_sort_attrs
, TRUE
, TRUE
);
355 /* reorder the whole array, because tm_tags_find expects a sorted array */
356 new_tags
= tm_tags_merge(theWorkspace
->global_tags
,
357 file_tags
, global_tags_sort_attrs
, TRUE
);
358 g_ptr_array_free(theWorkspace
->global_tags
, TRUE
);
359 g_ptr_array_free(file_tags
, TRUE
);
360 theWorkspace
->global_tags
= new_tags
;
362 g_ptr_array_free(theWorkspace
->global_typename_array
, TRUE
);
363 theWorkspace
->global_typename_array
= tm_tags_extract(new_tags
, TM_GLOBAL_TYPE_MASK
);
369 static gboolean
write_includes_file(const gchar
*outf
, GList
*includes_files
)
371 FILE *fp
= g_fopen(outf
, "w");
372 GList
*node
= includes_files
;
379 char *str
= g_strdup_printf("#include \"%s\"\n", (char*)node
->data
);
380 size_t str_len
= strlen(str
);
382 fwrite(str
, str_len
, 1, fp
);
384 node
= g_list_next(node
);
387 return fclose(fp
) == 0;
391 static gboolean
combine_include_files(const gchar
*outf
, GList
*file_list
)
393 FILE *fp
= g_fopen(outf
, "w");
394 GList
*node
= file_list
;
401 const char *fname
= node
->data
;
406 if (! g_file_get_contents(fname
, &contents
, &length
, &err
))
408 fprintf(stderr
, "Unable to read file: %s\n", err
->message
);
413 fwrite(contents
, length
, 1, fp
);
414 fwrite("\n", 1, 1, fp
); /* in case file doesn't end in newline (e.g. windows). */
417 node
= g_list_next (node
);
420 return fclose(fp
) == 0;
424 static gchar
*create_temp_file(const gchar
*tpl
)
429 fd
= g_file_open_tmp(tpl
, &name
, NULL
);
438 static GList
*lookup_includes(const gchar
**includes
, gint includes_count
)
440 GList
*includes_files
= NULL
;
441 GHashTable
*table
; /* used for deduping */
444 table
= g_hash_table_new_full(g_str_hash
, g_str_equal
, NULL
, NULL
);
446 for (i
= 0; i
< includes_count
; i
++)
448 if (!g_hash_table_lookup(table
, includes
[i
]))
450 gchar
* file_name_copy
= g_strdup(includes
[i
]);
452 includes_files
= g_list_prepend(includes_files
, file_name_copy
);
453 g_hash_table_insert(table
, file_name_copy
, file_name_copy
);
457 g_hash_table_destroy(table
);
459 return g_list_reverse(includes_files
);
462 static gchar
*pre_process_file(const gchar
*cmd
, const gchar
*inf
)
465 gchar
*outf
= create_temp_file("tmp_XXXXXX.cpp");
467 gchar
*errors
= NULL
;
473 tmp_errfile
= create_temp_file("tmp_XXXXXX");
481 command
= g_strdup_printf("%s %s >%s 2>%s",
482 cmd
, inf
, outf
, tmp_errfile
);
484 g_message("Executing: %s", command
);
486 ret
= system(command
);
489 g_file_get_contents(tmp_errfile
, &errors
, NULL
, NULL
);
490 if (errors
&& *errors
)
491 g_printerr("%s\n", errors
);
493 g_unlink(tmp_errfile
);
506 /* Creates a list of global tags. Ideally, this should be created once during
507 installations so that all users can use the same file. This is because a full
508 scale global tag list can occupy several megabytes of disk space.
509 @param pre_process The pre-processing command. This is executed via system(),
510 so you can pass stuff like 'gcc -E -dD -P `gnome-config --cflags gnome`'.
511 @param includes Include files to process. Wildcards such as '/usr/include/a*.h'
513 @param tags_file The file where the tags will be stored.
514 @param lang The language to use for the tags file.
515 @return TRUE on success, FALSE on failure.
517 gboolean
tm_workspace_create_global_tags(const char *pre_process
, const char **includes
,
518 int includes_count
, const char *tags_file
, TMParserType lang
)
520 gboolean ret
= FALSE
;
521 TMSourceFile
*source_file
;
522 GList
*includes_files
;
523 gchar
*temp_file
= create_temp_file("tmp_XXXXXX.cpp");
524 GPtrArray
*filtered_tags
;
529 includes_files
= lookup_includes(includes
, includes_count
);
532 g_message ("writing out files to %s\n", temp_file
);
535 ret
= write_includes_file(temp_file
, includes_files
);
537 ret
= combine_include_files(temp_file
, includes_files
);
539 g_list_free_full(includes_files
, g_free
);
546 gchar
*temp_file2
= pre_process_file(pre_process
, temp_file
);
552 temp_file
= temp_file2
;
558 source_file
= tm_source_file_new(temp_file
, tm_source_file_get_lang_name(lang
));
561 update_source_file(source_file
, NULL
, 0, FALSE
, FALSE
);
562 if (source_file
->tags_array
->len
== 0)
564 tm_source_file_free(source_file
);
568 tm_tags_sort(source_file
->tags_array
, global_tags_sort_attrs
, TRUE
, FALSE
);
569 filtered_tags
= tm_tags_extract(source_file
->tags_array
, ~tm_tag_local_var_t
);
570 ret
= tm_source_file_write_tags_file(tags_file
, filtered_tags
);
571 g_ptr_array_free(filtered_tags
, TRUE
);
572 tm_source_file_free(source_file
);
581 static void fill_find_tags_array(GPtrArray
*dst
, const GPtrArray
*src
,
582 const char *name
, const char *scope
, TMTagType type
, TMParserType lang
)
587 if (!src
|| !dst
|| !name
|| !*name
)
590 tag
= tm_tags_find(src
, name
, FALSE
, &num
);
591 for (i
= 0; i
< num
; ++i
)
593 if ((type
& (*tag
)->type
) &&
594 tm_parser_langs_compatible(lang
, (*tag
)->lang
) &&
595 (!scope
|| g_strcmp0((*tag
)->scope
, scope
) == 0))
597 g_ptr_array_add(dst
, *tag
);
604 /* Returns all matching tags found in the workspace.
605 @param name The name of the tag to find.
606 @param scope The scope name of the tag to find, or NULL.
607 @param type The tag types to return (TMTagType). Can be a bitmask.
608 @param attrs The attributes to sort and dedup on (0 terminated integer array).
609 @param lang Specifies the language(see the table in tm_parsers.h) of the tags to be found,
611 @return Array of matching tags.
613 GPtrArray
*tm_workspace_find(const char *name
, const char *scope
, TMTagType type
,
614 TMTagAttrType
*attrs
, TMParserType lang
)
616 GPtrArray
*tags
= g_ptr_array_new();
618 fill_find_tags_array(tags
, theWorkspace
->tags_array
, name
, scope
, type
, lang
);
619 fill_find_tags_array(tags
, theWorkspace
->global_tags
, name
, scope
, type
, lang
);
622 tm_tags_sort(tags
, attrs
, TRUE
, FALSE
);
628 gboolean
tm_workspace_is_autocomplete_tag(TMTag
*tag
,
629 TMSourceFile
*current_file
,
631 const gchar
*current_scope
)
633 TMParserType lang
= current_file
? current_file
->lang
: TM_PARSER_NONE
;
635 /* ignore local variables from other files/functions or after current line */
636 gboolean valid
= !(tag
->type
& tm_tag_local_var_t
) ||
637 (current_file
== tag
->file
&&
638 current_line
>= tag
->line
&&
639 g_strcmp0(current_scope
, tag
->scope
) == 0);
641 /* tag->local indicates per-file-only visibility such as static C functions */
642 gboolean valid_local
= !tag
->local
|| current_file
== tag
->file
;
644 return valid
&& valid_local
&&
645 !tm_tag_is_anon(tag
) && tm_parser_langs_compatible(lang
, tag
->lang
);
656 static gboolean
is_any_tag(TMTag
*tag
, CopyInfo
*info
)
661 static gboolean
is_local_tag(TMTag
*tag
, CopyInfo
*info
)
663 return tag
->type
& tm_tag_local_var_t
;
666 static gboolean
is_non_local_tag(TMTag
*tag
, CopyInfo
*info
)
668 return !is_local_tag(tag
, info
);
671 /* non-local tag not from current file */
672 static gboolean
is_workspace_tag(TMTag
*tag
, CopyInfo
*info
)
674 return tag
->file
!= info
->file
&&
675 is_non_local_tag(tag
, info
);
679 static guint
copy_tags(GPtrArray
*dst
, TMTag
**src
, guint src_len
, GHashTable
*name_table
,
680 gint num
, gboolean (*predicate
) (TMTag
*, CopyInfo
*), CopyInfo
*info
)
684 g_return_val_if_fail(src
&& dst
, 0);
686 for (i
= 0; i
< src_len
&& num
> 0; i
++)
689 if (predicate(tag
, info
) &&
690 tm_workspace_is_autocomplete_tag(tag
, info
->file
, info
->line
, info
->scope
) &&
691 !g_hash_table_contains(name_table
, tag
->name
))
693 g_ptr_array_add(dst
, tag
);
694 g_hash_table_add(name_table
, tag
->name
);
702 static void fill_find_tags_array_prefix(GPtrArray
*dst
, const char *name
,
703 CopyInfo
*info
, guint max_num
)
707 GHashTable
*name_table
;
709 if (!dst
|| !name
|| !*name
)
712 name_table
= g_hash_table_new_full(g_str_hash
, g_str_equal
, NULL
, NULL
);
716 found
= tm_tags_find(info
->file
->tags_array
, name
, TRUE
, &count
);
719 copy_tags(dst
, found
, count
, name_table
, max_num
- dst
->len
, is_local_tag
, info
);
720 if (dst
->len
< max_num
)
721 copy_tags(dst
, found
, count
, name_table
, max_num
- dst
->len
, is_non_local_tag
, info
);
724 if (dst
->len
< max_num
)
726 found
= tm_tags_find(theWorkspace
->tags_array
, name
, TRUE
, &count
);
728 copy_tags(dst
, found
, count
, name_table
, max_num
- dst
->len
, is_workspace_tag
, info
);
730 if (dst
->len
< max_num
)
732 found
= tm_tags_find(theWorkspace
->global_tags
, name
, TRUE
, &count
);
734 copy_tags(dst
, found
, count
, name_table
, max_num
- dst
->len
, is_any_tag
, info
);
737 g_hash_table_unref(name_table
);
744 gboolean sort_by_name
;
748 static gint
sort_found_tags(gconstpointer a
, gconstpointer b
, gpointer user_data
)
750 SortInfo
*info
= user_data
;
751 const TMTag
*t1
= *((TMTag
**) a
);
752 const TMTag
*t2
= *((TMTag
**) b
);
754 /* sort local vars first (with highest line number first), followed
755 * by tags from current file, followed by workspace tags, followed by
757 if (t1
->type
& tm_tag_local_var_t
&& t2
->type
& tm_tag_local_var_t
)
758 return info
->sort_by_name
? g_strcmp0(t1
->name
, t2
->name
) : t2
->line
- t1
->line
;
759 else if (t1
->type
& tm_tag_local_var_t
)
761 else if (t2
->type
& tm_tag_local_var_t
)
763 else if (t1
->file
== info
->file
&& t2
->file
!= info
->file
)
765 else if (t2
->file
== info
->file
&& t1
->file
!= info
->file
)
767 else if (t1
->file
&& !t2
->file
)
769 else if (t2
->file
&& !t1
->file
)
771 return g_strcmp0(t1
->name
, t2
->name
);
775 /* Returns tags with the specified prefix sorted by name, ignoring local
776 variables from other files/functions or after current line. If there are several
777 tags with the same name, only one of them appears in the resulting array.
778 @param prefix The prefix of the tag to find.
779 @param lang Specifies the language(see the table in tm_parsers.h) of the tags to be found,
781 @param max_num The maximum number of tags to return.
782 @return Array of matching tags sorted by their name.
784 GPtrArray
*tm_workspace_find_prefix(const char *prefix
,
785 TMSourceFile
*current_file
,
787 const gchar
*current_scope
,
790 TMTagAttrType attrs
[] = { tm_tag_attr_name_t
, 0 };
791 GPtrArray
*tags
= g_ptr_array_new();
795 copy_info
.file
= current_file
;
796 copy_info
.line
= current_line
;
797 copy_info
.scope
= current_scope
;
798 fill_find_tags_array_prefix(tags
, prefix
, ©_info
, max_num
);
800 /* sort based on how "close" the tag is to current line with local
802 sort_info
.file
= current_file
;
803 sort_info
.sort_by_name
= TRUE
;
804 g_ptr_array_sort_with_data(tags
, sort_found_tags
, &sort_info
);
810 static gboolean
replace_with_char(gchar
*haystack
, const gchar
*needle
, char replacement
)
812 gchar
*pos
= strstr(haystack
, needle
);
827 static gboolean
replace_parens_with_char(gchar
*haystack
, gchar paren_begin
, gchar paren_end
, char replacement
)
829 gchar needle
[2] = {paren_begin
, '\0'};
830 gchar
*pos
= strstr(haystack
, needle
);
837 if (*pos
== paren_begin
)
839 else if (*pos
== paren_end
)
852 static gchar
*strip_type(const gchar
*scoped_name
, TMParserType lang
, gboolean remove_scope
)
854 if (scoped_name
!= NULL
)
856 const gchar
*sep
= tm_parser_scope_separator(lang
);
857 gchar
*name
= g_strdup(scoped_name
);
860 /* remove pointers, parens and keywords appearing in types */
861 g_strdelimit(name
, "*^&", ' ');
862 while (replace_parens_with_char(name
, '[', ']', ' ')) {}
863 while (replace_parens_with_char(name
, '<', '>', ' ')) {}
864 while (replace_with_char(name
, "const ", ' ')) {}
865 while (replace_with_char(name
, " const", ' ')) {}
866 while (replace_with_char(name
, " struct", ' ')) {}
867 /* remove everything before final scope separator */
868 if (remove_scope
&& (scope_suffix
= g_strrstr(name
, sep
)))
870 scope_suffix
+= strlen(sep
);
871 scope_suffix
= g_strdup(scope_suffix
);
883 /* Gets all members of type_tag; search them inside the all array.
884 * The namespace parameter determines whether we are performing the "namespace"
885 * search (user has typed something like "A::" where A is a type) or "scope" search
886 * (user has typed "a." where a is a global struct-like variable). With the
887 * namespace search we return all direct descendants of any type while with the
888 * scope search we return only those which can be invoked on a variable (member,
891 find_scope_members_tags (const GPtrArray
*all
, TMTag
*type_tag
, gboolean
namespace, guint depth
)
893 TMTagType member_types
= tm_tag_max_t
& ~(TM_TYPE_WITH_MEMBERS
| tm_tag_typedef_t
);
899 return NULL
; /* simple inheritence cycle avoidance */
901 tags
= g_ptr_array_new();
904 member_types
= tm_tag_max_t
;
906 if (type_tag
->scope
&& *(type_tag
->scope
))
907 scope
= g_strconcat(type_tag
->scope
, tm_parser_scope_separator(type_tag
->lang
), type_tag
->name
, NULL
);
909 scope
= g_strdup(type_tag
->name
);
911 for (i
= 0; i
< all
->len
; ++i
)
913 TMTag
*tag
= TM_TAG (all
->pdata
[i
]);
915 if (tag
&& (tag
->type
& member_types
) &&
916 tag
->scope
&& tag
->scope
[0] != '\0' &&
917 tm_parser_langs_compatible(tag
->lang
, type_tag
->lang
) &&
918 strcmp(scope
, tag
->scope
) == 0 &&
919 (!namespace || !tm_tag_is_anon(tag
)))
921 g_ptr_array_add (tags
, tag
);
925 /* add members from parent classes */
926 if (!namespace && (type_tag
->type
& (tm_tag_class_t
| tm_tag_struct_t
)) &&
927 type_tag
->inheritance
&& *type_tag
->inheritance
)
929 gchar
*stripped
= strip_type(type_tag
->inheritance
, type_tag
->lang
, FALSE
);
930 gchar
**split_strv
= g_strsplit(stripped
, ",", -1); /* parent classes */
935 for (i
= 0; parent
= split_strv
[i
]; i
++)
937 GPtrArray
*parent_tags
;
939 stripped
= strip_type(parent
, type_tag
->lang
, TRUE
);
940 parent_tags
= tm_workspace_find(stripped
, NULL
, tm_tag_class_t
| tm_tag_struct_t
,
941 NULL
, type_tag
->lang
);
943 if (parent_tags
->len
> 0)
945 TMTag
*parent_tag
= parent_tags
->pdata
[0];
946 GPtrArray
*parent_members
= find_scope_members_tags(
947 parent_tag
->file
? parent_tag
->file
->tags_array
: all
, parent_tag
,
953 for (j
= 0; j
< parent_members
->len
; j
++)
954 g_ptr_array_add (tags
, parent_members
->pdata
[j
]);
955 g_ptr_array_free(parent_members
, TRUE
);
959 g_ptr_array_free(parent_tags
, TRUE
);
963 g_strfreev(split_strv
);
970 g_ptr_array_free(tags
, TRUE
);
976 TMTagAttrType sort_attrs
[] = {tm_tag_attr_name_t
, 0};
977 tm_tags_sort(tags
, sort_attrs
, TRUE
, FALSE
);
984 /* Gets all members of the type with the given name; search them inside tags_array */
986 find_scope_members (const GPtrArray
*tags_array
, const gchar
*name
, TMSourceFile
*file
,
987 TMParserType lang
, gboolean
namespace)
989 GPtrArray
*res
= NULL
;
993 g_return_val_if_fail(name
&& *name
, NULL
);
995 type_name
= g_strdup(name
);
997 /* Check if type_name is a type that can possibly contain members.
998 * Try to resolve intermediate typedefs to get the real type name. Also
999 * add scope information to the name if applicable.
1000 * The loop below loops only when resolving typedefs - avoid possibly infinite
1001 * loop when typedefs create a cycle by adding some limits. */
1002 for (i
= 0; i
< 5; i
++)
1005 GPtrArray
*type_tags
;
1006 TMTagType types
= TM_TYPE_WITH_MEMBERS
| tm_tag_typedef_t
;
1010 types
&= ~tm_tag_enum_t
;
1012 type_tags
= g_ptr_array_new();
1013 fill_find_tags_array(type_tags
, tags_array
, type_name
, NULL
, types
, lang
);
1015 for (j
= 0; j
< type_tags
->len
; j
++)
1017 TMTag
*test_tag
= TM_TAG(type_tags
->pdata
[j
]);
1019 /* anonymous type defined in a different file than the variable -
1020 * this isn't the type we are looking for */
1021 if (tm_tag_is_anon(test_tag
) && (file
!= test_tag
->file
|| test_tag
->file
== NULL
))
1026 /* prefer non-typedef tags because we can be sure they contain members */
1027 if (test_tag
->type
!= tm_tag_typedef_t
)
1031 g_ptr_array_free(type_tags
, TRUE
);
1033 if (!tag
) /* not a type that can contain members */
1036 /* intermediate typedef - resolve to the real type */
1037 if (tag
->type
== tm_tag_typedef_t
)
1039 if (tag
->var_type
&& tag
->var_type
[0] != '\0')
1042 type_name
= strip_type(tag
->var_type
, tag
->lang
, TRUE
);
1048 else /* real type with members */
1050 /* use the same file as the composite type if file information available */
1051 res
= find_scope_members_tags(tag
->file
? tag
->file
->tags_array
: tags_array
, tag
, namespace, 0);
1062 /* Checks whether a member tag is directly accessible from method */
1063 static gboolean
member_accessible(const GPtrArray
*tags
, const gchar
*method_scope
, TMTag
*member_tag
,
1066 const gchar
*sep
= tm_parser_scope_separator(lang
);
1067 gboolean ret
= FALSE
;
1071 /* method scope is in the form ...::class_name::method_name */
1072 comps
= g_strsplit (method_scope
, sep
, 0);
1073 len
= g_strv_length(comps
);
1076 gchar
*cls
= comps
[len
- 2];
1080 /* find method's class members */
1081 GPtrArray
*cls_tags
= find_scope_members(tags
, cls
, NULL
, lang
, FALSE
);
1087 /* check if one of the class members is member_tag */
1088 for (i
= 0; i
< cls_tags
->len
; i
++)
1090 TMTag
*t
= cls_tags
->pdata
[i
];
1092 if (t
== member_tag
)
1098 g_ptr_array_free(cls_tags
, TRUE
);
1108 /* For an array of variable/type tags, find members inside the types */
1110 find_scope_members_all(const GPtrArray
*tags
, const GPtrArray
*searched_array
, TMParserType lang
,
1111 gboolean member
, const gchar
*current_scope
)
1113 GPtrArray
*member_tags
= NULL
;
1116 /* there may be several variables/types with the same name - try each of them until
1117 * we find something */
1118 for (i
= 0; i
< tags
->len
&& !member_tags
; i
++)
1120 TMTag
*tag
= TM_TAG(tags
->pdata
[i
]);
1121 TMTagType member_types
= tm_tag_member_t
| tm_tag_field_t
| tm_tag_method_t
;
1122 TMTagType types
= TM_TYPE_WITH_MEMBERS
| tm_tag_typedef_t
;
1124 if (tag
->type
& types
) /* type: namespace search */
1126 if (tag
->type
& tm_tag_typedef_t
)
1127 member_tags
= find_scope_members(searched_array
, tag
->name
, tag
->file
, lang
, TRUE
);
1129 member_tags
= find_scope_members_tags(tag
->file
? tag
->file
->tags_array
: searched_array
,
1132 else if (tag
->var_type
) /* variable: scope search */
1134 /* The question now is whether we should use member tags (such as
1135 * tm_tag_field_t, tm_tag_member_t) or not. We want them if member==TRUE
1136 * (which means user has typed something like foo.bar.) or if we are
1137 * inside a method where foo is a class member, we want scope completion
1139 if (!(tag
->type
& member_types
) || member
||
1140 member_accessible(searched_array
, current_scope
, tag
, lang
))
1142 gchar
*tag_type
= strip_type(tag
->var_type
, tag
->lang
, TRUE
);
1144 member_tags
= find_scope_members(searched_array
, tag_type
, tag
->file
, lang
, FALSE
);
1154 static GPtrArray
*find_namespace_members_all(const GPtrArray
*tags
, const GPtrArray
*searched_array
)
1156 GPtrArray
*member_tags
= NULL
;
1159 for (i
= 0; i
< tags
->len
&& !member_tags
; i
++)
1161 TMTag
*tag
= TM_TAG(tags
->pdata
[i
]);
1163 member_tags
= find_scope_members_tags(searched_array
, tag
, TRUE
, 0);
1170 /* Returns all member tags of a struct/union/class if the provided name is a variable
1171 of such a type or the name of the type.
1172 @param source_file TMSourceFile of the edited source file
1173 @param name Name of the variable/type whose members are searched
1174 @param function TRUE if the name is a name of a function
1175 @param member TRUE if invoked on class/struct member (e.g. after the last dot in foo.bar.)
1176 @param current_scope The current scope in the editor
1177 @param current_line The current line in the editor
1178 @param search_namespace Whether to search the contents of namespace (e.g. after MyNamespace::)
1179 @return A GPtrArray of TMTag pointers to struct/union/class members or NULL when not found */
1181 tm_workspace_find_scope_members (TMSourceFile
*source_file
, const char *name
,
1182 gboolean function
, gboolean member
, const gchar
*current_scope
, guint current_line
,
1183 gboolean search_namespace
)
1185 TMParserType lang
= source_file
? source_file
->lang
: TM_PARSER_NONE
;
1186 GPtrArray
*tags
, *member_tags
= NULL
;
1187 TMTagType function_types
= tm_tag_function_t
| tm_tag_method_t
|
1188 tm_tag_macro_with_arg_t
| tm_tag_prototype_t
;
1189 TMTagType tag_type
= tm_tag_max_t
&
1190 ~(function_types
| tm_tag_enumerator_t
| tm_tag_namespace_t
| tm_tag_package_t
);
1191 TMTagAttrType sort_attr
[] = {tm_tag_attr_name_t
, 0};
1193 if (search_namespace
)
1195 tags
= tm_workspace_find(name
, NULL
, tm_tag_namespace_t
, NULL
, lang
);
1197 member_tags
= find_namespace_members_all(tags
, theWorkspace
->tags_array
);
1199 member_tags
= find_namespace_members_all(tags
, theWorkspace
->global_tags
);
1201 g_ptr_array_free(tags
, TRUE
);
1210 tag_type
= function_types
;
1212 /* tags corresponding to the variable/type name */
1213 tags
= tm_workspace_find(name
, NULL
, tag_type
, NULL
, lang
);
1215 /* remove invalid local tags and sort tags so "nearest" tags are first */
1216 for (i
= 0; i
< tags
->len
; i
++)
1218 TMTag
*tag
= tags
->pdata
[i
];
1219 if (!tm_workspace_is_autocomplete_tag(tag
, source_file
, current_line
, current_scope
))
1220 tags
->pdata
[i
] = NULL
;
1222 tm_tags_prune(tags
);
1224 info
.file
= source_file
;
1225 info
.sort_by_name
= FALSE
;
1226 g_ptr_array_sort_with_data(tags
, sort_found_tags
, &info
);
1228 /* Start searching inside the source file, continue with workspace tags and
1229 * end with global tags. This way we find the "closest" tag to the current
1230 * file in case there are more of them. */
1232 member_tags
= find_scope_members_all(tags
, source_file
->tags_array
,
1233 lang
, member
, current_scope
);
1235 member_tags
= find_scope_members_all(tags
, theWorkspace
->tags_array
, lang
,
1236 member
, current_scope
);
1238 member_tags
= find_scope_members_all(tags
, theWorkspace
->global_tags
, lang
,
1239 member
, current_scope
);
1241 g_ptr_array_free(tags
, TRUE
);
1245 tm_tags_dedup(member_tags
, sort_attr
, FALSE
);
1253 /* Dumps the workspace tree - useful for debugging */
1254 void tm_workspace_dump(void)
1259 g_message("Dumping TagManager workspace tree..");
1261 for (i
=0; i
< theWorkspace
->source_files
->len
; ++i
)
1263 TMSourceFile
*source_file
= theWorkspace
->source_files
->pdata
[i
];
1264 fprintf(stderr
, "%s", source_file
->file_name
);
1267 #endif /* TM_DEBUG */