From 1e8fa138696f28cf712d50d85b91afce1faec655 Mon Sep 17 00:00:00 2001
From: Danny van Kooten <dannyvankooten@users.noreply.github.com>
Date: Fri, 13 Mar 2020 11:26:48 +0100
Subject: add whitespace control for statements

---
 src/template.c        | 44 +++++++++++++++++++++++++++++++++++++++-----
 tests/test_hashmap.c  | 11 +++--------
 tests/test_template.c | 10 ++++++++++
 3 files changed, 52 insertions(+), 13 deletions(-)

diff --git a/src/template.c b/src/template.c
index 51c9a77..56abc6d 100644
--- a/src/template.c
+++ b/src/template.c
@@ -26,8 +26,35 @@ char *read_file(char *filename) {
     return input;
 }
 
+char *trim_trailing_whitespace(char *str) {
+    for (int i=strlen(str)-1; isspace(str[i]); i--) {
+        str[i] = '\0';
+    }
+    return str;
+}
+
+char *trim_leading_whitespace(char *str) {
+    while (isspace(*str)) {
+        str++;
+    }
+
+    return str;
+}
+
 int eval(char *dest, mpc_ast_t* t, struct hashmap *ctx) {
+    static int trim_whitespace = 0;
+
     if (strstr(t->tag, "content|var")) {
+        // maybe eat whitespace going backward
+        if (strstr(t->children[0]->contents, "{{-")) {
+            dest = trim_trailing_whitespace(dest);
+        }
+
+        // set flag for next eval() to trim leading whitespace from text
+        if (strstr(t->children[2]->contents, "-}}")) {
+            trim_whitespace = 1;
+        }
+
         char *value = NULL;
         char *key = t->children[1]->contents;
         value = hashmap_resolve(ctx, key);
@@ -52,7 +79,13 @@ int eval(char *dest, mpc_ast_t* t, struct hashmap *ctx) {
     }
 
     if (strstr(t->tag, "content|text")) {
-        strcat(dest, t->contents);
+        char *str = t->contents;
+        if (trim_whitespace) {
+            str = trim_leading_whitespace(str);
+            trim_whitespace = 0;
+        }
+
+        strcat(dest, str);
         return 0;
     }
 
@@ -65,8 +98,8 @@ int eval(char *dest, mpc_ast_t* t, struct hashmap *ctx) {
 
 mpc_parser_t *parser_init() {
     mpc_parser_t *Symbol = mpc_new("symbol");
-    mpc_parser_t *Symbols = mpc_new("symbols");
     mpc_parser_t *Text = mpc_new("text");
+    mpc_parser_t *Whitespace = mpc_new("whitespace");
     mpc_parser_t *Var_Open = mpc_new("var_open");
     mpc_parser_t *Var_Close = mpc_new("var_close");
     mpc_parser_t *Var = mpc_new("var");
@@ -81,8 +114,9 @@ mpc_parser_t *parser_init() {
     mpc_parser_t *Template = mpc_new("template");
     mpca_lang(MPCA_LANG_WHITESPACE_SENSITIVE,
         " symbol    : /[a-zA-Z_.]+/ ;"
-        " var_open  : /\{{2} ?/ ;"
-        " var_close : / ?}{2}/ ;"
+        " whitespace: \"-\"; "
+        " var_open  : /\{{2}-? ?/ ;"
+        " var_close : / ?-?}{2}/ ;"
         " var       : <var_open> <symbol> <var_close> ;"
         " block_open: /\{\% ?/ ;"
         " block_close: / ?\%}/ ;"
@@ -95,7 +129,7 @@ mpc_parser_t *parser_init() {
         " body      : <content>* ;"
         " template  : /^/ <body> /$/ ;",
         Symbol, 
-        Symbols, 
+        Whitespace,
         Var_Open, 
         Var_Close, 
         Var, 
diff --git a/tests/test_hashmap.c b/tests/test_hashmap.c
index d78f768..b9e1cfd 100644
--- a/tests/test_hashmap.c
+++ b/tests/test_hashmap.c
@@ -6,26 +6,21 @@ START_TESTS
 TEST(hashmap) {
     struct hashmap *hm = hashmap_new();
     assert(hashmap_get(hm, "foo") == NULL, "expected NULL");
-
     hashmap_insert(hm, "foo", "bar");
     char *value = hashmap_get(hm, "foo");
-    assert(value != NULL, "expected value, got NULL");
-    assert(strcmp(value, "bar") == 0, "expected %s, got %s", "bar", value);
-
+    assert_str(value, "bar");
     hashmap_free(hm);
 } 
 
 
 TEST(dot_notation) {
-
     struct hashmap *user = hashmap_new();
     hashmap_insert(user, "name", "Danny");
     struct hashmap *hm = hashmap_new();
     hashmap_insert(hm, "user", user);
+    assert(hashmap_resolve(hm, "user") == user, "expected user hashmap, got something else");
     char *value = (char *) hashmap_resolve(hm, "user.name");
-    assert(value != NULL, "expected value, got NULL");
-    assert(strcmp(value, "Danny") == 0, "expected %s, got %s", "Danny", value);
-
+    assert_str(value, "Danny");
     hashmap_free(hm);
 } 
 
diff --git a/tests/test_template.c b/tests/test_template.c
index d9f74ac..90190cc 100644
--- a/tests/test_template.c
+++ b/tests/test_template.c
@@ -20,6 +20,16 @@ TEST(var) {
     free(output);
 }
 
+TEST(var_whitespace) {
+    char *input = "Hello \n{{-name -}}\n.";
+    struct hashmap *ctx = hashmap_new();
+    hashmap_insert(ctx, "name", "world");
+    char *output = template(input, ctx);
+    assert_str(output, "Helloworld.");
+    hashmap_free(ctx);
+    free(output);
+}
+
 TEST(multiline) {
     char *input = "Hello {{name}}.\nL2";
     struct hashmap *ctx = hashmap_new();
-- 
cgit v1.2.3