Below is the message I've sent today to Edi Weitz on this topic.
Unfortunately, I've missed the existence of this mailing-list, that's
why I didn't consult the archives. Today I have quickly pierced the
discussion and, as far as I've seen, the solution, I propose, hadn't
being mentioned.
So, I suggest an implementation strategy for the macroexpansion inside
with-html-output and provide a patch against the current version
(0.11.1)...
I tried to use CL-WHO a couple of times in the past and always stumbled over the
fact, that it's possible to do something like that (example from the site):
(with-html-output (*http-stream*)
(:table :border 0 :cellpadding 4
(loop for i below 25 by 5
do (htm
(:tr :align "right"
(loop for j from i below (+ i 5)
do (htm
(:td :bgcolor (if (oddp j)
"pink"
"green")
(fmt "~@R" (1+ j))))))))))
...but not something like this (i.e. make a macro, to compress some of
the pseudo-html tree):
(with-html-output (*http-stream*)
(:table :border 0 :cellpadding 4
(loop for i below 25 by 5
do (htm
(:tr :align "right"
(loop for j from i below (+ i 5)
do (htm (embed-td j))))))))
(defmacro embed-td (j)
`(:td :bgcolor (if (oddp ,j) "pink" "green")
(fmt "~@R" (1+ ,j))))
Thus to write such a macro for with-htm-output you should do it in two
steps (at least, this is the only way I have discovered):
The original form should be like the following (with STR):
(with-html-output (*http-stream*)
(:table :border 0 :cellpadding 4
(loop for i below 25 by 5
do (htm
(:tr :align "right"
(loop for j from i below (+ i 5)
do (STR (embed-td j))))))))
...and the macro should itself use w-h-o-to-string:
(defmacro embed-td (j)
(let ((str (gensym)))
`(with-html-output-to-string (,str)
(:td :bgcolor (if (oddp ,j)
"pink"
"green")
(fmt "~@R" (1+ ,j))))))
I think it's quite a common case in the usage of the w-h-o macro to
want such macros (at least for me it always comes up). So I suggest to
add another keyword to a list of STR, ESC and HTM -- EMB -- specially
for such cases, which will mean "macroexpand-1 the enclosed form".
With it the above code may be expressed like:
(with-html-output (*http-stream*)
(:table :border 0 :cellpadding 4
(loop for i below 25 by 5
do (htm
(:tr :align "right"
(loop for j from i below (+ i 5)
do (htm (emb (embed-td j)))))))))
(defmacro embed-td (j)
`(:td :bgcolor (if (oddp ,j)
"pink"
"green")
(fmt "~@R" (1+ ,j))))
or like this:
(with-html-output (*http-stream*)
(:table :border 0 :cellpadding 4
(loop for i below 25 by 5
do (htm
(:tr :align "right" (emb (embed-tr i)))))))
(defmacro embed-tr (i)
(let ((j (gensym)))
`(loop for ,j from ,i below (+ ,i 5)
do (htm (:td :bgcolor (if (oddp ,j)
"pink"
"green")
(fmt "~@R" (1+ ,j))))))
I think, sometimes such flexibility is necessary. Although, I'm not
absolutely sure, that the solution, I've hacked, is flawless...
The patch is attached. I tried to follow the guidelines for patches
with this one. The only thing, that I didn't do, is provide examples
of the usage of EMB keyword in the doc (only a brief reference). I
think, that the examples in the letter might suit, but I'm not sure.
Best regards,
Vsevolod Dyomkin