ruricolist / spinneret

Common Lisp HTML5 generator
MIT License
369 stars 26 forks source link

Allow composition of HTML with macros #56

Closed K1D77A closed 3 years ago

K1D77A commented 3 years ago
(defun %html-block-title (title)
  (spinneret:with-html (:h2 title)))

(defmacro %html-left-bordered ((name) &body body)
  `(spinneret:with-html
     (:div :id ,(format nil "~(~A~)-bordered" name)
           :class "left-bordered"
           ,@body)))

(defmacro %html-new-block ((name title &key (pre-body nil)
                                         (post-body nil))
                           &body body)
  `(spinneret:with-html
     (:div :id ,(format nil "~(~A~)-div" name)
           :class "functionality-block"
           (%html-block-title ,title)
           (:div :class "pre-body"
           (%html-left-bordered (,name)
             ,@body)
           (:div :class "post-body"
                 ,post-body))))

macroexpansion


  (spinneret:with-html
  (:div :id "oof-div" :class "functionality-block" (%html-block-title "bog")
   (:div :class "pre-body" nil)
   (%html-left-bordered ("oof")
     (:p "boof"))
   (:div :class "post-body" nil)))

executing

  LUNA-SITE> (%html-new-block ("oof" "bog") (:p "boof"))

  Execution of a form compiled with errors.
Form:
  (SPINNERET::CATCH-OUTPUT
 (%HTML-LEFT-BORDERED (SPINNERET::FORMAT-TEXT (FORMATTER "oof"))
   (SPINNERET::WITH-TAG (:P)
     "boof")))
Compile-time error:
  during macroexpansion of
(SPINNERET::CATCH-OUTPUT
 (%HTML-LEFT-BORDERED #
   #)).
Use *BREAK-ON-SIGNALS* to intercept.

 Error while parsing arguments to DEFMACRO %HTML-LEFT-BORDERED:
   too many elements in
     (SPINNERET::FORMAT-TEXT (FORMATTER "oof"))
   to satisfy lambda list
     (NAME):
   exactly 1 expected, but got 2
   [Condition of type SB-INT:COMPILED-PROGRAM-ERROR]

Restarts:
 0: [RETRY] Retry SLY mREPL evaluation request.
 1: [*ABORT] Return to SLY's top level.
 2: [ABORT] abort thread (#<THREAD "sly-channel-1-mrepl-remote-1" RUNNING {100E7C8333}>)

Is it possible to modify with-html so that its possible to compose forms with defmacro?

Thanks.

ruricolist commented 3 years ago

The problem here is that Spinneret interprets strings in places that look like function calls as if they were calls to format. So when it sees

(%html-left-bordered ("oof")

It expands ("oof") into (format "oof").

Note that if you substitute a symbol for the string it works:

(with-html-string
  (%html-new-block (#:|oof| "bog") (:p "boof")))
=>
"<div class=functionality-block id=oof-div>
 <h2>bog</h2>
 <div class=pre-body>
  <div class=left-bordered id=oof-bordered>
   <p>boof
  </div>
  <div class=post-body>
  </div>
 </div>
</div>"