2 * Copyright (c) 2016, Jiri Techet
4 * This source code is released for free distribution under the terms of the
5 * GNU General Public License version 2 or (at your option) any later version.
7 * Encapsulates ctags so it is isolated from the rest of Geany.
13 #include "general.h" /* must always come before the rest of ctags headers */
17 #include "options_p.h"
19 #include "trashbox_p.h"
27 static gint
write_entry(tagWriter
*writer
, MIO
* mio
, const tagEntryInfo
*const tag
, void *user_data
);
28 static void rescan_failed(tagWriter
*writer
, gulong valid_tag_num
, void *user_data
);
30 tagWriter geanyWriter
= {
31 .writeEntry
= write_entry
,
32 .writePtagEntry
= NULL
, /* no pseudo-tags */
33 .preWriteEntry
= NULL
,
34 .postWriteEntry
= NULL
,
35 .rescanFailedEntry
= rescan_failed
,
36 .treatFieldAsFixed
= NULL
,
37 .defaultFileName
= "geany_tags_file_which_should_never_appear_anywhere",
43 static bool nonfatal_error_printer(const errorSelection selection
,
44 const gchar
*const format
,
45 va_list ap
, void *data CTAGS_ATTR_UNUSED
)
47 g_logv(G_LOG_DOMAIN
, G_LOG_LEVEL_WARNING
, format
, ap
);
53 static void enable_roles(const TMParserType lang
, guint kind
)
55 unsigned int c
= countLanguageRoles(lang
, kind
);
56 kindDefinition
*def
= getLanguageKind(lang
, kind
);
57 gchar kind_letter
= def
->letter
;
59 for (unsigned int i
= 0; i
< c
; i
++)
61 roleDefinition
* rdef
= getLanguageRole(lang
, kind
, (int)i
);
62 gboolean should_enable
= tm_parser_enable_role(lang
, kind_letter
);
63 enableRole(rdef
, should_enable
);
68 static void enable_kinds_and_roles()
72 for (lang
= 0; lang
< (gint
)countParsers(); lang
++)
74 guint kind_num
= countLanguageKinds(lang
);
77 for (kind
= 0; kind
< kind_num
; kind
++)
79 kindDefinition
*def
= getLanguageKind(lang
, kind
);
80 gboolean should_enable
= tm_parser_enable_kind(lang
, def
->letter
);
82 enableKind(def
, should_enable
);
84 enable_roles(lang
, kind
);
91 Initializes a TMTag structure with information from a ctagsTag struct
92 used by the ctags parsers. Note that the TMTag structure must be malloc()ed
93 before calling this function.
94 @param tag The TMTag structure to initialize
95 @param file Pointer to a TMSourceFile struct (it is assigned to the file member)
96 @param tag_entry Tag information gathered by the ctags parser
97 @return TRUE on success, FALSE on failure
99 static gboolean
init_tag(TMTag
*tag
, TMSourceFile
*file
, const tagEntryInfo
*tag_entry
)
108 lang
= tag_entry
->langType
;
109 kind_letter
= getLanguageKind(tag_entry
->langType
, tag_entry
->kindIndex
)->letter
;
110 type
= tm_parser_get_tag_type(kind_letter
, lang
);
111 if (file
->lang
!= lang
) /* this is a tag from a subparser */
113 /* check for possible re-definition of subparser type */
114 type
= tm_parser_get_subparser_type(file
->lang
, lang
, type
);
117 if (!tag_entry
->name
|| type
== tm_tag_undef_t
)
120 tag
->name
= g_strdup(tag_entry
->name
);
122 tag
->local
= tag_entry
->isFileScope
&& file
->trust_file_scope
;
123 tag
->flags
= tm_tag_flag_none_t
;
124 if (isTagExtraBitMarked(tag_entry
, XTAG_ANONYMOUS
))
125 tag
->flags
|= tm_tag_flag_anon_t
;
126 tag
->kind_letter
= kind_letter
;
127 tag
->line
= tag_entry
->lineNumber
;
128 if (NULL
!= tag_entry
->extensionFields
.signature
)
129 tag
->arglist
= g_strdup(tag_entry
->extensionFields
.signature
);
130 if ((NULL
!= tag_entry
->extensionFields
.scopeName
) &&
131 (0 != tag_entry
->extensionFields
.scopeName
[0]))
132 tag
->scope
= g_strdup(tag_entry
->extensionFields
.scopeName
);
133 if (tag_entry
->extensionFields
.inheritance
!= NULL
)
134 tag
->inheritance
= g_strdup(tag_entry
->extensionFields
.inheritance
);
135 if (tag_entry
->extensionFields
.typeRef
[1] != NULL
)
136 tag
->var_type
= g_strdup(tag_entry
->extensionFields
.typeRef
[1]);
137 if (tag_entry
->extensionFields
.access
!= NULL
)
138 tag
->access
= tm_source_file_get_tag_access(tag_entry
->extensionFields
.access
);
139 if (tag_entry
->extensionFields
.implementation
!= NULL
)
140 tag
->impl
= tm_source_file_get_tag_impl(tag_entry
->extensionFields
.implementation
);
141 if ((tm_tag_macro_t
== tag
->type
) && (NULL
!= tag
->arglist
))
142 tag
->type
= tm_tag_macro_with_arg_t
;
144 /* redefine lang also for subparsers because the rest of Geany assumes that
145 * tags from a single file are from a single language */
146 tag
->lang
= file
->lang
;
149 gchar
*new_scope
= tm_parser_update_scope(tag
->lang
, tag
->scope
);
150 if (new_scope
!= tag
->scope
)
153 tag
->scope
= new_scope
;
160 static gint
write_entry(tagWriter
*writer
, MIO
* mio
, const tagEntryInfo
*const tag
, void *user_data
)
162 TMSourceFile
*source_file
= user_data
;
163 TMTag
*tm_tag
= tm_tag_new();
165 getTagScopeInformation((tagEntryInfo
*)tag
, NULL
, NULL
);
167 if (!init_tag(tm_tag
, source_file
, tag
))
169 tm_tag_unref(tm_tag
);
173 g_ptr_array_add(source_file
->tags_array
, tm_tag
);
175 /* output length - we don't write anything to the MIO */
180 static void rescan_failed(tagWriter
*writer
, gulong valid_tag_num
, void *user_data
)
182 TMSourceFile
*source_file
= user_data
;
183 GPtrArray
*tags_array
= source_file
->tags_array
;
185 if (tags_array
->len
> valid_tag_num
)
188 for (i
= valid_tag_num
; i
< tags_array
->len
; i
++)
189 tm_tag_unref(tags_array
->pdata
[i
]);
190 g_ptr_array_set_size(tags_array
, valid_tag_num
);
195 /* keep in sync with ctags main() - use only things interesting for us */
196 void tm_ctags_init(void)
198 initDefaultTrashBox();
200 setErrorPrinter(nonfatal_error_printer
, NULL
);
201 setTagWriter(WRITER_CUSTOM
, &geanyWriter
);
209 initRegexOptscript();
211 /* make sure all parsers are initialized */
212 initializeParser(LANG_AUTO
);
214 /* change default values which are false */
215 enableXtag(XTAG_TAGS_GENERATED_BY_GUEST_PARSERS
, true);
216 enableXtag(XTAG_REFERENCE_TAGS
, true);
218 /* some kinds we are interested in are disabled by default */
219 enable_kinds_and_roles();
223 void tm_ctags_add_ignore_symbol(const char *value
)
225 langType lang
= getNamedLanguage ("CPreProcessor", 0);
226 gchar
*val
= g_strdup(value
);
228 /* make sure we don't enter empty string - passing NULL or "" clears
229 * the ignore list in ctags */
230 val
= g_strstrip(val
);
232 applyParameter (lang
, "ignore", val
);
237 void tm_ctags_clear_ignore_symbols(void)
239 langType lang
= getNamedLanguage ("CPreProcessor", 0);
240 applyParameter (lang
, "ignore", NULL
);
244 /* call after all tags have been collected so we don't have to handle reparses
245 * with the counter (which gets complicated when also subparsers are involved) */
246 static void rename_anon_tags(TMSourceFile
*source_file
)
248 gboolean is_c
= source_file
->lang
== TM_PARSER_C
|| source_file
->lang
== TM_PARSER_CPP
;
249 gint
*anon_counter_table
= NULL
;
250 GPtrArray
*removed_typedefs
= NULL
;
253 for (i
= 0; i
< source_file
->tags_array
->len
; i
++)
255 TMTag
*tag
= TM_TAG(source_file
->tags_array
->pdata
[i
]);
256 if (tm_tag_is_anon(tag
))
258 gchar
*orig_name
, *new_name
= NULL
;
260 guint new_name_len
, orig_name_len
;
261 gboolean inside_nesting
= FALSE
;
262 guint scope_len
= tag
->scope
? strlen(tag
->scope
) : 0;
263 gchar kind
= tag
->kind_letter
;
265 orig_name
= tag
->name
;
266 orig_name_len
= strlen(orig_name
);
270 /* First check if there's a typedef behind the scope nesting
271 * such as typedef struct {} Foo; - in this case we can replace
272 * the anon tag with Foo */
273 for (j
= i
+ 1; j
< source_file
->tags_array
->len
; j
++)
275 TMTag
*nested_tag
= TM_TAG(source_file
->tags_array
->pdata
[j
]);
276 guint nested_scope_len
= nested_tag
->scope
? strlen(nested_tag
->scope
) : 0;
278 /* Tags can be interleaved with scopeless macros - skip those */
279 if (nested_tag
->type
& (tm_tag_macro_t
| tm_tag_macro_with_arg_t
))
282 /* Nested tags have longer scope than the parent - once the scope
283 * is equal or lower than the parent scope, we are outside the tag's
285 if (nested_scope_len
<= scope_len
)
289 /* We are out of the nesting - the next tag could be a typedef */
290 if (j
< source_file
->tags_array
->len
)
292 TMTag
*typedef_tag
= TM_TAG(source_file
->tags_array
->pdata
[j
]);
293 guint typedef_scope_len
= typedef_tag
->scope
? strlen(typedef_tag
->scope
) : 0;
295 /* Should be at the same scope level as the anon tag */
296 if (typedef_tag
->type
== tm_tag_typedef_t
&&
297 typedef_scope_len
== scope_len
&&
298 g_strcmp0(typedef_tag
->var_type
, tag
->name
) == 0)
300 /* set the name of the original anon tag and pretend
301 * it wasn't a anon tag */
302 tag
->name
= g_strdup(typedef_tag
->name
);
303 tag
->flags
&= ~tm_tag_flag_anon_t
;
304 new_name
= tag
->name
;
305 /* the typedef tag will be removed */
306 if (!removed_typedefs
)
307 removed_typedefs
= g_ptr_array_new();
308 g_ptr_array_add(removed_typedefs
, GUINT_TO_POINTER(j
));
313 /* there's no typedef name for the anon tag so let's generate one */
318 const gchar
*kind_name
= tm_ctags_get_kind_name(kind
, tag
->lang
);
320 if (!anon_counter_table
)
321 anon_counter_table
= g_new0(gint
, 256);
323 anon_counter
= ++anon_counter_table
[kind
];
325 sprintf(buf
, "anon_%s_%u", kind_name
, anon_counter
);
326 tag
->name
= g_strdup(buf
);
327 new_name
= tag
->name
;
330 new_name_len
= strlen(new_name
);
332 /* Check if this tag is parent of some other tag - if so, we have to
333 * update the scope. It can only be parent of the following tags
334 * so start with the next tag. */
335 for (j
= i
+ 1; j
< source_file
->tags_array
->len
; j
++)
337 TMTag
*nested_tag
= TM_TAG(source_file
->tags_array
->pdata
[j
]);
338 guint nested_scope_len
= nested_tag
->scope
? strlen(nested_tag
->scope
) : 0;
341 /* Tags can be interleaved with scopeless macros - skip those */
342 if (is_c
&& nested_tag
->type
& (tm_tag_macro_t
| tm_tag_macro_with_arg_t
))
345 /* In Fortran, we can create variables of anonymous structures:
346 * structure var1, var2
349 * and the parser first generates tags for var1 and var2 which
350 * are on the same scope as the structure itself. So first
351 * we need to skip past the tags on the same scope and only
352 * afterwards we get the nested tags.
354 if (source_file
->lang
== TM_PARSER_FORTRAN
&&
355 !inside_nesting
&& nested_scope_len
== scope_len
)
358 inside_nesting
= TRUE
;
360 /* Terminate if outside of tag scope, see above */
361 if (nested_scope_len
<= scope_len
)
364 pos
= strstr(nested_tag
->scope
, orig_name
);
365 /* We found the parent name in the nested tag scope - replace it
366 * with the new name. Note: anonymous tag names generated by
367 * ctags are unique enough that we don't have to check for
368 * scope separators here. */
371 gchar
*str
= g_malloc(nested_scope_len
+ 50);
372 guint prefix_len
= pos
- nested_tag
->scope
;
374 strncpy(str
, nested_tag
->scope
, prefix_len
);
375 strcpy(str
+ prefix_len
, new_name
);
376 strcpy(str
+ prefix_len
+ new_name_len
, pos
+ orig_name_len
);
377 g_free(nested_tag
->scope
);
378 nested_tag
->scope
= str
;
382 /* We are out of the nesting - the next tags could be variables
383 * of an anonymous struct such as "struct {} a[2], *b, c;" */
384 while (j
< source_file
->tags_array
->len
)
386 TMTag
*var_tag
= TM_TAG(source_file
->tags_array
->pdata
[j
]);
387 guint var_scope_len
= var_tag
->scope
? strlen(var_tag
->scope
) : 0;
390 /* Should be at the same scope level as the anon tag */
391 if (var_scope_len
== scope_len
&&
392 var_tag
->var_type
&& (pos
= strstr(var_tag
->var_type
, orig_name
)))
394 GString
*str
= g_string_new(var_tag
->var_type
);
395 gssize p
= pos
- var_tag
->var_type
;
396 g_string_erase(str
, p
, strlen(orig_name
));
397 g_string_insert(str
, p
, new_name
);
398 g_free(var_tag
->var_type
);
399 var_tag
->var_type
= str
->str
;
400 g_string_free(str
, FALSE
);
412 if (removed_typedefs
)
414 for (i
= 0; i
< removed_typedefs
->len
; i
++)
416 guint j
= GPOINTER_TO_UINT(removed_typedefs
->pdata
[i
]);
417 TMTag
*tag
= TM_TAG(source_file
->tags_array
->pdata
[j
]);
419 source_file
->tags_array
->pdata
[j
] = NULL
;
422 /* remove NULL entries from the array */
423 tm_tags_prune(source_file
->tags_array
);
425 g_ptr_array_free(removed_typedefs
, TRUE
);
428 if (anon_counter_table
)
429 g_free(anon_counter_table
);
433 void tm_ctags_parse(guchar
*buffer
, gsize buffer_size
,
434 const gchar
*file_name
, TMParserType language
, TMSourceFile
*source_file
)
436 g_return_if_fail(buffer
!= NULL
|| file_name
!= NULL
);
438 parseRawBuffer(file_name
, buffer
, buffer_size
, language
, source_file
);
440 rename_anon_tags(source_file
);
444 const gchar
*tm_ctags_get_lang_name(TMParserType lang
)
446 return getLanguageName(lang
);
450 TMParserType
tm_ctags_get_named_lang(const gchar
*name
)
452 return getNamedLanguage(name
, 0);
456 const gchar
*tm_ctags_get_lang_kinds(TMParserType lang
)
458 guint kind_num
= countLanguageKinds(lang
);
459 static gchar kinds
[257];
462 for (i
= 0; i
< kind_num
; i
++)
463 kinds
[i
] = getLanguageKind(lang
, i
)->letter
;
470 const gchar
*tm_ctags_get_kind_name(gchar kind
, TMParserType lang
)
472 kindDefinition
*def
= getLanguageKindForLetter(lang
, kind
);
473 return def
? def
->name
: "unknown";
477 gchar
tm_ctags_get_kind_from_name(const gchar
*name
, TMParserType lang
)
479 kindDefinition
*def
= getLanguageKindForName(lang
, name
);
480 return def
? def
->letter
: '-';
484 guint
tm_ctags_get_lang_count(void)
486 return countParsers();