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
< 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
;
124 tag
->line
= tag_entry
->lineNumber
;
125 if (NULL
!= tag_entry
->extensionFields
.signature
)
126 tag
->arglist
= g_strdup(tag_entry
->extensionFields
.signature
);
127 if ((NULL
!= tag_entry
->extensionFields
.scopeName
) &&
128 (0 != tag_entry
->extensionFields
.scopeName
[0]))
129 tag
->scope
= g_strdup(tag_entry
->extensionFields
.scopeName
);
130 if (tag_entry
->extensionFields
.inheritance
!= NULL
)
131 tag
->inheritance
= g_strdup(tag_entry
->extensionFields
.inheritance
);
132 if (tag_entry
->extensionFields
.typeRef
[1] != NULL
)
133 tag
->var_type
= g_strdup(tag_entry
->extensionFields
.typeRef
[1]);
134 if (tag_entry
->extensionFields
.access
!= NULL
)
135 tag
->access
= tm_source_file_get_tag_access(tag_entry
->extensionFields
.access
);
136 if (tag_entry
->extensionFields
.implementation
!= NULL
)
137 tag
->impl
= tm_source_file_get_tag_impl(tag_entry
->extensionFields
.implementation
);
138 if ((tm_tag_macro_t
== tag
->type
) && (NULL
!= tag
->arglist
))
139 tag
->type
= tm_tag_macro_with_arg_t
;
141 /* redefine lang also for subparsers because the rest of Geany assumes that
142 * tags from a single file are from a single language */
143 tag
->lang
= file
->lang
;
146 gchar
*new_scope
= tm_parser_update_scope(tag
->lang
, tag
->scope
);
147 if (new_scope
!= tag
->scope
)
150 tag
->scope
= new_scope
;
157 static gint
write_entry(tagWriter
*writer
, MIO
* mio
, const tagEntryInfo
*const tag
, void *user_data
)
159 TMSourceFile
*source_file
= user_data
;
160 TMTag
*tm_tag
= tm_tag_new();
162 getTagScopeInformation((tagEntryInfo
*)tag
, NULL
, NULL
);
164 if (!init_tag(tm_tag
, source_file
, tag
))
166 tm_tag_unref(tm_tag
);
170 g_ptr_array_add(source_file
->tags_array
, tm_tag
);
172 /* output length - we don't write anything to the MIO */
177 static void rescan_failed(tagWriter
*writer
, gulong valid_tag_num
, void *user_data
)
179 TMSourceFile
*source_file
= user_data
;
180 GPtrArray
*tags_array
= source_file
->tags_array
;
182 if (tags_array
->len
> valid_tag_num
)
185 for (i
= valid_tag_num
; i
< tags_array
->len
; i
++)
186 tm_tag_unref(tags_array
->pdata
[i
]);
187 g_ptr_array_set_size(tags_array
, valid_tag_num
);
192 /* keep in sync with ctags main() - use only things interesting for us */
193 void tm_ctags_init(void)
195 initDefaultTrashBox();
197 setErrorPrinter(nonfatal_error_printer
, NULL
);
198 setTagWriter(WRITER_CUSTOM
, &geanyWriter
);
206 initRegexOptscript();
208 /* make sure all parsers are initialized */
209 initializeParser(LANG_AUTO
);
211 /* change default values which are false */
212 enableXtag(XTAG_TAGS_GENERATED_BY_GUEST_PARSERS
, true);
213 enableXtag(XTAG_REFERENCE_TAGS
, true);
215 /* some kinds we are interested in are disabled by default */
216 enable_kinds_and_roles();
220 void tm_ctags_add_ignore_symbol(const char *value
)
222 langType lang
= getNamedLanguage ("CPreProcessor", 0);
223 gchar
*val
= g_strdup(value
);
225 /* make sure we don't enter empty string - passing NULL or "" clears
226 * the ignore list in ctags */
227 val
= g_strstrip(val
);
229 applyParameter (lang
, "ignore", val
);
234 void tm_ctags_clear_ignore_symbols(void)
236 langType lang
= getNamedLanguage ("CPreProcessor", 0);
237 applyParameter (lang
, "ignore", NULL
);
241 void tm_ctags_parse(guchar
*buffer
, gsize buffer_size
,
242 const gchar
*file_name
, TMParserType language
, TMSourceFile
*source_file
)
244 g_return_if_fail(buffer
!= NULL
|| file_name
!= NULL
);
246 parseRawBuffer(file_name
, buffer
, buffer_size
, language
, source_file
);
250 const gchar
*tm_ctags_get_lang_name(TMParserType lang
)
252 return getLanguageName(lang
);
256 TMParserType
tm_ctags_get_named_lang(const gchar
*name
)
258 return getNamedLanguage(name
, 0);
262 const gchar
*tm_ctags_get_lang_kinds(TMParserType lang
)
264 guint kind_num
= countLanguageKinds(lang
);
265 static gchar kinds
[257];
268 for (i
= 0; i
< kind_num
; i
++)
269 kinds
[i
] = getLanguageKind(lang
, i
)->letter
;
276 const gchar
*tm_ctags_get_kind_name(gchar kind
, TMParserType lang
)
278 kindDefinition
*def
= getLanguageKindForLetter(lang
, kind
);
279 return def
? def
->name
: "unknown";
283 gchar
tm_ctags_get_kind_from_name(const gchar
*name
, TMParserType lang
)
285 kindDefinition
*def
= getLanguageKindForName(lang
, name
);
286 return def
? def
->letter
: '-';
290 guint
tm_ctags_get_lang_count(void)
292 return countParsers();