yihui / bookdown-crc

A minimal example of using bookdown to write a book for Chapman & Hall/CRC
https://yihui.name/en/2018/08/bookdown-crc/
MIT License
72 stars 66 forks source link

LaTeX Error: Environment rmdtip undefined. #1

Closed cpsievert closed 4 years ago

cpsievert commented 5 years ago

First off, thanks so much for this template! It's going to save me so much time and agony 🍻.

Have you given any thought to supporting custom blocks in the pdf version? Currently if I try to add something like this to an Rmd:

```{block, type = "rmdtip"}
Bookdown rocks
```

I get

LaTeX Error: Environment rmdtip undefined.
yihui commented 5 years ago

I used these environments in the bookdown book. The relevant LaTeX code is here: https://github.com/rstudio/bookdown/blob/7a0364b7ffd16b360b7abde36a29a8801675906c/inst/examples/latex/preamble.tex#L58-L88

The icons are here: https://github.com/rstudio/bookdown/tree/master/inst/examples/images

The HTML versions are defined here: https://github.com/rstudio/bookdown/blob/7a0364b7ffd16b360b7abde36a29a8801675906c/inst/examples/css/style.css#L1-L20

And of course, the documentation: https://bookdown.org/yihui/bookdown/custom-blocks.html

Personally I don't quite like the syntax I invented. I wish someone could figure out how to support fenced divs for LaTeX output: http://pandoc.org/MANUAL.html#divs-and-spans i.e. convert ::: foo to \begin{foo}. I'm sure @RLesur has the capability since he is familiar with Pandoc filters :)

RLesur commented 5 years ago

It looks to be feasible. BTW, there is a Pandoc python filter that does a very similar job https://github.com/chdemko/pandoc-latex-environment I think that the most difficult part is to write the specs. I'm not sure to have fully understood what you need.

Since fenced divs is a Pandoc 2 feature, the filter could be written in lua (advantage: no system dependency).

yihui commented 5 years ago

Very good questions. I agree that the spec requires more thoughts than the actual implementation. I was thinking of something like

::: {.foo data-latex="latex,options,bar=zzz"}
:::

which is converted to

\begin[latex,options,bar=zzz]{foo}
\end{foo}

where the data-latex attribute is optional.

RLesur commented 5 years ago

OK. That's clear. Just another question: what would you want for multiple classes div?

::: {.foo .baz data-latex="latex,options,bar=zzz"}
:::

I guess you just want the first class (I ask to be sure).

yihui commented 5 years ago

Yes, that's exactly what I'd expect.

RLesur commented 5 years ago

So, here is the Pandoc lua filter.

--[[
     A Pandoc 2 lua filter converting Pandoc native divs to LaTeX environments
     Author: Romain Lesur
     License: Public domain
--]]
local pandocList = require 'pandoc.List'

Div = function (div)
  -- if the output format is not latex, the object is left unchanged
  if FORMAT ~= 'latex' then return nil end

  local env = div.classes[1]
  -- if the div has no class, the object is left unchanged
  if not env then return nil end

  local options = div.attributes['data-latex']
  local content = div.content

  -- build the options character string
  local optionsString
  if options then
    optionsString = '[' .. options .. ']'
  else
    optionsString = ''
  end

  -- build the returned list of blocks
  local beginEnv = pandocList:new{pandoc.RawBlock('tex', '\\begin' .. optionsString .. '{' .. env .. '}')}
  local endEnv = pandocList:new{pandoc.RawBlock('tex', '\\end{' .. env .. '}')}
  local returnedList = beginEnv .. content .. endEnv    

  return returnedList
end

Be aware that this filter will transform fenced divs but also html raw divs (since the native_divs extension is enabled by default):

<div class="foo baz" data-latex="latex,options,bar=zzz">
Here is a paragraph.

And another.
</div>

is converted to

\begin[latex,options,bar=zzz]{foo}

Here is a paragraph.

And another.

\end{foo}

This is convenient but could have some side effects.

yihui commented 5 years ago

Excellent!! I'll include this in a future version of bookdown (ideally after the stable release of RStudio 1.2, so most people have access to Pandoc 2). Many thanks!

yihui commented 4 years ago

