moderninterpreters / markup

MARKUP provides a reader-macro to read HTML tags inside of Common Lisp code
Apache License 2.0
70 stars 8 forks source link

Question about nesting #9

Closed atgreen closed 2 years ago

atgreen commented 2 years ago

Does markup allow me to nest lisp and html several layers down? I don't see how to do this right now. Imagine, for instance, that I want to create a table, and use a dolist to generate the rows of the table. We would have the markup for the table start and end, and then a ,(dolist (a '(1 2 3)) ,a). I don't think that's right, but how would you do it?

tdrhq commented 2 years ago

@atgreen Most certainly, you can nest how many ever levels deep. But, you can't use dolist, you'd have to use something like mapcar or loop for x in ... collect ....

Your table example would look like this:

<table>
  ,@(loop for row in data collect
          <tr><td>...</td></tr>)
</table>

Note the use of ,@ instead of ,. We're splicing the list of nodes returned by the loop into the table node's children.

Essentially each time you call <...>, it's creating a new object (well, with some optimization under the hood that you don't need to worry about, you can treat it like it's creating a new object for each node).

tdrhq commented 2 years ago

Here are some real-world examples of generating tables like you mentioned:

https://github.com/screenshotbot/screenshotbot-oss/blob/e3b89770c4baa974af4b947a16089591f8a27517/src/screenshotbot/company/members.lisp#L112

https://github.com/screenshotbot/screenshotbot-oss/blob/61dc0eab70ce271c2133a0233c9f0785209d789c/src/screenshotbot/dashboard/api-keys.lisp#L108

atgreen commented 2 years ago

Thanks. I ran into trouble generating a complex table with nested ,@. Have a look here: https://github.com/atgreen/red-light-green-light/blob/66dc02b8f1d26d9af33050b935550a467425612a/rlgl-server.lisp#L757-L787

The inner loop generates pairs of rows. But the outer ,@ loop can only deal with one markup object per list item, so I wrapped each pair of rows with . Then I had to strip the out so the existing javascript/css would work. If there's a better way of doing this, I'd love to hear it.

Regardless, thanks for markup, and making screenshotbot FOSS for others to learn from.

tdrhq commented 2 years ago

@atgreen There are two options for what you need. I usually would go with a loop for ... appending (list ...). Or you can wrap the pairs using <markup:merge-tag>, which would just merge the elements into the parent node at rendering time.

atgreen commented 2 years ago

Thanks for the tip! I used and it works perfectly. Thanks again!