Mercurial > sci
comparison scid/theme.c @ 30:43333d18e4b8
scid: document theme
author | David Demelier <markand@malikania.fr> |
---|---|
date | Thu, 04 Aug 2022 14:54:43 +0200 |
parents | 695637f1d8a7 |
children | 081e1c258e64 |
comparison
equal
deleted
inserted
replaced
29:695637f1d8a7 | 30:43333d18e4b8 |
---|---|
1 /* | |
2 * theme.c -- theme management | |
3 * | |
4 * Copyright (c) 2021 David Demelier <markand@malikania.fr> | |
5 * | |
6 * Permission to use, copy, modify, and/or distribute this software for any | |
7 * purpose with or without fee is hereby granted, provided that the above | |
8 * copyright notice and this permission notice appear in all copies. | |
9 * | |
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | |
11 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | |
12 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | |
13 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | |
14 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | |
15 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | |
16 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |
17 */ | |
18 | |
1 #include <assert.h> | 19 #include <assert.h> |
2 #include <errno.h> | 20 #include <errno.h> |
3 #include <limits.h> | 21 #include <limits.h> |
4 #include <string.h> | 22 #include <string.h> |
5 | 23 |
12 #include "theme.h" | 30 #include "theme.h" |
13 #include "util.h" | 31 #include "util.h" |
14 | 32 |
15 #define SIGNATURE DUK_HIDDEN_SYMBOL("File") | 33 #define SIGNATURE DUK_HIDDEN_SYMBOL("File") |
16 | 34 |
17 struct theme { | 35 static struct { |
18 char base[PATH_MAX]; | |
19 duk_context *ctx; | 36 duk_context *ctx; |
20 }; | 37 } theme; |
21 | 38 |
22 /* {{{ mustache support */ | 39 /* {{{ mustache support */ |
23 | 40 |
24 static void | 41 static void |
25 mch_parse_error(int code, const char *msg, unsigned int line, unsigned int col, void *data) | 42 mch_parse_error(int code, const char *msg, unsigned int line, unsigned int col, void *data) |
196 .get_child_by_index = mch_get_child_by_index, | 213 .get_child_by_index = mch_get_child_by_index, |
197 .get_partial = mch_get_partial | 214 .get_partial = mch_get_partial |
198 }; | 215 }; |
199 MUSTACHE_TEMPLATE *tmpl; | 216 MUSTACHE_TEMPLATE *tmpl; |
200 int status; | 217 int status; |
201 | 218 |
202 if (!(tmpl = mustache_compile(input, strlen(input), &parser, (void *)path, 0))) | 219 if (!(tmpl = mustache_compile(input, strlen(input), &parser, (void *)path, 0))) |
203 return -1; | 220 return -1; |
204 | 221 |
205 status = mustache_process(tmpl, &rdr, fp, &pv, doc); | 222 status = mustache_process(tmpl, &rdr, fp, &pv, doc); |
206 mustache_release(tmpl); | 223 mustache_release(tmpl); |
239 json_error_t err; | 256 json_error_t err; |
240 | 257 |
241 if (json && !(doc = json_loads(json, 0, &err))) | 258 if (json && !(doc = json_loads(json, 0, &err))) |
242 return duk_error(ctx, DUK_ERR_ERROR, "%d:%d:%s", err.line, err.column, err.text); | 259 return duk_error(ctx, DUK_ERR_ERROR, "%d:%d:%s", err.line, err.column, err.text); |
243 | 260 |
244 mch_templatize(fp, theme_path(scid.theme, path), doc); | 261 mch_templatize(fp, theme_path(path), doc); |
245 | 262 |
246 if (doc) | 263 if (doc) |
247 json_decref(doc); | 264 json_decref(doc); |
248 | 265 |
249 return 0; | 266 return 0; |
264 }; | 281 }; |
265 | 282 |
266 /* }}} */ | 283 /* }}} */ |
267 | 284 |
268 static char * | 285 static char * |
269 call(struct theme *t, json_t *json, const char *function) | 286 call(const json_t *json, const char *function) |
270 { | 287 { |
271 char *out = NULL, *dump = NULL; | 288 char *out = NULL, *dump; |
272 size_t outsz = 0; | 289 size_t outsz = 0; |
273 FILE *fp = NULL; | 290 FILE *fp; |
274 int nargs = 1; | 291 |
275 | 292 duk_get_global_string(theme.ctx, function); |
276 duk_get_global_string(t->ctx, function); | 293 |
277 | 294 if (duk_is_callable(theme.ctx, -1)) { |
278 if (!duk_is_callable(t->ctx, -1)) | 295 fp = util_open_memstream(&out, &outsz); |
279 goto over; | 296 dump = util_json_dump(json); |
280 if (!(fp = open_memstream(&out, &outsz))) | 297 |
281 goto over; | 298 duk_push_pointer(theme.ctx, fp); |
282 | 299 duk_push_string(theme.ctx, dump); |
283 duk_push_pointer(t->ctx, fp); | 300 duk_json_decode(theme.ctx, -1); |
284 | 301 |
285 if (json && (dump = json_dumps(json, JSON_COMPACT))) { | 302 if (duk_pcall(theme.ctx, 2) != 0) |
286 duk_push_string(t->ctx, dump); | 303 log_warn("theme: %s", duk_safe_to_string(theme.ctx, -1)); |
287 duk_json_decode(t->ctx, -1); | 304 |
288 nargs++; | 305 duk_pop(theme.ctx); |
289 } | |
290 | |
291 if (duk_pcall(t->ctx, nargs) != 0) | |
292 log_warn("theme: %s", duk_safe_to_string(t->ctx, -1)); | |
293 | |
294 over: | |
295 duk_pop(t->ctx); | |
296 | |
297 /* | |
298 * For convenience, otherwise all callers have to check for non-NULL | |
299 * after calling the function. | |
300 */ | |
301 free(dump); | |
302 | |
303 if (fp) | |
304 fclose(fp); | 306 fclose(fp); |
307 free(dump); | |
308 } else | |
309 duk_pop(theme.ctx); | |
310 | |
305 if (!out) | 311 if (!out) |
306 out = util_strdup(""); | 312 out = util_strdup(""); |
307 | 313 |
308 return out; | 314 return out; |
309 } | 315 } |
310 | 316 |
317 void | |
318 theme_open(const char *directory) | |
319 { | |
320 assert(directory); | |
321 | |
322 const char *path; | |
323 char *data; | |
324 | |
325 theme.ctx = duk_create_heap_default(); | |
326 path = theme_path("theme.js"); | |
327 | |
328 if (!(data = util_read(path))) | |
329 log_warn("theme: %s: %s", path, strerror(errno)); | |
330 else { | |
331 if (duk_peval_string(theme.ctx, data) != 0) | |
332 log_warn("theme: %s", duk_safe_to_string(theme.ctx, -1)); | |
333 | |
334 duk_pop(theme.ctx); | |
335 duk_push_object(theme.ctx); | |
336 duk_put_function_list(theme.ctx, -1, functions); | |
337 duk_put_global_string(theme.ctx, "Scid"); | |
338 free(data); | |
339 } | |
340 } | |
341 | |
311 const char * | 342 const char * |
312 theme_path(struct theme *t, const char *filename) | 343 theme_path(const char *filename) |
313 { | 344 { |
314 assert(filename); | 345 assert(filename); |
315 | 346 |
316 /* Build path to the template file. */ | 347 /* Build path to the template file. */ |
317 static _Thread_local char path[PATH_MAX]; | 348 static _Thread_local char path[PATH_MAX]; |
318 | 349 |
319 snprintf(path, sizeof (path), "%s/%s", t->base, filename); | 350 snprintf(path, sizeof (path), "%s/%s", scid.themedir, filename); |
320 | 351 |
321 return path; | 352 return path; |
322 } | 353 } |
323 | 354 |
324 struct theme * | |
325 theme_open(const char *directory) | |
326 { | |
327 assert(directory); | |
328 | |
329 struct theme *t; | |
330 char themefile[PATH_MAX], *data; | |
331 | |
332 t = util_calloc(1, sizeof (*t)); | |
333 t->ctx = duk_create_heap_default(); | |
334 util_strlcpy(t->base, directory, sizeof (t->base)); | |
335 | |
336 /* Open theme.js in the directory. */ | |
337 snprintf(themefile, sizeof (themefile), "%s/theme.js", t->base); | |
338 | |
339 if (!(data = util_read(themefile))) | |
340 log_warn("theme: %s: %s", themefile, strerror(errno)); | |
341 else { | |
342 if (duk_peval_string(t->ctx, data) != 0) | |
343 log_warn("theme: %s", duk_safe_to_string(t->ctx, -1)); | |
344 | |
345 duk_pop(t->ctx); | |
346 duk_push_object(t->ctx); | |
347 duk_put_function_list(t->ctx, -1, functions); | |
348 duk_put_global_string(t->ctx, "Scid"); | |
349 free(data); | |
350 } | |
351 | |
352 return t; | |
353 } | |
354 | |
355 char * | 355 char * |
356 theme_page_index(struct theme *t, json_t *json) | 356 theme_page_index(const json_t *json) |
357 { | 357 { |
358 assert(t); | 358 assert(json); |
359 | 359 |
360 return call(t, json, "onPageIndex"); | 360 return call(json, "onPageIndex"); |
361 } | 361 } |
362 | 362 |
363 char * | 363 char * |
364 theme_page_status(struct theme *t, enum khttp status) | 364 theme_page_status(enum khttp status) |
365 { | 365 { |
366 assert(t); | 366 json_t *doc; |
367 | 367 char *ret; |
368 (void)t; | 368 |
369 (void)status; | 369 doc = util_json_pack("{si}", "status", status); |
370 | 370 ret = call(doc, "onPageStatus"); |
371 #if 0 | 371 |
372 return call(t, json, "onPageStatus"); | 372 json_decref(doc); |
373 #endif | 373 |
374 return "ERROR"; | 374 return ret; |
375 } | 375 } |
376 | 376 |
377 void | 377 void |
378 theme_free(struct theme *t) | 378 theme_free(void) |
379 { | 379 { |
380 assert(t); | 380 duk_destroy_heap(theme.ctx); |
381 | 381 } |
382 duk_destroy_heap(t->ctx); | |
383 } |