;; Parenscript shortcut (defmacro script (&rest body) "Macro expanding to (:script (:raw (ps body))). Great for embedding JS inside page." `(list :script (list :raw (ps ,@body)))) ;; Templating macros (defmacro mu (&rest body) "Macro writing Mustache syntax, namely the '{{ mustache }}'" `(list :raw (concatenate 'string "{{ " ,@body " }}"))) (defun keyword-to-chain (string-or-keyword) (if (keywordp string-or-keyword) (concatenate 'string "." (-> string-or-keyword symbol-name string-downcase)) string-or-keyword)) (defun muc (&rest chain-of-props) "Shortcut chaining props in a mustache" (mu (reduce (lambda (a b) (concatenate 'string (keyword-to-chain a) (keyword-to-chain b))) chain-of-props))) (defmacro mublock (name attrs &rest body) "Macro writing a block where a '{{ end }}' is followed." `(list (mu ,name " " ,attrs) ,@(mapcar (lambda (x) `',x) body) (mu "end"))) (defmacro muwhen (condition &rest body) `(mublock "if" ,condition ,@body)) (defmacro muif (condition do do-else) `(muwhen ,condition (values ,do) (list :RAW (mu "else")) (values ,do-else))) (defun quote-if-string (str) (if (stringp str) (concatenate 'string "\"" str "\"") (write-to-string str))) ;; TODO support function calls as values (defmacro mudefvar (var val) `(mu "$" (string-downcase (symbol-name ',var)) " := " (quote-if-string ,val)))