xref: /Universal-ctags/parsers/tex-beamer.c (revision 3671ad7255885a0c8f6ff4979d80c70f201ea411)
1 /*
2  *	 Copyright (c) 2020, Masatake YAMATO
3  *
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.
6  *
7  *	 This module contains functions for generating tags for Beamer class of TeX.
8  *   - https://github.com/josephwright/beamer
9  *   - http://mirrors.ibiblio.org/CTAN/macros/latex/contrib/beamer/doc/beameruserguide.pdf
10  *
11  */
12 
13 /*
14  *	 INCLUDE FILES
15  */
16 
17 #include "general.h"  /* must always come first */
18 
19 #include "entry.h"
20 #include "kind.h"
21 #include "parse.h"
22 #include "read.h"
23 #include "tex.h"
24 
25 #include <string.h>
26 
27 
28 /*
29  *	 DATA DECLARATIONS
30  */
31 
32 struct beamerSubparser {
33 	texSubparser tex;
34 	int lastTitleCorkIndex;
35 };
36 
37 enum BamerKind {
38 	K_FRAMETITLE,
39 	K_FRAMESUBTITLE,
40 };
41 
42 
43 /*
44  *	 DATA DEFINITIONS
45  */
46 
47 static kindDefinition beamerKinds[] = {
48 	{ true, 'f', "frametitle", "frametitles" },
49 	{ true, 'g', "framesubtitle", "framesubtitles"},
50 };
51 
52 /* \frametitle<overlay specification>[short frame title]{frame title text} */
53 static struct TexParseStrategy frametitle_strategy[] = {
54 	{
55 		.type = '<',
56 		.flags = TEX_NAME_FLAG_OPTIONAL,
57 		.kindIndex = KIND_GHOST_INDEX,
58 		.name = NULL,
59 	},
60 	{
61 		.type = '[',
62 		.flags = TEX_NAME_FLAG_OPTIONAL|TEX_NAME_FLAG_EXCLUSIVE,
63 		.kindIndex = K_FRAMETITLE,
64 		.roleIndex = ROLE_DEFINITION_INDEX,
65 		.name = NULL,
66 		.unique = false,
67 	},
68 	{
69 		.type = '{',
70 		.flags = TEX_NAME_FLAG_INCLUDING_WHITESPACE,
71 		.kindIndex = K_FRAMETITLE,
72 		.roleIndex = ROLE_DEFINITION_INDEX,
73 		.name = NULL,
74 		.unique = true,
75 		.scopeIndex = CORK_NIL,	/* root scope */
76 	},
77 	{
78 		.type = 0
79 	}
80 };
81 
82 /* \framesubtitle<overlay specification>{frame subtitle text} */
83 static struct TexParseStrategy framesubtitle_strategy[] = {
84 	{
85 		.type = '<',
86 		.flags = TEX_NAME_FLAG_OPTIONAL,
87 		.kindIndex = KIND_GHOST_INDEX,
88 		.name = NULL,
89 	},
90 	{
91 		.type = '{',
92 		.flags = TEX_NAME_FLAG_INCLUDING_WHITESPACE,
93 		.kindIndex = K_FRAMESUBTITLE,
94 		.roleIndex = ROLE_DEFINITION_INDEX,
95 		.name = NULL,
96 		.unique = false,
97 	},
98 	{
99 		.type = 0
100 	}
101 };
102 
103 /*  \begin{frame}<overlay specification>[<default overlay specification>][options]{title}{subtitle}*/
104 static struct TexParseStrategy frame_env_strategy [] = {
105 	{
106 		.type = '<',
107 		.flags = TEX_NAME_FLAG_OPTIONAL,
108 		.kindIndex = KIND_GHOST_INDEX,
109 		.name = NULL,
110 	},
111 	{
112 		.type = '[',
113 		.flags = TEX_NAME_FLAG_OPTIONAL,
114 		.kindIndex = KIND_GHOST_INDEX,
115 		.name = NULL,
116 	},
117 	{
118 		.type = '[',
119 		.flags = TEX_NAME_FLAG_OPTIONAL,
120 		.kindIndex = KIND_GHOST_INDEX,
121 		.name = NULL,
122 	},
123 	{
124 		.type = '{',
125 		.flags = TEX_NAME_FLAG_INCLUDING_WHITESPACE,
126 		.kindIndex = K_FRAMETITLE,
127 		.roleIndex = ROLE_DEFINITION_INDEX,
128 		.unique = true,
129 		.scopeIndex = CORK_NIL,	/* root scope */
130 	},
131 	{
132 		/* This should not be optoinal. */
133 		.type = '{',
134 		.flags = TEX_NAME_FLAG_INCLUDING_WHITESPACE,
135 		.kindIndex = K_FRAMESUBTITLE,
136 		.roleIndex = ROLE_DEFINITION_INDEX,
137 		.name = NULL,
138 		.unique = false,
139 	},
140 	{
141 		.type = 0
142 	}
143 };
144 
145 
146 /*
147  *	 FUNCTION DEFINITIONS
148  */
149 
readIdentifierNotify(texSubparser * s,vString * identifier)150 static  struct TexParseStrategy *readIdentifierNotify (texSubparser *s,
151 													   vString *identifier)
152 {
153 	/* Reject uninteresting identifiers early. */
154 	if (! (vStringLength (identifier) > 10
155 		   && strncmp (vStringValue(identifier), "\\frame", 6) == 0))
156 		return NULL;
157 	else if (vStringLength (identifier) == 11
158 		&& strcmp (vStringValue(identifier), "\\frametitle") == 0)
159 		return frametitle_strategy;
160 	/* strlen("\\framesubtitle") = 14 */
161 	else if (vStringLength (identifier) == 14
162 		&& strcmp (vStringValue(identifier), "\\framesubtitle") == 0)
163 		return framesubtitle_strategy;
164 	else
165 		return NULL;
166 }
167 
inputStart(subparser * s)168 static void inputStart (subparser *s)
169 {
170 	struct beamerSubparser *b = (struct beamerSubparser *)s;
171 	b->lastTitleCorkIndex = CORK_NIL;
172 }
173 
reportStrategicParsing(texSubparser * s,const struct TexParseStrategy * strategy)174 static void reportStrategicParsing (texSubparser *s,
175 									const struct TexParseStrategy *strategy)
176 {
177 	struct beamerSubparser *b = (struct beamerSubparser *)s;
178 
179 	if (strategy == frametitle_strategy)
180 	{
181 		if (strategy [1].corkIndex != CORK_NIL)
182 			b->lastTitleCorkIndex = strategy [1].corkIndex;
183 		else if (strategy [2].corkIndex != CORK_NIL)
184 			b->lastTitleCorkIndex = strategy [2].corkIndex;
185 	}
186 	else if (strategy == framesubtitle_strategy)
187 	{
188 		tagEntryInfo *e = getEntryInCorkQueue (strategy [1].corkIndex);
189 		if (e)
190 			e->extensionFields.scopeIndex = b->lastTitleCorkIndex;
191 	}
192 	else if (strategy == frame_env_strategy)
193 	{
194 		b->lastTitleCorkIndex = CORK_NIL;
195 
196 		if (strategy [3].corkIndex != CORK_NIL)
197 			b->lastTitleCorkIndex = strategy [3].corkIndex;
198 
199 		tagEntryInfo *e = getEntryInCorkQueue (strategy [4].corkIndex);
200 		if (e && b->lastTitleCorkIndex != CORK_NIL)
201 			e->extensionFields.scopeIndex = b->lastTitleCorkIndex;
202 	}
203 }
204 
readEnviromentBeginNotify(texSubparser * s,vString * env)205 static struct TexParseStrategy *readEnviromentBeginNotify (texSubparser *s,
206 														   vString *env)
207 {
208 	if (strcmp (vStringValue (env), "frame") == 0)
209        return frame_env_strategy;
210 	return NULL;
211 }
212 
readEnviromentEndNotify(texSubparser * s,vString * env)213 static bool readEnviromentEndNotify (texSubparser *s,
214 									 vString *env)
215 {
216 	if (strcmp (vStringValue (env), "frame") == 0)
217 	{
218 		struct beamerSubparser *b = (struct beamerSubparser *)s;
219 		tagEntryInfo *e = getEntryInCorkQueue (b->lastTitleCorkIndex);
220 		if (e)
221 			e->extensionFields.endLine = getInputLineNumber ();
222 		return true;
223 	}
224 	return false;
225 }
226 
227 static struct beamerSubparser beamerSubparser = {
228 	.tex = {
229 		.subparser = {
230 			.direction = SUBPARSER_BI_DIRECTION,
231 			.inputStart = inputStart,
232 		},
233 		.readIdentifierNotify = readIdentifierNotify,
234 		.readEnviromentBeginNotify = readEnviromentBeginNotify,
235 		.readEnviromentEndNotify = readEnviromentEndNotify,
236 		.reportStrategicParsing = reportStrategicParsing,
237 	},
238 };
239 
findBeamerTags(void)240 static void findBeamerTags(void)
241 {
242 	scheduleRunningBaseparser (RUN_DEFAULT_SUBPARSERS);
243 }
244 
TexBeamerParser(void)245 extern parserDefinition* TexBeamerParser (void)
246 {
247 	parserDefinition* const def = parserNew("TeXBeamer");
248 
249 	static parserDependency dependencies [] = {
250 		[0] = { DEPTYPE_SUBPARSER, "Tex", &beamerSubparser },
251 	};
252 
253 	def->dependencies = dependencies;
254 	def->dependencyCount = ARRAY_SIZE (dependencies);
255 
256 	def->kindTable = beamerKinds;
257 	def->kindCount = ARRAY_SIZE(beamerKinds);
258 
259 	def->parser = findBeamerTags;
260 	def->useCork = CORK_QUEUE;
261 
262 	return def;
263 }
264