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