I just incorporated it into the rmarkdown package. Note that originally I made a mistake in my example. The LaTeX environment syntax should be \begin{foo}[latex,options,bar=zzz] instead of \begin[latex,options,bar=zzz]{foo}, and sometimes it could also be \begin{foo}[latex,options,bar=zzz]{more options}, so I decided not to add the square brackets automatically and let users provide the full argument string after the environment.

Another minor change I made was to drop the data-latex attribute when the output format is not LaTeX: https://github.com/rstudio/rmarkdown/commit/cecd812743826989b539a7b0fcb1b8c08f09c05d#diff-2406dc32c250628c6ff0162c391a7a20R14 since this attribute is unlikely to be useful to other formats such as HTML (hence the HTML code will be a little cleaner).

Many thanks to @RLesur for the lua filter! Finally I can sleep well---I really disliked the block and block2 hacks I invented originally: https://bookdown.org/yihui/bookdown/custom-blocks.html This new lua filter makes custom blocks much more powerful since you can include anything in the div (even R code blocks).

tchevri commented 4 years ago

Hi folks - this is really awesome and works well, for html and pdf. Thank you so much - Merci Romain, XieXie YiHui.

In bookdown however, I am not getting the expected result, when I compile with YiHui's trick:

bookdown::pdf_book: base_format: "function(..., number_sections) rmarkdown::beamer_presentation(...)"

Therefore, I thought the issue was the code above and the line if FORMAT ~= 'latex' then return nil end.

But looking at Release Notes for 1.16 clearly states:

Added a Pandoc lua filter to convert fenced Divs to LaTeX environments when the output format is latex or beamer

So clearly, beamer has been accounted for and I can see that indeed, the above code has been adjusted, line 13!

But as I said, when I compile my book in beamer the fenced block is ignored. However, if in a custom Lua filter I copy the entire filtering code, then everything is as expected and works nicely.

Am I messing something up or is bookdown not picking up this filter properly? I am confused, I am sorry. Again - let me repeat - I run my code without the custom filter and the ::: fenced code is ignored. I run the exact same code with simply your code pasted into a custom Lua filter, and the ::: fenced code is properly converted to latex. Thought i'd bring this up to you, as you would obviously know best.

Again - thank you so much. thomas

tchevri commented 4 years ago

hmmm, digging a bit further, i wonder if this could be the issue then... https://github.com/rstudio/rmarkdown/issues/1779 No - I copy this new code in a custom filter and it works just fine. So only conclusion is that in RStudio, when I click build the book, it's missing this latex-div.lua filter... or are we required to set it ourselves? I thought it'd be part of bookdown, so to speak, no?

yihui commented 4 years ago

@tchevri Please try remotes::install_github('rstudio/rmarkdown') (the relevant commit: https://github.com/rstudio/rmarkdown/commit/fe610c079aad7a6520af634b1012f416f91203b0).

tchevri commented 4 years ago

Thank you so much @yihui ! Such fast response - of course, this solved it, sorry i missed it,
RStudio was telling me i was up to date...

Can I please, please, abuse your kindness before you eat your mooncakes again, please? :-)

It seems an easy solution to my SO question 63116467 is to use ::: {.theorem} instead of ```{theorem}. It works just perfect for non html output, but for html, i obviously lose the numbering and the labeling. Indeed, by just looking at the html file, I can see that the chunk will automatically add the html elements <span><strong>Theorem x.x etc </strong></span>. Is this something that could be achieved with the ::: {.xxx} approach as well, getting numbering and labeling? That would solve so many problems at once and make the book's markdown so easy to read, if you do not mind my thinking so. I could be wrong, but from my extensive internet search, I feel like a lot of other people would very much benefit from this. FeiChang GanXie Nin. thomas

yihui commented 4 years ago

Is this something that could be achieved with the ::: {.xxx} approach as well, getting numbering and labeling?

That's exactly the tricky part, but I definitely see the usefulness, which is why I just said I'd prioritize it https://github.com/rstudio/bookdown/issues/924#issuecomment-675123262.

Such fast response - of course, this solved it, sorry i missed it, RStudio was telling me i was up to date...

Not your fault, since it was only in the development version of rmarkdown.

BTW, I baked some mooncakes a week ago and tasted one yesterday (making mooncakes is very time-consuming so I do it at most twice a year). I feel like you were watching me from somewhere... :)