2 * tm_parser.c - this file is part of Geany, a fast and lightweight IDE
4 * Copyright 2016 The Geany contributors
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License along
17 * with this program; if not, write to the Free Software Foundation, Inc.,
18 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
21 #include "tm_parser.h"
33 /* Allows remapping a subparser tag type to another type if there's a clash with
34 * the master parser tag type. Only subparser tag types explicitly listed within
35 * TMSubparserMapEntry maps are added to tag manager - tags with types not listed
36 * are discarded to prevent uncontrolled merging of tags from master parser and
42 } TMSubparserMapEntry
;
45 static GHashTable
*subparser_map
= NULL
;
48 {'d', tm_tag_macro_t}, \
49 {'e', tm_tag_enumerator_t}, \
50 {'f', tm_tag_function_t}, \
51 {'g', tm_tag_enum_t}, \
52 {'m', tm_tag_member_t}, \
53 {'p', tm_tag_prototype_t}, \
54 {'s', tm_tag_struct_t}, \
55 {'t', tm_tag_typedef_t}, \
56 {'u', tm_tag_union_t}, \
57 {'v', tm_tag_variable_t}, \
58 {'x', tm_tag_externvar_t},
60 /* Old C parser, also used by GLSL and Ferite */
61 static TMParserMapEntry map_C_old_parser
[] = {
63 {'c', tm_tag_class_t
},
64 {'n', tm_tag_namespace_t
},
67 # define COMMON_C_NEW_PARSER \
68 {'h', tm_tag_undef_t}, \
69 {'l', tm_tag_undef_t}, \
70 {'z', tm_tag_undef_t}, \
71 {'L', tm_tag_undef_t}, \
72 {'D', tm_tag_undef_t},
74 static TMParserMapEntry map_C
[] = {
79 static TMParserMapEntry map_CPP
[] = {
83 {'c', tm_tag_class_t
},
84 {'n', tm_tag_namespace_t
},
85 {'A', tm_tag_undef_t
},
86 {'N', tm_tag_undef_t
},
87 {'U', tm_tag_undef_t
},
88 {'Z', tm_tag_undef_t
},
91 static TMParserMapEntry map_JAVA
[] = {
92 {'c', tm_tag_class_t
},
93 {'f', tm_tag_field_t
},
94 {'i', tm_tag_interface_t
},
95 {'m', tm_tag_method_t
},
96 {'p', tm_tag_package_t
},
97 {'e', tm_tag_enumerator_t
},
101 static TMParserMapEntry map_MAKEFILE
[] = {
102 {'m', tm_tag_macro_t
},
103 {'t', tm_tag_function_t
},
104 {'I', tm_tag_undef_t
},
107 static TMParserMapEntry map_PASCAL
[] = {
108 {'f', tm_tag_function_t
},
109 {'p', tm_tag_function_t
},
112 static TMParserMapEntry map_PERL
[] = {
113 {'c', tm_tag_enum_t
},
114 {'f', tm_tag_other_t
},
115 {'l', tm_tag_macro_t
},
116 {'p', tm_tag_package_t
},
117 {'s', tm_tag_function_t
},
118 {'d', tm_tag_prototype_t
},
119 {'M', tm_tag_undef_t
},
122 static TMParserMapEntry map_PHP
[] = {
123 {'c', tm_tag_class_t
},
124 {'d', tm_tag_macro_t
},
125 {'f', tm_tag_function_t
},
126 {'i', tm_tag_interface_t
},
127 {'l', tm_tag_undef_t
},
128 {'n', tm_tag_namespace_t
},
129 {'t', tm_tag_struct_t
},
130 {'v', tm_tag_variable_t
},
131 {'a', tm_tag_undef_t
},
134 static TMParserMapEntry map_PYTHON
[] = {
135 {'c', tm_tag_class_t
},
136 {'f', tm_tag_function_t
},
137 {'m', tm_tag_method_t
},
138 {'v', tm_tag_variable_t
},
139 /* defined as externvar to get those excluded as forward type in symbols.c:goto_tag()
140 * so we can jump to the real implementation (if known) instead of to the import statement */
141 {'x', tm_tag_externvar_t
},
144 /* different parser than tex.c from universal-ctags */
145 static TMParserMapEntry map_LATEX
[] = {
146 {'f', tm_tag_function_t
},
147 {'c', tm_tag_class_t
},
148 {'m', tm_tag_member_t
},
149 {'d', tm_tag_macro_t
},
150 {'v', tm_tag_variable_t
},
151 {'n', tm_tag_namespace_t
},
152 {'s', tm_tag_struct_t
},
154 static TMParserMapEntry map_BIBTEX
[] = {
155 {'a', tm_tag_function_t
},
156 {'b', tm_tag_class_t
},
157 {'B', tm_tag_class_t
},
158 {'c', tm_tag_member_t
},
159 {'i', tm_tag_macro_t
},
160 {'I', tm_tag_macro_t
},
161 {'j', tm_tag_member_t
},
162 {'m', tm_tag_other_t
},
163 {'M', tm_tag_variable_t
},
164 {'n', tm_tag_other_t
},
165 {'p', tm_tag_variable_t
},
166 {'P', tm_tag_class_t
},
167 {'s', tm_tag_namespace_t
},
168 {'t', tm_tag_other_t
},
169 {'u', tm_tag_externvar_t
},
172 static TMParserMapEntry map_ASM
[] = {
173 {'d', tm_tag_macro_t
},
174 {'l', tm_tag_namespace_t
},
175 {'m', tm_tag_function_t
},
176 {'t', tm_tag_struct_t
},
179 /* not in universal-ctags */
180 static TMParserMapEntry map_CONF
[] = {
181 {'s', tm_tag_namespace_t
},
182 {'k', tm_tag_macro_t
},
185 static TMParserMapEntry map_SQL
[] = {
186 {'c', tm_tag_undef_t
},
187 {'d', tm_tag_prototype_t
},
188 {'f', tm_tag_function_t
},
189 {'E', tm_tag_field_t
},
190 {'l', tm_tag_undef_t
},
191 {'L', tm_tag_undef_t
},
192 {'P', tm_tag_package_t
},
193 {'p', tm_tag_namespace_t
},
194 {'r', tm_tag_undef_t
},
195 {'s', tm_tag_undef_t
},
196 {'t', tm_tag_class_t
},
197 {'T', tm_tag_macro_t
},
198 {'v', tm_tag_variable_t
},
199 {'i', tm_tag_struct_t
},
200 {'e', tm_tag_undef_t
},
201 {'U', tm_tag_undef_t
},
202 {'R', tm_tag_undef_t
},
203 {'D', tm_tag_undef_t
},
204 {'V', tm_tag_member_t
},
205 {'n', tm_tag_undef_t
},
206 {'x', tm_tag_undef_t
},
207 {'y', tm_tag_undef_t
},
208 {'z', tm_tag_undef_t
},
209 {'C', tm_tag_undef_t
},
212 /* not in universal-ctags */
213 static TMParserMapEntry map_DOCBOOK
[] = {
214 {'f', tm_tag_function_t
},
215 {'c', tm_tag_class_t
},
216 {'m', tm_tag_member_t
},
217 {'d', tm_tag_macro_t
},
218 {'v', tm_tag_variable_t
},
219 {'s', tm_tag_struct_t
},
222 static TMParserMapEntry map_ERLANG
[] = {
223 {'d', tm_tag_macro_t
},
224 {'f', tm_tag_function_t
},
225 {'m', tm_tag_undef_t
},
226 {'r', tm_tag_struct_t
},
227 {'t', tm_tag_typedef_t
},
230 static TMParserMapEntry map_CSS
[] = {
231 {'c', tm_tag_class_t
},
232 {'s', tm_tag_struct_t
},
233 {'i', tm_tag_variable_t
},
236 static TMParserMapEntry map_RUBY
[] = {
237 {'c', tm_tag_class_t
},
238 {'f', tm_tag_method_t
},
239 {'m', tm_tag_namespace_t
},
240 {'S', tm_tag_member_t
},
241 {'C', tm_tag_undef_t
},
242 {'A', tm_tag_undef_t
},
243 {'a', tm_tag_undef_t
},
244 {'L', tm_tag_undef_t
},
247 static TMParserMapEntry map_TCL
[] = {
248 {'c', tm_tag_class_t
},
249 {'m', tm_tag_member_t
},
250 {'p', tm_tag_function_t
},
251 {'n', tm_tag_namespace_t
},
254 static TMParserMapEntry map_SH
[] = {
255 {'f', tm_tag_function_t
},
258 static TMParserMapEntry map_D
[] = {
259 {'c', tm_tag_class_t
},
260 {'e', tm_tag_enumerator_t
},
261 {'f', tm_tag_function_t
},
262 {'g', tm_tag_enum_t
},
263 {'i', tm_tag_interface_t
},
264 {'m', tm_tag_member_t
},
265 {'n', tm_tag_namespace_t
},
266 {'p', tm_tag_prototype_t
},
267 {'s', tm_tag_struct_t
},
268 {'t', tm_tag_typedef_t
},
269 {'u', tm_tag_union_t
},
270 {'v', tm_tag_variable_t
},
271 {'x', tm_tag_externvar_t
},
274 static TMParserMapEntry map_DIFF
[] = {
275 {'m', tm_tag_function_t
},
276 {'n', tm_tag_function_t
},
277 {'d', tm_tag_function_t
},
278 {'h', tm_tag_undef_t
},
281 /* different parser than in universal-ctags */
282 static TMParserMapEntry map_VHDL
[] = {
283 {'c', tm_tag_variable_t
},
284 {'t', tm_tag_typedef_t
},
285 {'v', tm_tag_variable_t
},
286 {'a', tm_tag_undef_t
},
287 {'s', tm_tag_variable_t
},
288 {'f', tm_tag_function_t
},
289 {'p', tm_tag_function_t
},
290 {'k', tm_tag_member_t
},
291 {'l', tm_tag_namespace_t
},
292 {'m', tm_tag_member_t
},
293 {'n', tm_tag_class_t
},
294 {'o', tm_tag_struct_t
},
295 {'u', tm_tag_undef_t
},
296 {'b', tm_tag_member_t
},
297 {'A', tm_tag_typedef_t
},
300 static TMParserMapEntry map_LUA
[] = {
301 {'f', tm_tag_function_t
},
302 {'X', tm_tag_undef_t
},
305 static TMParserMapEntry map_JAVASCRIPT
[] = {
306 {'f', tm_tag_function_t
},
307 {'c', tm_tag_class_t
},
308 {'m', tm_tag_method_t
},
309 {'p', tm_tag_member_t
},
310 {'C', tm_tag_macro_t
},
311 {'v', tm_tag_variable_t
},
312 {'g', tm_tag_function_t
},
313 {'G', tm_tag_undef_t
},
314 {'S', tm_tag_undef_t
},
315 {'M', tm_tag_undef_t
},
318 static TMParserMapEntry map_HASKELL
[] = {
319 {'t', tm_tag_typedef_t
},
320 {'c', tm_tag_macro_t
},
321 {'f', tm_tag_function_t
},
322 {'m', tm_tag_namespace_t
},
325 static TMParserMapEntry map_CSHARP
[] = {
326 {'c', tm_tag_class_t
},
327 {'d', tm_tag_macro_t
},
328 {'e', tm_tag_enumerator_t
},
329 {'E', tm_tag_undef_t
},
330 {'f', tm_tag_field_t
},
331 {'g', tm_tag_enum_t
},
332 {'i', tm_tag_interface_t
},
333 {'l', tm_tag_undef_t
},
334 {'m', tm_tag_method_t
},
335 {'n', tm_tag_namespace_t
},
336 {'p', tm_tag_undef_t
},
337 {'s', tm_tag_struct_t
},
338 {'t', tm_tag_typedef_t
},
341 static TMParserMapEntry map_FREEBASIC
[] = {
342 {'c', tm_tag_macro_t
},
343 {'f', tm_tag_function_t
},
344 {'l', tm_tag_namespace_t
},
345 {'t', tm_tag_struct_t
},
346 {'v', tm_tag_variable_t
},
347 {'g', tm_tag_externvar_t
},
350 static TMParserMapEntry map_HAXE
[] = {
351 {'m', tm_tag_method_t
},
352 {'c', tm_tag_class_t
},
353 {'e', tm_tag_enum_t
},
354 {'v', tm_tag_variable_t
},
355 {'i', tm_tag_interface_t
},
356 {'t', tm_tag_typedef_t
},
359 static TMParserMapEntry map_REST
[] = {
360 {'c', tm_tag_namespace_t
},
361 {'s', tm_tag_member_t
},
362 {'S', tm_tag_macro_t
},
363 {'t', tm_tag_variable_t
},
364 {'C', tm_tag_undef_t
},
365 {'T', tm_tag_undef_t
},
366 {'d', tm_tag_undef_t
},
369 static TMParserMapEntry map_HTML
[] = {
370 {'a', tm_tag_member_t
},
371 {'c', tm_tag_undef_t
},
372 {'h', tm_tag_namespace_t
},
373 {'i', tm_tag_class_t
},
374 {'j', tm_tag_variable_t
},
375 {'C', tm_tag_undef_t
},
376 {'I', tm_tag_undef_t
},
377 {'J', tm_tag_undef_t
},
380 static TMSubparserMapEntry subparser_HTML_javascript_map
[] = {
381 {tm_tag_function_t
, tm_tag_function_t
},
384 static TMParserMapEntry map_F77
[] = {
385 {'b', tm_tag_undef_t
},
386 {'c', tm_tag_macro_t
},
387 {'e', tm_tag_undef_t
},
388 {'f', tm_tag_function_t
},
389 {'i', tm_tag_interface_t
},
390 {'k', tm_tag_member_t
},
391 {'l', tm_tag_undef_t
},
392 {'L', tm_tag_undef_t
},
393 {'m', tm_tag_namespace_t
},
394 {'n', tm_tag_undef_t
},
395 {'p', tm_tag_struct_t
},
396 {'s', tm_tag_method_t
},
397 {'t', tm_tag_class_t
},
398 {'v', tm_tag_variable_t
},
399 {'E', tm_tag_enum_t
},
400 {'N', tm_tag_enumerator_t
},
403 #define map_FORTRAN map_F77
405 #define map_FERITE map_C_old_parser
407 /* different parser than in universal-ctags */
408 static TMParserMapEntry map_MATLAB
[] = {
409 {'f', tm_tag_function_t
},
410 {'s', tm_tag_struct_t
},
413 #define map_GLSL map_C_old_parser
415 /* not in universal-ctags */
416 static TMParserMapEntry map_VALA
[] = {
417 {'c', tm_tag_class_t
},
418 {'d', tm_tag_macro_t
},
419 {'e', tm_tag_enumerator_t
},
420 {'f', tm_tag_field_t
},
421 {'g', tm_tag_enum_t
},
422 {'i', tm_tag_interface_t
},
423 {'l', tm_tag_undef_t
},
424 {'m', tm_tag_method_t
},
425 {'n', tm_tag_namespace_t
},
426 {'p', tm_tag_undef_t
},
427 {'S', tm_tag_undef_t
},
428 {'s', tm_tag_struct_t
},
431 /* not in universal-ctags */
432 static TMParserMapEntry map_ACTIONSCRIPT
[] = {
433 {'f', tm_tag_function_t
},
434 {'c', tm_tag_class_t
},
435 {'i', tm_tag_interface_t
},
436 {'P', tm_tag_package_t
},
437 {'m', tm_tag_method_t
},
438 {'p', tm_tag_member_t
},
439 {'v', tm_tag_variable_t
},
440 {'l', tm_tag_variable_t
},
441 {'C', tm_tag_macro_t
},
442 {'I', tm_tag_externvar_t
},
443 {'x', tm_tag_other_t
},
446 static TMParserMapEntry map_NSIS
[] = {
447 {'s', tm_tag_namespace_t
},
448 {'f', tm_tag_function_t
},
449 {'v', tm_tag_variable_t
},
450 {'d', tm_tag_undef_t
},
451 {'m', tm_tag_undef_t
},
452 {'S', tm_tag_undef_t
},
453 {'p', tm_tag_undef_t
},
454 {'l', tm_tag_undef_t
},
455 {'i', tm_tag_undef_t
},
458 /* not in universal-ctags */
459 static TMParserMapEntry map_MARKDOWN
[] = {
460 {'v', tm_tag_variable_t
},
463 static TMParserMapEntry map_TXT2TAGS
[] = {
464 {'s', tm_tag_member_t
},
467 static TMParserMapEntry map_ABC
[] = {
468 {'s', tm_tag_member_t
},
471 static TMParserMapEntry map_VERILOG
[] = {
472 {'c', tm_tag_variable_t
},
473 {'e', tm_tag_typedef_t
},
474 {'f', tm_tag_function_t
},
475 {'m', tm_tag_class_t
},
476 {'n', tm_tag_variable_t
},
477 {'p', tm_tag_variable_t
},
478 {'r', tm_tag_variable_t
},
479 {'t', tm_tag_function_t
},
482 static TMParserMapEntry map_R
[] = {
483 {'f', tm_tag_function_t
},
484 {'l', tm_tag_other_t
},
485 {'s', tm_tag_other_t
},
488 static TMParserMapEntry map_COBOL
[] = {
489 {'d', tm_tag_variable_t
},
490 {'D', tm_tag_interface_t
},
491 {'f', tm_tag_function_t
},
492 {'g', tm_tag_struct_t
},
493 {'p', tm_tag_macro_t
},
494 {'P', tm_tag_class_t
},
495 {'s', tm_tag_namespace_t
},
496 {'S', tm_tag_externvar_t
},
499 static TMParserMapEntry map_OBJC
[] = {
500 {'i', tm_tag_interface_t
},
501 {'I', tm_tag_undef_t
},
502 {'P', tm_tag_undef_t
},
503 {'m', tm_tag_method_t
},
504 {'c', tm_tag_class_t
},
505 {'v', tm_tag_variable_t
},
506 {'E', tm_tag_field_t
},
507 {'f', tm_tag_function_t
},
508 {'p', tm_tag_undef_t
},
509 {'t', tm_tag_typedef_t
},
510 {'s', tm_tag_struct_t
},
511 {'e', tm_tag_enum_t
},
512 {'M', tm_tag_macro_t
},
513 {'C', tm_tag_undef_t
},
516 static TMParserMapEntry map_ASCIIDOC
[] = {
517 {'c', tm_tag_namespace_t
},
518 {'s', tm_tag_member_t
},
519 {'S', tm_tag_macro_t
},
520 {'t', tm_tag_variable_t
},
521 {'T', tm_tag_struct_t
},
522 {'u', tm_tag_undef_t
},
523 {'a', tm_tag_undef_t
},
526 static TMParserMapEntry map_ABAQUS
[] = {
527 {'p', tm_tag_class_t
},
528 {'a', tm_tag_member_t
},
529 {'s', tm_tag_interface_t
},
532 static TMParserMapEntry map_RUST
[] = {
533 {'n', tm_tag_namespace_t
},
534 {'s', tm_tag_struct_t
},
535 {'i', tm_tag_interface_t
},
536 {'c', tm_tag_class_t
},
537 {'f', tm_tag_function_t
},
538 {'g', tm_tag_enum_t
},
539 {'t', tm_tag_typedef_t
},
540 {'v', tm_tag_variable_t
},
541 {'M', tm_tag_macro_t
},
542 {'m', tm_tag_field_t
},
543 {'e', tm_tag_enumerator_t
},
544 {'P', tm_tag_method_t
},
547 static TMParserMapEntry map_GO
[] = {
548 {'p', tm_tag_namespace_t
},
549 {'f', tm_tag_function_t
},
550 {'c', tm_tag_macro_t
},
551 {'t', tm_tag_typedef_t
},
552 {'v', tm_tag_variable_t
},
553 {'s', tm_tag_struct_t
},
554 {'i', tm_tag_interface_t
},
555 {'m', tm_tag_member_t
},
556 {'M', tm_tag_undef_t
},
557 {'n', tm_tag_undef_t
},
558 {'u', tm_tag_undef_t
},
559 {'P', tm_tag_undef_t
},
560 {'a', tm_tag_undef_t
},
561 {'R', tm_tag_undef_t
},
564 static TMParserMapEntry map_JSON
[] = {
565 {'o', tm_tag_member_t
},
566 {'a', tm_tag_member_t
},
567 {'n', tm_tag_member_t
},
568 {'s', tm_tag_member_t
},
569 {'b', tm_tag_member_t
},
570 {'z', tm_tag_member_t
},
573 /* Zephir, same as PHP */
574 #define map_ZEPHIR map_PHP
576 /* not in universal-ctags */
577 static TMParserMapEntry map_POWERSHELL
[] = {
578 {'f', tm_tag_function_t
},
579 {'v', tm_tag_variable_t
},
582 static TMParserMapEntry map_JULIA
[] = {
583 {'c', tm_tag_variable_t
},
584 {'f', tm_tag_function_t
},
585 {'g', tm_tag_member_t
},
586 {'m', tm_tag_macro_t
},
587 {'n', tm_tag_namespace_t
},
588 {'s', tm_tag_struct_t
},
589 {'t', tm_tag_typedef_t
},
590 /* defined as externvar to get those excluded as forward type in symbols.c:goto_tag()
591 * so we can jump to the real implementation (if known) instead of to the import statement */
592 {'x', tm_tag_externvar_t
},
595 static TMParserMapEntry map_CPREPROCESSOR
[] = {
596 {'d', tm_tag_undef_t
},
597 {'h', tm_tag_undef_t
},
598 {'D', tm_tag_undef_t
},
603 TMParserMapEntry
*entries
;
607 #define MAP_ENTRY(lang) [TM_PARSER_##lang] = {map_##lang, G_N_ELEMENTS(map_##lang)}
609 /* keep in sync with TM_PARSER_* definitions in the header */
610 static TMParserMap parser_map
[] = {
636 MAP_ENTRY(JAVASCRIPT
),
639 MAP_ENTRY(FREEBASIC
),
647 MAP_ENTRY(ACTIONSCRIPT
),
662 MAP_ENTRY(POWERSHELL
),
664 MAP_ENTRY(CPREPROCESSOR
),
666 /* make sure the parser map is consistent and complete */
667 G_STATIC_ASSERT(G_N_ELEMENTS(parser_map
) == TM_PARSER_COUNT
);
670 TMTagType
tm_parser_get_tag_type(gchar kind
, TMParserType lang
)
672 TMParserMap
*map
= &parser_map
[lang
];
675 for (i
= 0; i
< map
->size
; i
++)
677 TMParserMapEntry
*entry
= &map
->entries
[i
];
679 if (entry
->kind
== kind
)
682 return tm_tag_undef_t
;
686 gchar
tm_parser_get_tag_kind(TMTagType type
, TMParserType lang
)
688 TMParserMap
*map
= &parser_map
[lang
];
691 for (i
= 0; i
< map
->size
; i
++)
693 TMParserMapEntry
*entry
= &map
->entries
[i
];
695 if (entry
->type
== type
)
702 static void add_subparser(TMParserType lang
, TMParserType sublang
, TMSubparserMapEntry
*map
, guint map_size
)
706 GHashTable
*lang_map
= g_hash_table_lookup(subparser_map
, GINT_TO_POINTER(lang
));
710 lang_map
= g_hash_table_new(g_direct_hash
, g_direct_equal
);
711 g_hash_table_insert(subparser_map
, GINT_TO_POINTER(lang
), lang_map
);
714 mapping
= g_ptr_array_new();
715 for (i
= 0; i
< map_size
; i
++)
716 g_ptr_array_add(mapping
, &map
[i
]);
718 g_hash_table_insert(lang_map
, GINT_TO_POINTER(sublang
), mapping
);
722 #define SUBPARSER_MAP_ENTRY(lang, sublang, map) add_subparser(TM_PARSER_##lang, TM_PARSER_##sublang, map, G_N_ELEMENTS(map))
724 static void init_subparser_map(void)
726 SUBPARSER_MAP_ENTRY(HTML
, JAVASCRIPT
, subparser_HTML_javascript_map
);
730 TMTagType
tm_parser_get_subparser_type(TMParserType lang
, TMParserType sublang
, TMTagType type
)
733 GHashTable
*lang_map
;
738 subparser_map
= g_hash_table_new(g_direct_hash
, g_direct_equal
);
739 init_subparser_map();
742 lang_map
= g_hash_table_lookup(subparser_map
, GINT_TO_POINTER(lang
));
744 return tm_tag_undef_t
;
746 mapping
= g_hash_table_lookup(lang_map
, GINT_TO_POINTER(sublang
));
748 return tm_tag_undef_t
;
750 for (i
= 0; i
< mapping
->len
; i
++)
752 TMSubparserMapEntry
*entry
= mapping
->pdata
[i
];
753 if (entry
->orig_type
== type
)
754 return entry
->new_type
;
757 return tm_tag_undef_t
;
761 void tm_parser_verify_type_mappings(void)
765 if (TM_PARSER_COUNT
> tm_ctags_get_lang_count())
766 g_error("More parsers defined in Geany than in ctags");
768 for (lang
= 0; lang
< TM_PARSER_COUNT
; lang
++)
770 const gchar
*kinds
= tm_ctags_get_lang_kinds(lang
);
771 TMParserMap
*map
= &parser_map
[lang
];
772 gchar presence_map
[256];
775 if (! map
->entries
|| map
->size
< 1)
776 g_error("No tag types in TM for %s, is the language listed in parser_map?",
777 tm_ctags_get_lang_name(lang
));
779 if (map
->size
!= strlen(kinds
))
780 g_error("Different number of tag types in TM (%d) and ctags (%d) for %s",
781 map
->size
, (int)strlen(kinds
), tm_ctags_get_lang_name(lang
));
783 memset(presence_map
, 0, sizeof(presence_map
));
784 for (i
= 0; i
< map
->size
; i
++)
786 gboolean ctags_found
= FALSE
;
787 gboolean tm_found
= FALSE
;
790 for (j
= 0; j
< map
->size
; j
++)
792 /* check that for every type in TM there's a type in ctags */
793 if (map
->entries
[i
].kind
== kinds
[j
])
795 /* check that for every type in ctags there's a type in TM */
796 if (map
->entries
[j
].kind
== kinds
[i
])
798 if (ctags_found
&& tm_found
)
802 g_error("Tag type '%c' found in TM but not in ctags for %s",
803 map
->entries
[i
].kind
, tm_ctags_get_lang_name(lang
));
805 g_error("Tag type '%c' found in ctags but not in TM for %s",
806 kinds
[i
], tm_ctags_get_lang_name(lang
));
808 presence_map
[(unsigned char) map
->entries
[i
].kind
]++;
811 for (i
= 0; i
< sizeof(presence_map
); i
++)
813 if (presence_map
[i
] > 1)
814 g_error("Duplicate tag type '%c' found for %s",
815 (gchar
)i
, tm_ctags_get_lang_name(lang
));
821 /* When the suffix of 'str' is an operator that should trigger scope
822 * autocompletion, this function should return the length of the operator,
824 gint
tm_parser_scope_autocomplete_suffix(TMParserType lang
, const gchar
*str
)
826 const gchar
*sep
= tm_parser_context_separator(lang
);
828 if (g_str_has_suffix(str
, sep
))
835 if (g_str_has_suffix(str
, "."))
837 else if (g_str_has_suffix(str
, "->"))
839 else if (lang
== TM_PARSER_CPP
&& g_str_has_suffix(str
, "->*"))
848 /* Get the name of constructor method. Arguments of this method will be used
849 * for calltips when creating an object using the class name
850 * (e.g. after the opening brace in 'c = MyClass()' in Python) */
851 const gchar
*tm_parser_get_constructor_method(TMParserType lang
)
857 case TM_PARSER_PYTHON
:
865 /* determine anonymous tags from tag names only when corresponding
866 * ctags information is not available */
867 gboolean
tm_parser_is_anon_name(TMParserType lang
, gchar
*name
)
872 if (sscanf(name
, "__anon%u%c", &i
, &dummy
) == 1) /* uctags tags files */
874 else if (lang
== TM_PARSER_C
|| lang
== TM_PARSER_CPP
) /* legacy Geany tags files */
875 return sscanf(name
, "anon_%*[a-z]_%u%c", &i
, &dummy
) == 1;
876 else if (lang
== TM_PARSER_FORTRAN
|| lang
== TM_PARSER_F77
) /* legacy Geany tags files */
878 return sscanf(name
, "Structure#%u%c", &i
, &dummy
) == 1 ||
879 sscanf(name
, "Interface#%u%c", &i
, &dummy
) == 1 ||
880 sscanf(name
, "Enum#%u%c", &i
, &dummy
) == 1;
886 static gchar
*replace_string_if_present(gchar
*haystack
, gchar
*needle
, gchar
*subst
)
888 if (strstr(haystack
, needle
))
890 gchar
**split
= g_strsplit(haystack
, needle
, -1);
891 gchar
*ret
= g_strjoinv(subst
, split
);
899 /* return updated scope or original scope if no change needed */
900 gchar
*tm_parser_update_scope(TMParserType lang
, gchar
*scope
)
905 case TM_PARSER_ZEPHIR
:
906 /* PHP parser uses two different scope separators but this would
907 * complicate things in Geany so make sure there's just one type */
908 return replace_string_if_present(scope
, "\\", "::");
914 /* whether or not to enable ctags roles for the given language and kind */
915 gboolean
tm_parser_enable_role(TMParserType lang
, gchar kind
)
920 /* 'p' is used both for package definition tags and imported package
921 * tags and we can't tell which is which just by kind. By disabling
922 * roles for this kind, we only get package definition tags. */
923 return kind
== 'p' ? FALSE
: TRUE
;
929 /* whether or not to enable ctags kinds for the given language */
930 gboolean
tm_parser_enable_kind(TMParserType lang
, gchar kind
)
935 if (lang
>= TM_PARSER_COUNT
)
936 /* Fatal error but tm_parser_verify_type_mappings() will provide
937 * better message later */
940 map
= &parser_map
[lang
];
941 for (i
= 0; i
< map
->size
; i
++)
943 if (map
->entries
[i
].kind
== kind
)
944 return map
->entries
[i
].type
!= tm_tag_undef_t
;
950 gchar
*tm_parser_format_variable(TMParserType lang
, const gchar
*name
, const gchar
*type
)
958 return g_strconcat(name
, " ", type
, NULL
);
959 case TM_PARSER_PASCAL
:
960 case TM_PARSER_PYTHON
:
961 return g_strconcat(name
, ": ", type
, NULL
);
963 return g_strconcat(type
, " ", name
, NULL
);
968 gchar
*tm_parser_format_function(TMParserType lang
, const gchar
*fname
, const gchar
*args
,
969 const gchar
*retval
, const gchar
*scope
)
973 if (!args
) /* not a function */
976 str
= g_string_new(NULL
);
980 g_string_append(str
, scope
);
981 g_string_append(str
, tm_parser_context_separator(lang
));
983 g_string_append(str
, fname
);
984 g_string_append_c(str
, ' ');
985 g_string_append(str
, args
);
992 case TM_PARSER_PASCAL
:
993 case TM_PARSER_PYTHON
:
995 /* retval after function */
999 case TM_PARSER_PASCAL
:
1002 case TM_PARSER_PYTHON
:
1009 g_string_append(str
, sep
);
1010 g_string_append(str
, retval
);
1014 /* retval before function */
1015 g_string_prepend_c(str
, ' ');
1016 g_string_prepend(str
, retval
);
1021 return g_string_free(str
, FALSE
);
1025 const gchar
*tm_parser_context_separator(TMParserType lang
)
1029 case TM_PARSER_C
: /* for C++ .h headers or C structs */
1031 case TM_PARSER_GLSL
: /* for structs */
1033 case TM_PARSER_POWERSHELL
:
1034 case TM_PARSER_RUST
:
1035 case TM_PARSER_ZEPHIR
:
1038 case TM_PARSER_TXT2TAGS
:
1041 /* these parsers don't report nested scopes but default "." for scope separator
1042 * might appear in the text so use something more improbable */
1043 case TM_PARSER_ASCIIDOC
:
1044 case TM_PARSER_CONF
:
1045 case TM_PARSER_REST
:
1054 gboolean
tm_parser_has_full_context(TMParserType lang
)
1058 /* These parsers include full hierarchy in the tag scope, separated by tm_parser_context_separator() */
1059 case TM_PARSER_ACTIONSCRIPT
:
1062 case TM_PARSER_CSHARP
:
1063 case TM_PARSER_COBOL
:
1065 case TM_PARSER_FERITE
:
1066 case TM_PARSER_GLSL
:
1068 case TM_PARSER_JAVA
:
1069 case TM_PARSER_JAVASCRIPT
:
1070 case TM_PARSER_JSON
:
1073 case TM_PARSER_POWERSHELL
:
1074 case TM_PARSER_PYTHON
:
1075 case TM_PARSER_RUBY
:
1076 case TM_PARSER_RUST
:
1078 case TM_PARSER_TXT2TAGS
:
1079 case TM_PARSER_VALA
:
1080 case TM_PARSER_ZEPHIR
:
1083 /* These make use of the scope, but don't include nested hierarchy
1084 * (either as a parser limitation or a language semantic) */
1085 case TM_PARSER_ASCIIDOC
:
1086 case TM_PARSER_CONF
:
1087 case TM_PARSER_ERLANG
:
1089 case TM_PARSER_FORTRAN
:
1090 case TM_PARSER_OBJC
:
1091 case TM_PARSER_REST
:
1092 /* Other parsers don't use scope at all (or should be somewhere above) */
1099 gboolean
tm_parser_langs_compatible(TMParserType lang
, TMParserType other
)
1101 if (lang
== TM_PARSER_NONE
|| other
== TM_PARSER_NONE
)
1105 /* Accept CPP tags for C lang and vice versa */
1106 else if (lang
== TM_PARSER_C
&& other
== TM_PARSER_CPP
)
1108 else if (lang
== TM_PARSER_CPP
&& other
== TM_PARSER_C
)