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
},
177 {'s', tm_tag_undef_t
},
180 /* not in universal-ctags */
181 static TMParserMapEntry map_CONF
[] = {
182 {'s', tm_tag_namespace_t
},
183 {'k', tm_tag_macro_t
},
186 static TMParserMapEntry map_SQL
[] = {
187 {'c', tm_tag_undef_t
},
188 {'d', tm_tag_prototype_t
},
189 {'f', tm_tag_function_t
},
190 {'E', tm_tag_field_t
},
191 {'l', tm_tag_undef_t
},
192 {'L', tm_tag_undef_t
},
193 {'P', tm_tag_package_t
},
194 {'p', tm_tag_namespace_t
},
195 {'r', tm_tag_undef_t
},
196 {'s', tm_tag_undef_t
},
197 {'t', tm_tag_class_t
},
198 {'T', tm_tag_macro_t
},
199 {'v', tm_tag_variable_t
},
200 {'i', tm_tag_struct_t
},
201 {'e', tm_tag_undef_t
},
202 {'U', tm_tag_undef_t
},
203 {'R', tm_tag_undef_t
},
204 {'D', tm_tag_undef_t
},
205 {'V', tm_tag_member_t
},
206 {'n', tm_tag_undef_t
},
207 {'x', tm_tag_undef_t
},
208 {'y', tm_tag_undef_t
},
209 {'z', tm_tag_undef_t
},
210 {'C', tm_tag_undef_t
},
213 /* not in universal-ctags */
214 static TMParserMapEntry map_DOCBOOK
[] = {
215 {'f', tm_tag_function_t
},
216 {'c', tm_tag_class_t
},
217 {'m', tm_tag_member_t
},
218 {'d', tm_tag_macro_t
},
219 {'v', tm_tag_variable_t
},
220 {'s', tm_tag_struct_t
},
223 static TMParserMapEntry map_ERLANG
[] = {
224 {'d', tm_tag_macro_t
},
225 {'f', tm_tag_function_t
},
226 {'m', tm_tag_undef_t
},
227 {'r', tm_tag_struct_t
},
228 {'t', tm_tag_typedef_t
},
231 static TMParserMapEntry map_CSS
[] = {
232 {'c', tm_tag_class_t
},
233 {'s', tm_tag_struct_t
},
234 {'i', tm_tag_variable_t
},
237 static TMParserMapEntry map_RUBY
[] = {
238 {'c', tm_tag_class_t
},
239 {'f', tm_tag_method_t
},
240 {'m', tm_tag_namespace_t
},
241 {'S', tm_tag_member_t
},
242 {'C', tm_tag_undef_t
},
243 {'A', tm_tag_undef_t
},
244 {'a', tm_tag_undef_t
},
245 {'L', tm_tag_undef_t
},
248 static TMParserMapEntry map_TCL
[] = {
249 {'c', tm_tag_class_t
},
250 {'m', tm_tag_member_t
},
251 {'p', tm_tag_function_t
},
252 {'n', tm_tag_namespace_t
},
255 static TMParserMapEntry map_SH
[] = {
256 {'a', tm_tag_undef_t
},
257 {'f', tm_tag_function_t
},
258 {'s', tm_tag_undef_t
},
259 {'h', tm_tag_undef_t
},
262 static TMParserMapEntry map_D
[] = {
263 {'c', tm_tag_class_t
},
264 {'e', tm_tag_enumerator_t
},
265 {'f', tm_tag_function_t
},
266 {'g', tm_tag_enum_t
},
267 {'i', tm_tag_interface_t
},
268 {'m', tm_tag_member_t
},
269 {'n', tm_tag_namespace_t
},
270 {'p', tm_tag_prototype_t
},
271 {'s', tm_tag_struct_t
},
272 {'t', tm_tag_typedef_t
},
273 {'u', tm_tag_union_t
},
274 {'v', tm_tag_variable_t
},
275 {'x', tm_tag_externvar_t
},
278 static TMParserMapEntry map_DIFF
[] = {
279 {'m', tm_tag_function_t
},
280 {'n', tm_tag_function_t
},
281 {'d', tm_tag_function_t
},
282 {'h', tm_tag_undef_t
},
285 /* different parser than in universal-ctags */
286 static TMParserMapEntry map_VHDL
[] = {
287 {'c', tm_tag_variable_t
},
288 {'t', tm_tag_typedef_t
},
289 {'v', tm_tag_variable_t
},
290 {'a', tm_tag_undef_t
},
291 {'s', tm_tag_variable_t
},
292 {'f', tm_tag_function_t
},
293 {'p', tm_tag_function_t
},
294 {'k', tm_tag_member_t
},
295 {'l', tm_tag_namespace_t
},
296 {'m', tm_tag_member_t
},
297 {'n', tm_tag_class_t
},
298 {'o', tm_tag_struct_t
},
299 {'u', tm_tag_undef_t
},
300 {'b', tm_tag_member_t
},
301 {'A', tm_tag_typedef_t
},
304 static TMParserMapEntry map_LUA
[] = {
305 {'f', tm_tag_function_t
},
306 {'X', tm_tag_undef_t
},
309 static TMParserMapEntry map_JAVASCRIPT
[] = {
310 {'f', tm_tag_function_t
},
311 {'c', tm_tag_class_t
},
312 {'m', tm_tag_method_t
},
313 {'p', tm_tag_member_t
},
314 {'C', tm_tag_macro_t
},
315 {'v', tm_tag_variable_t
},
316 {'g', tm_tag_function_t
},
317 {'G', tm_tag_undef_t
},
318 {'S', tm_tag_undef_t
},
319 {'M', tm_tag_undef_t
},
322 static TMParserMapEntry map_HASKELL
[] = {
323 {'t', tm_tag_typedef_t
},
324 {'c', tm_tag_macro_t
},
325 {'f', tm_tag_function_t
},
326 {'m', tm_tag_namespace_t
},
329 static TMParserMapEntry map_CSHARP
[] = {
330 {'c', tm_tag_class_t
},
331 {'d', tm_tag_macro_t
},
332 {'e', tm_tag_enumerator_t
},
333 {'E', tm_tag_undef_t
},
334 {'f', tm_tag_field_t
},
335 {'g', tm_tag_enum_t
},
336 {'i', tm_tag_interface_t
},
337 {'l', tm_tag_undef_t
},
338 {'m', tm_tag_method_t
},
339 {'n', tm_tag_namespace_t
},
340 {'p', tm_tag_undef_t
},
341 {'s', tm_tag_struct_t
},
342 {'t', tm_tag_typedef_t
},
345 static TMParserMapEntry map_FREEBASIC
[] = {
346 {'c', tm_tag_macro_t
},
347 {'f', tm_tag_function_t
},
348 {'l', tm_tag_namespace_t
},
349 {'t', tm_tag_struct_t
},
350 {'v', tm_tag_variable_t
},
351 {'g', tm_tag_externvar_t
},
354 static TMParserMapEntry map_HAXE
[] = {
355 {'m', tm_tag_method_t
},
356 {'c', tm_tag_class_t
},
357 {'e', tm_tag_enum_t
},
358 {'v', tm_tag_variable_t
},
359 {'i', tm_tag_interface_t
},
360 {'t', tm_tag_typedef_t
},
363 static TMParserMapEntry map_REST
[] = {
364 {'c', tm_tag_namespace_t
},
365 {'s', tm_tag_member_t
},
366 {'S', tm_tag_macro_t
},
367 {'t', tm_tag_variable_t
},
368 {'C', tm_tag_undef_t
},
369 {'T', tm_tag_undef_t
},
370 {'d', tm_tag_undef_t
},
373 static TMParserMapEntry map_HTML
[] = {
374 {'a', tm_tag_member_t
},
375 {'c', tm_tag_undef_t
},
376 {'h', tm_tag_namespace_t
},
377 {'i', tm_tag_class_t
},
378 {'j', tm_tag_variable_t
},
379 {'C', tm_tag_undef_t
},
380 {'I', tm_tag_undef_t
},
381 {'J', tm_tag_undef_t
},
384 static TMSubparserMapEntry subparser_HTML_javascript_map
[] = {
385 {tm_tag_function_t
, tm_tag_function_t
},
388 static TMParserMapEntry map_F77
[] = {
389 {'b', tm_tag_undef_t
},
390 {'c', tm_tag_macro_t
},
391 {'e', tm_tag_undef_t
},
392 {'f', tm_tag_function_t
},
393 {'i', tm_tag_interface_t
},
394 {'k', tm_tag_member_t
},
395 {'l', tm_tag_undef_t
},
396 {'L', tm_tag_undef_t
},
397 {'m', tm_tag_namespace_t
},
398 {'n', tm_tag_undef_t
},
399 {'p', tm_tag_struct_t
},
400 {'s', tm_tag_method_t
},
401 {'t', tm_tag_class_t
},
402 {'v', tm_tag_variable_t
},
403 {'E', tm_tag_enum_t
},
404 {'N', tm_tag_enumerator_t
},
407 #define map_FORTRAN map_F77
409 /* different parser than in universal-ctags */
410 static TMParserMapEntry map_MATLAB
[] = {
411 {'f', tm_tag_function_t
},
412 {'s', tm_tag_struct_t
},
415 #define map_CUDA map_C
417 /* not in universal-ctags */
418 static TMParserMapEntry map_VALA
[] = {
419 {'c', tm_tag_class_t
},
420 {'d', tm_tag_macro_t
},
421 {'e', tm_tag_enumerator_t
},
422 {'f', tm_tag_field_t
},
423 {'g', tm_tag_enum_t
},
424 {'i', tm_tag_interface_t
},
425 {'l', tm_tag_undef_t
},
426 {'m', tm_tag_method_t
},
427 {'n', tm_tag_namespace_t
},
428 {'p', tm_tag_undef_t
},
429 {'S', tm_tag_undef_t
},
430 {'s', tm_tag_struct_t
},
433 /* not in universal-ctags */
434 static TMParserMapEntry map_ACTIONSCRIPT
[] = {
435 {'f', tm_tag_function_t
},
436 {'c', tm_tag_class_t
},
437 {'i', tm_tag_interface_t
},
438 {'P', tm_tag_package_t
},
439 {'m', tm_tag_method_t
},
440 {'p', tm_tag_member_t
},
441 {'v', tm_tag_variable_t
},
442 {'l', tm_tag_variable_t
},
443 {'C', tm_tag_macro_t
},
444 {'I', tm_tag_externvar_t
},
445 {'x', tm_tag_other_t
},
448 static TMParserMapEntry map_NSIS
[] = {
449 {'s', tm_tag_namespace_t
},
450 {'f', tm_tag_function_t
},
451 {'v', tm_tag_variable_t
},
452 {'d', tm_tag_undef_t
},
453 {'m', tm_tag_undef_t
},
454 {'S', tm_tag_undef_t
},
455 {'p', tm_tag_undef_t
},
456 {'l', tm_tag_undef_t
},
457 {'i', tm_tag_undef_t
},
460 /* not in universal-ctags */
461 static TMParserMapEntry map_MARKDOWN
[] = {
462 {'v', tm_tag_variable_t
},
465 static TMParserMapEntry map_TXT2TAGS
[] = {
466 {'s', tm_tag_member_t
},
469 static TMParserMapEntry map_ABC
[] = {
470 {'s', tm_tag_member_t
},
473 static TMParserMapEntry map_VERILOG
[] = {
474 {'c', tm_tag_variable_t
},
475 {'e', tm_tag_typedef_t
},
476 {'f', tm_tag_function_t
},
477 {'m', tm_tag_class_t
},
478 {'n', tm_tag_variable_t
},
479 {'p', tm_tag_variable_t
},
480 {'r', tm_tag_variable_t
},
481 {'t', tm_tag_function_t
},
482 {'b', tm_tag_undef_t
},
483 {'i', tm_tag_undef_t
},
486 static TMParserMapEntry map_R
[] = {
487 {'f', tm_tag_function_t
},
488 {'l', tm_tag_other_t
},
489 {'s', tm_tag_other_t
},
490 {'g', tm_tag_undef_t
},
491 {'v', tm_tag_undef_t
},
492 {'z', tm_tag_undef_t
},
493 {'c', tm_tag_undef_t
},
494 {'L', tm_tag_undef_t
},
495 {'d', tm_tag_undef_t
},
496 {'n', tm_tag_undef_t
},
499 static TMParserMapEntry map_COBOL
[] = {
500 {'d', tm_tag_variable_t
},
501 {'D', tm_tag_interface_t
},
502 {'f', tm_tag_function_t
},
503 {'g', tm_tag_struct_t
},
504 {'p', tm_tag_macro_t
},
505 {'P', tm_tag_class_t
},
506 {'s', tm_tag_namespace_t
},
507 {'S', tm_tag_externvar_t
},
510 static TMParserMapEntry map_OBJC
[] = {
511 {'i', tm_tag_interface_t
},
512 {'I', tm_tag_undef_t
},
513 {'P', tm_tag_undef_t
},
514 {'m', tm_tag_method_t
},
515 {'c', tm_tag_class_t
},
516 {'v', tm_tag_variable_t
},
517 {'E', tm_tag_field_t
},
518 {'f', tm_tag_function_t
},
519 {'p', tm_tag_undef_t
},
520 {'t', tm_tag_typedef_t
},
521 {'s', tm_tag_struct_t
},
522 {'e', tm_tag_enum_t
},
523 {'M', tm_tag_macro_t
},
524 {'C', tm_tag_undef_t
},
527 static TMParserMapEntry map_ASCIIDOC
[] = {
528 {'c', tm_tag_namespace_t
},
529 {'s', tm_tag_member_t
},
530 {'S', tm_tag_macro_t
},
531 {'t', tm_tag_variable_t
},
532 {'T', tm_tag_struct_t
},
533 {'u', tm_tag_undef_t
},
534 {'a', tm_tag_undef_t
},
537 static TMParserMapEntry map_ABAQUS
[] = {
538 {'p', tm_tag_class_t
},
539 {'a', tm_tag_member_t
},
540 {'s', tm_tag_interface_t
},
543 static TMParserMapEntry map_RUST
[] = {
544 {'n', tm_tag_namespace_t
},
545 {'s', tm_tag_struct_t
},
546 {'i', tm_tag_interface_t
},
547 {'c', tm_tag_class_t
},
548 {'f', tm_tag_function_t
},
549 {'g', tm_tag_enum_t
},
550 {'t', tm_tag_typedef_t
},
551 {'v', tm_tag_variable_t
},
552 {'M', tm_tag_macro_t
},
553 {'m', tm_tag_field_t
},
554 {'e', tm_tag_enumerator_t
},
555 {'P', tm_tag_method_t
},
558 static TMParserMapEntry map_GO
[] = {
559 {'p', tm_tag_namespace_t
},
560 {'f', tm_tag_function_t
},
561 {'c', tm_tag_macro_t
},
562 {'t', tm_tag_typedef_t
},
563 {'v', tm_tag_variable_t
},
564 {'s', tm_tag_struct_t
},
565 {'i', tm_tag_interface_t
},
566 {'m', tm_tag_member_t
},
567 {'M', tm_tag_undef_t
},
568 {'n', tm_tag_undef_t
},
569 {'u', tm_tag_undef_t
},
570 {'P', tm_tag_undef_t
},
571 {'a', tm_tag_undef_t
},
572 {'R', tm_tag_undef_t
},
575 static TMParserMapEntry map_JSON
[] = {
576 {'o', tm_tag_member_t
},
577 {'a', tm_tag_member_t
},
578 {'n', tm_tag_member_t
},
579 {'s', tm_tag_member_t
},
580 {'b', tm_tag_member_t
},
581 {'z', tm_tag_member_t
},
584 /* Zephir, same as PHP */
585 #define map_ZEPHIR map_PHP
587 /* not in universal-ctags */
588 static TMParserMapEntry map_POWERSHELL
[] = {
589 {'f', tm_tag_function_t
},
590 {'v', tm_tag_variable_t
},
593 static TMParserMapEntry map_JULIA
[] = {
594 {'c', tm_tag_variable_t
},
595 {'f', tm_tag_function_t
},
596 {'g', tm_tag_member_t
},
597 {'m', tm_tag_macro_t
},
598 {'n', tm_tag_namespace_t
},
599 {'s', tm_tag_struct_t
},
600 {'t', tm_tag_typedef_t
},
601 /* defined as externvar to get those excluded as forward type in symbols.c:goto_tag()
602 * so we can jump to the real implementation (if known) instead of to the import statement */
603 {'x', tm_tag_externvar_t
},
606 static TMParserMapEntry map_CPREPROCESSOR
[] = {
607 {'d', tm_tag_undef_t
},
608 {'h', tm_tag_undef_t
},
609 {'D', tm_tag_undef_t
},
611 static TMParserMapEntry map_GDSCRIPT
[] = {
612 {'c', tm_tag_class_t
},
613 {'m', tm_tag_method_t
},
614 {'v', tm_tag_variable_t
},
615 {'C', tm_tag_variable_t
},
616 {'g', tm_tag_enum_t
},
617 {'e', tm_tag_variable_t
},
618 {'z', tm_tag_other_t
},
619 {'l', tm_tag_other_t
},
620 {'s', tm_tag_variable_t
},
625 TMParserMapEntry
*entries
;
629 #define MAP_ENTRY(lang) [TM_PARSER_##lang] = {map_##lang, G_N_ELEMENTS(map_##lang)}
631 /* keep in sync with TM_PARSER_* definitions in the header */
632 static TMParserMap parser_map
[] = {
658 MAP_ENTRY(JAVASCRIPT
),
661 MAP_ENTRY(FREEBASIC
),
669 MAP_ENTRY(ACTIONSCRIPT
),
684 MAP_ENTRY(POWERSHELL
),
686 MAP_ENTRY(CPREPROCESSOR
),
688 /* make sure the parser map is consistent and complete */
689 G_STATIC_ASSERT(G_N_ELEMENTS(parser_map
) == TM_PARSER_COUNT
);
692 TMTagType
tm_parser_get_tag_type(gchar kind
, TMParserType lang
)
694 TMParserMap
*map
= &parser_map
[lang
];
697 for (i
= 0; i
< map
->size
; i
++)
699 TMParserMapEntry
*entry
= &map
->entries
[i
];
701 if (entry
->kind
== kind
)
704 return tm_tag_undef_t
;
708 gchar
tm_parser_get_tag_kind(TMTagType type
, TMParserType lang
)
710 TMParserMap
*map
= &parser_map
[lang
];
713 for (i
= 0; i
< map
->size
; i
++)
715 TMParserMapEntry
*entry
= &map
->entries
[i
];
717 if (entry
->type
== type
)
724 static void add_subparser(TMParserType lang
, TMParserType sublang
, TMSubparserMapEntry
*map
, guint map_size
)
728 GHashTable
*lang_map
= g_hash_table_lookup(subparser_map
, GINT_TO_POINTER(lang
));
732 lang_map
= g_hash_table_new(g_direct_hash
, g_direct_equal
);
733 g_hash_table_insert(subparser_map
, GINT_TO_POINTER(lang
), lang_map
);
736 mapping
= g_ptr_array_new();
737 for (i
= 0; i
< map_size
; i
++)
738 g_ptr_array_add(mapping
, &map
[i
]);
740 g_hash_table_insert(lang_map
, GINT_TO_POINTER(sublang
), mapping
);
744 #define SUBPARSER_MAP_ENTRY(lang, sublang, map) add_subparser(TM_PARSER_##lang, TM_PARSER_##sublang, map, G_N_ELEMENTS(map))
746 static void init_subparser_map(void)
748 SUBPARSER_MAP_ENTRY(HTML
, JAVASCRIPT
, subparser_HTML_javascript_map
);
752 TMTagType
tm_parser_get_subparser_type(TMParserType lang
, TMParserType sublang
, TMTagType type
)
755 GHashTable
*lang_map
;
760 subparser_map
= g_hash_table_new(g_direct_hash
, g_direct_equal
);
761 init_subparser_map();
764 lang_map
= g_hash_table_lookup(subparser_map
, GINT_TO_POINTER(lang
));
766 return tm_tag_undef_t
;
768 mapping
= g_hash_table_lookup(lang_map
, GINT_TO_POINTER(sublang
));
770 return tm_tag_undef_t
;
772 for (i
= 0; i
< mapping
->len
; i
++)
774 TMSubparserMapEntry
*entry
= mapping
->pdata
[i
];
775 if (entry
->orig_type
== type
)
776 return entry
->new_type
;
779 return tm_tag_undef_t
;
783 void tm_parser_verify_type_mappings(void)
787 if (TM_PARSER_COUNT
> tm_ctags_get_lang_count())
788 g_error("More parsers defined in Geany than in ctags");
790 for (lang
= 0; lang
< TM_PARSER_COUNT
; lang
++)
792 const gchar
*kinds
= tm_ctags_get_lang_kinds(lang
);
793 TMParserMap
*map
= &parser_map
[lang
];
794 gchar presence_map
[256];
797 if (! map
->entries
|| map
->size
< 1)
798 g_error("No tag types in TM for %s, is the language listed in parser_map?",
799 tm_ctags_get_lang_name(lang
));
801 if (map
->size
!= strlen(kinds
))
802 g_error("Different number of tag types in TM (%d) and ctags (%d) for %s",
803 map
->size
, (int)strlen(kinds
), tm_ctags_get_lang_name(lang
));
805 memset(presence_map
, 0, sizeof(presence_map
));
806 for (i
= 0; i
< map
->size
; i
++)
808 gboolean ctags_found
= FALSE
;
809 gboolean tm_found
= FALSE
;
812 for (j
= 0; j
< map
->size
; j
++)
814 /* check that for every type in TM there's a type in ctags */
815 if (map
->entries
[i
].kind
== kinds
[j
])
817 /* check that for every type in ctags there's a type in TM */
818 if (map
->entries
[j
].kind
== kinds
[i
])
820 if (ctags_found
&& tm_found
)
824 g_error("Tag type '%c' found in TM but not in ctags for %s",
825 map
->entries
[i
].kind
, tm_ctags_get_lang_name(lang
));
827 g_error("Tag type '%c' found in ctags but not in TM for %s",
828 kinds
[i
], tm_ctags_get_lang_name(lang
));
830 presence_map
[(unsigned char) map
->entries
[i
].kind
]++;
833 for (i
= 0; i
< sizeof(presence_map
); i
++)
835 if (presence_map
[i
] > 1)
836 g_error("Duplicate tag type '%c' found for %s",
837 (gchar
)i
, tm_ctags_get_lang_name(lang
));
843 /* When the suffix of 'str' is an operator that should trigger scope
844 * autocompletion, this function should return the length of the operator,
846 gint
tm_parser_scope_autocomplete_suffix(TMParserType lang
, const gchar
*str
)
848 const gchar
*sep
= tm_parser_scope_separator(lang
);
850 if (g_str_has_suffix(str
, sep
))
857 if (g_str_has_suffix(str
, "."))
859 else if (g_str_has_suffix(str
, "->"))
861 else if (lang
== TM_PARSER_CPP
&& g_str_has_suffix(str
, "->*"))
870 /* Get the name of constructor method. Arguments of this method will be used
871 * for calltips when creating an object using the class name
872 * (e.g. after the opening brace in 'c = MyClass()' in Python) */
873 const gchar
*tm_parser_get_constructor_method(TMParserType lang
)
879 case TM_PARSER_PYTHON
:
887 /* determine anonymous tags from tag names only when corresponding
888 * ctags information is not available */
889 gboolean
tm_parser_is_anon_name(TMParserType lang
, gchar
*name
)
894 if (sscanf(name
, "__anon%u%c", &i
, &dummy
) == 1) /* uctags tags files */
896 else if (lang
== TM_PARSER_C
|| lang
== TM_PARSER_CPP
) /* legacy Geany tags files */
897 return sscanf(name
, "anon_%*[a-z]_%u%c", &i
, &dummy
) == 1;
898 else if (lang
== TM_PARSER_FORTRAN
|| lang
== TM_PARSER_F77
) /* legacy Geany tags files */
900 return sscanf(name
, "Structure#%u%c", &i
, &dummy
) == 1 ||
901 sscanf(name
, "Interface#%u%c", &i
, &dummy
) == 1 ||
902 sscanf(name
, "Enum#%u%c", &i
, &dummy
) == 1;
908 static gchar
*replace_string_if_present(gchar
*haystack
, gchar
*needle
, gchar
*subst
)
910 if (strstr(haystack
, needle
))
912 gchar
**split
= g_strsplit(haystack
, needle
, -1);
913 gchar
*ret
= g_strjoinv(subst
, split
);
921 /* return updated scope or original scope if no change needed */
922 gchar
*tm_parser_update_scope(TMParserType lang
, gchar
*scope
)
927 case TM_PARSER_ZEPHIR
:
928 /* PHP parser uses two different scope separators but this would
929 * complicate things in Geany so make sure there's just one type */
930 return replace_string_if_present(scope
, "\\", "::");
936 /* whether or not to enable ctags roles for the given language and kind */
937 gboolean
tm_parser_enable_role(TMParserType lang
, gchar kind
)
941 case TM_PARSER_GDSCRIPT
:
942 return kind
== 'c' ? FALSE
: TRUE
;
944 /* 'p' is used both for package definition tags and imported package
945 * tags and we can't tell which is which just by kind. By disabling
946 * roles for this kind, we only get package definition tags. */
947 return kind
== 'p' ? FALSE
: TRUE
;
953 /* whether or not to enable ctags kinds for the given language */
954 gboolean
tm_parser_enable_kind(TMParserType lang
, gchar kind
)
959 if (lang
>= TM_PARSER_COUNT
)
960 /* Fatal error but tm_parser_verify_type_mappings() will provide
961 * better message later */
964 map
= &parser_map
[lang
];
965 for (i
= 0; i
< map
->size
; i
++)
967 if (map
->entries
[i
].kind
== kind
)
968 return map
->entries
[i
].type
!= tm_tag_undef_t
;
974 gchar
*tm_parser_format_variable(TMParserType lang
, const gchar
*name
, const gchar
*type
)
982 return g_strconcat(name
, " ", type
, NULL
);
983 case TM_PARSER_PASCAL
:
984 case TM_PARSER_PYTHON
:
985 return g_strconcat(name
, ": ", type
, NULL
);
987 return g_strconcat(type
, " ", name
, NULL
);
992 gchar
*tm_parser_format_function(TMParserType lang
, const gchar
*fname
, const gchar
*args
,
993 const gchar
*retval
, const gchar
*scope
)
997 if (!args
) /* not a function */
1000 str
= g_string_new(NULL
);
1004 g_string_append(str
, scope
);
1005 g_string_append(str
, tm_parser_scope_separator_printable(lang
));
1007 g_string_append(str
, fname
);
1008 g_string_append_c(str
, ' ');
1009 g_string_append(str
, args
);
1015 case TM_PARSER_GDSCRIPT
:
1017 case TM_PARSER_PASCAL
:
1018 case TM_PARSER_PYTHON
:
1020 /* retval after function */
1024 case TM_PARSER_PASCAL
:
1027 case TM_PARSER_GDSCRIPT
:
1028 case TM_PARSER_PYTHON
:
1035 g_string_append(str
, sep
);
1036 g_string_append(str
, retval
);
1040 /* retval before function */
1041 g_string_prepend_c(str
, ' ');
1042 g_string_prepend(str
, retval
);
1047 return g_string_free(str
, FALSE
);
1051 const gchar
*tm_parser_scope_separator(TMParserType lang
)
1055 case TM_PARSER_C
: /* for C++ .h headers or C structs */
1057 case TM_PARSER_CUDA
:
1059 case TM_PARSER_POWERSHELL
:
1060 case TM_PARSER_RUST
:
1061 case TM_PARSER_ZEPHIR
:
1064 case TM_PARSER_TXT2TAGS
:
1067 /* these parsers don't report nested scopes but default "." for scope separator
1068 * might appear in the text so use something more improbable */
1069 case TM_PARSER_ASCIIDOC
:
1070 case TM_PARSER_CONF
:
1071 case TM_PARSER_REST
:
1080 const gchar
*tm_parser_scope_separator_printable(TMParserType lang
)
1084 case TM_PARSER_TXT2TAGS
:
1085 case TM_PARSER_ASCIIDOC
:
1086 case TM_PARSER_CONF
:
1087 case TM_PARSER_REST
:
1091 return tm_parser_scope_separator(lang
);
1096 gboolean
tm_parser_has_full_scope(TMParserType lang
)
1100 /* These parsers include full hierarchy in the tag scope, separated by tm_parser_scope_separator() */
1101 case TM_PARSER_ACTIONSCRIPT
:
1104 case TM_PARSER_CUDA
:
1105 case TM_PARSER_CSHARP
:
1106 case TM_PARSER_COBOL
:
1108 case TM_PARSER_GDSCRIPT
:
1110 case TM_PARSER_JAVA
:
1111 case TM_PARSER_JAVASCRIPT
:
1112 case TM_PARSER_JSON
:
1115 case TM_PARSER_POWERSHELL
:
1116 case TM_PARSER_PYTHON
:
1118 case TM_PARSER_RUBY
:
1119 case TM_PARSER_RUST
:
1121 case TM_PARSER_TXT2TAGS
:
1122 case TM_PARSER_VALA
:
1123 case TM_PARSER_VERILOG
:
1124 case TM_PARSER_ZEPHIR
:
1127 /* These make use of the scope, but don't include nested hierarchy
1128 * (either as a parser limitation or a language semantic) */
1129 case TM_PARSER_ASCIIDOC
:
1130 case TM_PARSER_CONF
:
1131 case TM_PARSER_ERLANG
:
1133 case TM_PARSER_FORTRAN
:
1134 case TM_PARSER_OBJC
:
1135 case TM_PARSER_REST
:
1136 /* Other parsers don't use scope at all (or should be somewhere above) */
1143 gboolean
tm_parser_langs_compatible(TMParserType lang
, TMParserType other
)
1145 if (lang
== TM_PARSER_NONE
|| other
== TM_PARSER_NONE
)
1149 /* Accept CPP tags for C lang and vice versa */
1150 else if (lang
== TM_PARSER_C
&& other
== TM_PARSER_CPP
)
1152 else if (lang
== TM_PARSER_CPP
&& other
== TM_PARSER_C
)