Scribble: how to wrap a flow in a style?

25 views
Skip to first unread message

Reuben Thomas

unread,
Dec 2, 2019, 5:41:19 PM12/2/19
to Racket Users
I'm trying to get LaTeX output that wraps an environment around several paragraphs (while containing @para elements) and HTML output that does something similar with a <div>. HTML is actually my sticking point, because so far all I've managed to do is get nested <p> elements, which is illegal.

Here's a M(non-)WE:

#lang scribble/base
@(require scribble/core
          scribble/decode)

@(define foo-style (make-style "foo" null))
@(define (foo . content) (make-nested-flow foo-style (decode-flow content)))
@foo{Test.

@para[#:style "bar"]{Bar.}}

This is almost what I want, except that the outer element is a blockquote, not a div. The LaTeX does exactly what I want: the contents is wrapped in \begin{foo}…\end{foo}.

How can I get it wrapped in a div instead? I tried this:

@(define (foo . content)
  (make-part
   #f
   (list `(part ,(generated-tag)))
   #f
   foo-style
   null
   (decode-flow content)
   null))
Unfortunately, styles on parts seem to be interpreted differently, and the name "foo" does not come out in the HTML or LaTeX.

None of the other sorts of block seem to do what I want: table and itemization are special-purpose, compound-paragraph and paragraph are too low level (they are paragraphs, and can't have paragraphs inside them), and traverse-block and delayed-block are of course ways of computing blocks eventually, of one of the other types.


--

Matthew Flatt

unread,
Dec 2, 2019, 5:47:05 PM12/2/19
to Reuben Thomas, Racket Users
Does this get closer?

@(define foo-style (make-style "foo" (list (body-id "div"))))
> --
> You received this message because you are subscribed to the Google Groups
> "Racket Users" group.
> To unsubscribe from this group and stop receiving emails from it, send an
> email to racket-users...@googlegroups.com.
> To view this discussion on the web visit
> https://groups.google.com/d/msgid/racket-users/CAOnWdohD15-1ajAjFEG8CLdLrbDoGYQ
> Ax0VQR%3DKe0PW_iyyt-g%40mail.gmail.com.

Reuben Thomas

unread,
Dec 2, 2019, 5:55:50 PM12/2/19
to Matthew Flatt, Racket Users
On Mon, 2 Dec 2019 at 22:47, Matthew Flatt <mfl...@cs.utah.edu> wrote:
Does this get closer?

 @(define foo-style (make-style "foo" (list (body-id "div"))))

Thanks for the suggestion. It doesn't seem to make any difference. I added scribble/html-properties to my requires, of course, then since I couldn't tell which version of (define foo) you meant me to use it with, I tried it with both. With the definition using make-nested-flow, the output still has a blockquote element. With the definition using make-part, the output still doesn't have any element wrapping it, or any mention of class "foo".

--

Matthew Flatt

unread,
Dec 2, 2019, 6:06:46 PM12/2/19
to Reuben Thomas, Racket Users
Ah, it looks like `alt-tag` is the one that works, instead of
`body-id`. (I'll fix the docs.)

Since I actually tried it this time, here's a modified version of your
example.

----------------------------------------

#lang scribble/base

@(require scribble/core
scribble/decode
scribble/html-properties)

@(define foo-style (make-style "foo" (list (alt-tag "div"))))

Reuben Thomas

unread,
Dec 4, 2019, 4:08:29 AM12/4/19
to Matthew Flatt, Racket Users
On Mon, 2 Dec 2019 at 23:06, Matthew Flatt <mfl...@cs.utah.edu> wrote:

Ah, it looks like `alt-tag` is the one that works, instead of
`body-id`. (I'll fix the docs.)

Thanks for this. I had come across alt-tag before, but I didn't think of it here; it didn't occur to me that an HTML-specific solution would work! I was instead getting stuck on the fact that not every level of the Scribble's document model has an associated struct (e.g. there is no "block").

Anyway, this does what I want, so thanks again; it's also reasonably accurate model-wise: my "foo"s are actually "poem"s, and having them as nested flows makes sense.

--

Reuben Thomas

unread,
Dec 4, 2019, 6:09:55 AM12/4/19
to Matthew Flatt, Racket Users
After a few more experiments, I find that I can't work out another problem I was having: nested <p> elements (which is not legal HTML).

This occurs when I put a style on a @para; for example, a small change to the example code that Matthew kindly provided:

#lang scribble/base
@(require scribble/core
          scribble/decode
          scribble/html-properties)

@(define foo-style (make-style "foo" (list (alt-tag "div"))))
@(define (foo . content) (make-nested-flow foo-style (decode-flow content)))

@foo{@para[#:style "foo"]{Bar.}
@para{Bar.}

This generates (excerpted):

<div class="foo"><p><div class="SIntrapara"><p class="foo">Bar.</p></div><div class="SIntrapara">Bar.</div></p></div></div></div>

My understanding is that a nested flow should be able to contain multiple paragraphs. If I remove the style then the extra <p> elements are not generated, but this doesn't seem to be the real problem; rather, it's that the paragraphs are wrapped in a single <p> element containing <div class="SIntrapara"> elements for the actual paragraphs. I find the following documentation:

  [@css{SIntrapara} @elem{Used with @tt{<div>} instead of @tt{<p>} for a paragraph
                       within a @racket[compound-paragraph].}]

So it looks as though the contents of @foo is being treated as a "compound paragraph", which itself is a somewhat tricky idea to me: it looks like it's a way to typeset multiple paragraphs without each one being indented (so really multiple paragraphs?) yet, as the name suggests, it's clearly modelled as a single paragraph. But surely multiple @para's with a nested-flow should work correctly?

I'm sorry, I can't work out whether the confusion is purely mine, or whether there's something on going on in Scribble here!

--

Matthew Flatt

unread,
Dec 4, 2019, 8:45:08 AM12/4/19
to Reuben Thomas, Racket Users
I'm not sure I follow completely, but I think the problem is the
compound-paragraph parsing that is triggered by the lack of space
between the two `para` calls:

@foo{@para[#:style "foo"]{Bar.}
@para{Bar.}}

If you change it to

@foo{@para[#:style "foo"]{Bar.}

@para{Bar.}}

then the "SIntrapara" layer goes away.

If all the arguments to `foo` will be paragraphs, then one solution is
skip the `decode-flow` call that is creating a compound paragraph. In
that case, use square brackets, since `foo` then expects normal
arguments instead of text-mode argument:

@foo[@para[#:style "foo"]{Bar.}
@para{Bar.}]

Meanwhile, it may be that compound paragraphs do not render in to HTML
in a valid way (within a nested flow?). But I think the immediate
problem is that you don't want the compound paragraph.

Reuben Thomas

unread,
Dec 4, 2019, 3:27:26 PM12/4/19
to Matthew Flatt, Racket Users
On Wed, 4 Dec 2019 at 13:45, Matthew Flatt <mfl...@cs.utah.edu> wrote:
I'm not sure I follow completely, but I think the problem is the
compound-paragraph parsing that is triggered by the lack of space
between the two `para` calls:

Exactly right. I tried to find out if this is documented. I couldn't find any mention of what constitutes a compound paragraph, nor did grepping the scribble package for "blank" get me anywhere. But the fact that you know suggests I have overlooked something…
 
Meanwhile, it may be that compound paragraphs do not render in to HTML
in a valid way (within a nested flow?). But I think the immediate
problem is that you don't want the compound paragraph.

That certainly works for me. Thanks!

--
Reply all
Reply to author
Forward
0 new messages