From f5f04edbf832aa2e219c621b9895c33dce3e47ba Mon Sep 17 00:00:00 2001 From: Danny van Kooten Date: Tue, 17 Mar 2020 16:12:55 +0100 Subject: first stab at supporting template inheritance --- src/template.c | 68 ++++++++++++++++++++++++++++++++++++++++++++---- src/template.h | 5 ++++ tests/data/01/base.tmpl | 9 +++++++ tests/data/01/child.tmpl | 5 ++++ tests/test_template.c | 8 ++++++ 5 files changed, 90 insertions(+), 5 deletions(-) create mode 100644 tests/data/01/base.tmpl create mode 100644 tests/data/01/child.tmpl diff --git a/src/template.c b/src/template.c index 7aa3a75..c43827a 100644 --- a/src/template.c +++ b/src/template.c @@ -1,6 +1,8 @@ #include #include #include +#include +#include #include "vendor/mpc.h" #include "template.h" @@ -26,6 +28,11 @@ struct buffer { char *string; }; +struct env { + struct hashmap *templates; +}; + +/* ensure buffer has room for a string sized l, grows buffer capacity if needed */ void buffer_reserve(struct buffer *buf, int l) { int req_size = buf->size + l; if (req_size >= buf->cap) { @@ -40,14 +47,44 @@ void buffer_reserve(struct buffer *buf, int l) { } } +struct env *env_new(char *dirname) { + DIR *dr = opendir(dirname); + if (dr == NULL) { + err(EXIT_FAILURE, "could not open directory %s", dirname); + } + + struct env *env = malloc(sizeof *env); + env->templates = hashmap_new(); + chdir(dirname); + + struct dirent *de; + while ((de = readdir(dr)) != NULL) { + // skip files starting with a dot + if (de->d_name[0] == '.') { + continue; + } + + char *name = de->d_name; + char *tmpl = read_file(name); + hashmap_insert(env->templates, name, tmpl); + } + + closedir(dr); + return env; +} + +void env_free(struct env *env) { + // TODO: Free template strings + free(env); +} + char *read_file(char *filename) { char *input = malloc(BUFSIZ); unsigned int size = 0; FILE *f = fopen(filename, "r"); if (!f) { - printf("Could not open \"%s\" for reading", filename); - exit(1); + err(EXIT_FAILURE, "Could not open \"%s\" for reading", filename); } unsigned int read = 0; @@ -217,6 +254,20 @@ struct unja_object *eval_expression(mpc_ast_t* expr, struct hashmap *ctx) { int eval(struct buffer *buf, mpc_ast_t* t, struct hashmap *ctx) { static int trim_whitespace = 0; + + if (strstr(t->tag, "content|statement|extends")) { + char *template_name = t->children[2]->children[1]->contents; + // TODO: Render given template instead + // but replace blocks with blocks in current template + return 0; + } + + + if (strstr(t->tag, "content|statement|block")) { + char *block_name = t->children[2]->contents; + return eval(buf, t->children[4], ctx); + } + // eval print statement if (strstr(t->tag, "content|print")) { // maybe eat whitespace going backward @@ -275,8 +326,11 @@ int eval(struct buffer *buf, mpc_ast_t* t, struct hashmap *ctx) { return 0; } - for (int i=0; i < t->children_num; i++) { - eval(buf, t->children[i], ctx); + + if (strstr(t->tag, ">")) { + for (int i=0; i < t->children_num; i++) { + eval(buf, t->children[i], ctx); + } } return 0; @@ -318,7 +372,7 @@ mpc_parser_t *parser_init() { " statement_open: \"{%\" /-? */;" " statement_close: / *-?/ \"%}\";" " for : \"for \" \"in\" \"endfor\" ;" - " block : \"block \" \"endblock\" ;" + " block : \"block \" \"endblock\" ;" " extends : \"extends \" ;" " if : \"if \" ( \"else\" )? \"endif\" ;" " statement : | | | ;" @@ -375,3 +429,7 @@ char *template(char *tmpl, struct hashmap *ctx) { return buf.string; } +char *render(struct env *env, char *template_name, struct hashmap *ctx) { + char *tmpl = hashmap_get(env->templates, template_name); + return template(tmpl, ctx); +} \ No newline at end of file diff --git a/src/template.h b/src/template.h index 36d540d..f65da47 100644 --- a/src/template.h +++ b/src/template.h @@ -3,3 +3,8 @@ char *read_file(char *filename); char *template(char *tmpl, struct hashmap *ctx); + +struct env; +struct env *env_new(); +void env_free(struct env *env); +char *render(struct env *env, char *template_name, struct hashmap *ctx); \ No newline at end of file diff --git a/tests/data/01/base.tmpl b/tests/data/01/base.tmpl new file mode 100644 index 0000000..6ca89cb --- /dev/null +++ b/tests/data/01/base.tmpl @@ -0,0 +1,9 @@ +Header + +{% block content %} +Content +{% endblock %} + +{% block footer %} +Footer +{% endblock %} \ No newline at end of file diff --git a/tests/data/01/child.tmpl b/tests/data/01/child.tmpl new file mode 100644 index 0000000..05467a6 --- /dev/null +++ b/tests/data/01/child.tmpl @@ -0,0 +1,5 @@ +{% extends "base.tmpl" %} + +{% block content %} +Child content +{% endblock %} \ No newline at end of file diff --git a/tests/test_template.c b/tests/test_template.c index c13ef4c..cc57ba5 100644 --- a/tests/test_template.c +++ b/tests/test_template.c @@ -215,6 +215,14 @@ TEST(buffer_alloc) { free(output); } +TEST(directory) { + struct env *env = env_new("./tests/data/01/"); + char *output = render(env, "child.tmpl", NULL); + assert_str(output, "Header\n\nChild content\n\nFooter"); + free(output); + env_free(env); +} + END_TESTS \ No newline at end of file -- cgit v1.2.3