Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Option for wrapping block codes with minipages (LaTeX) #703

Closed
aviramsegal opened this issue Jan 16, 2013 · 27 comments
Closed

Option for wrapping block codes with minipages (LaTeX) #703

aviramsegal opened this issue Jan 16, 2013 · 27 comments

Comments

@aviramsegal
Copy link

Curretnly block codes are able to split between pages. for preventing it it is possible to wrap it with a minipage:

\begin{minipage}{linewidth}
\begin{listings}
some code
\end{listings}
\end{minipage}

I downloaded the sources and added it manually for now, I tried doing something more general to suggest as a pull request but Haskell kicked me to the curve.

I hope you will be kind enough to add it, it should be very simple

@jgm
Copy link
Owner

jgm commented Jan 16, 2013

I don't think it would be good to add it, because some people
may want their code blocks to be able to split across pages
(particularly for long listings that might not even fit on
a single page).

+++ Aviram Segal [Jan 16 13 06:20 ]:

Curretnly block codes are able to split between pages. for preventing
it it is possible to wrap it with a minipage:

\begin{minipage}{linewidth}
\begin{listings}
some code
\end{listings}
\end{minipage}

I downloaded the sources and added it manually for now, I tried doing
something more general to suggest as a pull request but Haskell kicked
me to the curve.

I hope you will be kind enough to add it, it should be very simple

--
Reply to this email directly or [1]view it on GitHub.
[xJAuenYDiIoVt3LF3y6848DAslDCyjnQ6q-QyN4VMN_5ygf1_i2t7qNv0W-yJNyI.gif]

References

  1. Option for wrapping block codes with minipages (LaTeX) #703

@aviramsegal
Copy link
Author

I mean add an option for it that is turned off by default

@jgm
Copy link
Owner

jgm commented Jan 16, 2013

Have you considered a pure LaTeX solution? Use a custom latex template, in which you redefine the lstlisting environment, which is what pandoc emits when the --listings option is used.

@aviramsegal
Copy link
Author

I spent 2 whole days trying to do that with no success
While doing that I found another person that tried in December and gave up. It is probably possible but I couldn't get it to work.
I gave up, cloned the repository and edited the latex writer.

@jgm
Copy link
Owner

jgm commented Jan 16, 2013

You might ask on the pandoc-discuss list. There are some people
there who are good with LaTeX.

+++ Aviram Segal [Jan 16 13 08:42 ]:

I spent 2 whole days trying to do that with no success
While doing that I found another person that tried in December and gave
up. It is probably possible but I couldn't get it to work.
I gave up, cloned the repository and edited the latex writer.

--
Reply to this email directly or [1]view it on GitHub.
[xJAuenYDiIoVt3LF3y6848DAslDCyjnQ6q-QyN4VMN_5ygf1_i2t7qNv0W-yJNyI.gif]

References

  1. Option for wrapping block codes with minipages (LaTeX) #703 (comment)

@aviramsegal
Copy link
Author

After I got no reply for 2 days I consulted with somebody who uses latex a lot
He suggested me asking for a way to specify the name of the environment for code blocks. Listings use a special environment whic created with lstnewenvironment and does not provide a renew command (the standard doesn't work) if I could choose how code blocks are called I can create a new env and do what I need

@aviramsegal
Copy link
Author

Added a pull request (#707) for this issue, I guess we can close this one

@jamtur01
Copy link

I've also tried this repeatedly using LaTeX alone plus asked on the TeX list and stackexchange without success. I spent about two weeks hammering on the problem. As far as I am concerned @aviramsegal's solution is ideal. +1.

@jgm
Copy link
Owner

jgm commented Jan 20, 2013

Another possibility would be to make the minipage sensitive to the
code block's attributes. So,

~~~ {.haskell keeptogether=yes}
...
~~~

would wrap the thing in a minipage (whether or not listings is used).
This seems a better solution to me. No new command line options,
and you can still have some wrapping code blocks in the document.

+++ James Turnbull [Jan 20 13 08:09 ]:

I've also tried this repeatedly using LaTeX alone plus asked on the TeX
list and stackexchange without success. I spent about two weeks
hammering on the problem. As far as I am concerned [1]@aviramsegal's
solution is ideal. +1.

--
Reply to this email directly or [2]view it on GitHub.
[J6T91GIPIyhU-8ti4GCGP7AlC2fiocPKodp06RQqyLzv_2vRniVyyWZKvujL71a0.gif]

References

  1. https://github.com/aviramsegal
  2. Option for wrapping block codes with minipages (LaTeX) #703 (comment)

@aviramsegal
Copy link
Author

Personally I have a problem with that because it will require me to pre-process the markdown file as they already have a ````` code block styles and I can not edit them.

@jgm
Copy link
Owner

jgm commented Jan 20, 2013

It occurs to me that you could easily add the minipage instructions
using the techniques described on the website in "Scripting with
pandoc."

Write a function Block -> [Block] that matches code blocks and
surrounds them with raw latex blocks with the begin and end
minipage commands. Then lift this using toJsonFilter.

As your last comment shows, people's needs in this area are going to
depend a lot on the details of what they're doing. So there is a
case to be made for handling this with existing methods (scripting)
rather than adding new options and gizmos.

@jamtur01
Copy link

That's well beyond my limited Haskell skills I am afraid but hopefully someone else can chime in with a script that does it.

@jgm
Copy link
Owner

jgm commented Jan 21, 2013

This should do it

import Text.Pandoc

main = toJsonFilter addMinipages

addMinipages :: Block -> [Block]
addMinipages (CodeBlock attr code) =
  [ RawBlock "latex" "\\begin{minipage}{\\linewidth}"
    , CodeBlock attr code
      , RawBlock "latex" "\\end{minipage}" ]
      addMinipages b = [b]

Save this as minipage.hs, compile with 'ghc --make minipage',
then run with:

pandoc -t json | ./minipage | pandoc -f json -t latex

+++ James Turnbull [Jan 20 13 16:05 ]:

That's well beyond my limited Haskell skills I am afraid but hopefully
someone else can chime in with a script that does it.


Reply to this email directly or [1]view it on GitHub.
[J6T91GIPIyhU-8ti4GCGP7AlC2fiocPKodp06RQqyLzv_2vRniVyyWZKvujL71a0.gif]

References

  1. Option for wrapping block codes with minipages (LaTeX) #703 (comment)

@jamtur01
Copy link

John

Works perfectly! Thank you very much.

@jamtur01
Copy link

Okay small issue. Testing worked perfectly but on my whole book I get:

minipage: Unable to read String
pandoc: Malformed JSON: invalid token in this context

Any clues on where I should start debugging?

@jgm
Copy link
Owner

jgm commented Jan 21, 2013

+++ James Turnbull [Jan 20 13 17:01 ]:

Okay small issue. Testing worked perfectly but on my whole book I get:

minipage: Unable to read String
pandoc: Malformed JSON: invalid token in this context

Any clues on where I should start debugging?

That's a strange one. Pandoc uses the json package's generic
json serialization to create the json string, so I'd be very
surprised if it let in malformed json -- though it might be a
bug in the json package.

One way to debug would be to create a file with pandoc's
json output:

pandoc -t json mybook.txt > mybook.json

Then feed that file to minipage:

cat mybook.json | minipage

Presumably you'll get the error here. But now you can
submit the contents of mybook.json to a json validator, like
http://jsonlint.com/. If the json is really invalid, this
should tell you where. And then you can submit a bug report
to the json package, since pandoc uses Text.JSON.Generic.encodeJSON
to create the json string.

If it's not invalid, then it's possible that the fault lies
with Text.JSON.Generic.decodeJSON, which is what is used
to read the json string in toJsonFilter.

@jamtur01
Copy link

Upgrading to 1.10 removed the error but I am noticing it's generating multiple minipages:

\begin{minipage}{\linewidth}

\begin{minipage}{\linewidth}

\begin{minipage}{\linewidth}

\begin{minipage}{\linewidth}

\begin{minipage}{\linewidth}

\begin{minipage}{\linewidth}

\begin{minipage}{\linewidth}

\begin{minipage}{\linewidth}

\begin{minipage}{\linewidth}

the listing...

\end{minipage}

\end{minipage}

\end{minipage}

\end{minipage}

\end{minipage}

\end{minipage}

\end{minipage}

\end{minipage}

\end{minipage}

\end{minipage}

\end{minipage}

\end{minipage}

\end{minipage}

\end{minipage}

\end{minipage}

\end{minipage}

@jgm
Copy link
Owner

jgm commented Jan 21, 2013

Ah yes. I see what is happening. Note that a Haskell list contains
a number of other Haskell lists (tail xs, tail (tail xs), etc.).
The bottomUp operation operates on each of them.

One workaround is to use this:

import Text.Pandoc

main = interact $ jsonFilter $ \(Pandoc meta blocks) ->
              Pandoc meta (addMinipages blocks)

addMinipages :: [Block] -> [Block]
addMinipages (CodeBlock attr code : xs) =
            [ RawBlock "latex" "\\begin{minipage}{\\linewidth}"
            , CodeBlock attr code
            , RawBlock "latex" "\\end{minipage}" ]
            ++ addMinipages xs
addMinipages (x:xs) = x : addMinipages xs
addMinipages [] = []

It will only operate on top-level block elements, so it won't work if
you have code blocks inside list items, for example. (Though it
could be modified to do so.)

This is a limitation of the scripting API; it should be easier to
do this kind of thing. Maybe what we need is a generic Div or List
block element, so we could make addMinipages a Block -> Block.

+++ James Turnbull [Jan 20 13 17:51 ]:

Upgrading to 1.10 removed the error but I am noticing it's generating
like:

\begin{minipage}{\linewidth}

\begin{minipage}{\linewidth}

\begin{minipage}{\linewidth}

\begin{minipage}{\linewidth}

\begin{minipage}{\linewidth}

\begin{minipage}{\linewidth}

\begin{minipage}{\linewidth}

\begin{minipage}{\linewidth}

\begin{minipage}{\linewidth}

the listing...

\end{minipage}

\end{minipage}

\end{minipage}

\end{minipage}

\end{minipage}

\end{minipage}

\end{minipage}

\end{minipage}

\end{minipage}

\end{minipage}

\end{minipage}

\end{minipage}

\end{minipage}

\end{minipage}

\end{minipage}

\end{minipage}


Reply to this email directly or [1]view it on GitHub.
[J6T91GIPIyhU-8ti4GCGP7AlC2fiocPKodp06RQqyLzv_2vRniVyyWZKvujL71a0.gif]

References

  1. Option for wrapping block codes with minipages (LaTeX) #703 (comment)

@jamtur01
Copy link

Awesome! Fixed. You've gone above and beyond on this and I really appreciate it.

@aviramsegal
Copy link
Author

Thank you so much James!
I really appreciate the time you took to help us with this issue.

Obviously I came across the issue you described with code blocks in a list, I made a fix and I would love to get your feedback on it.

Basically what I did is that if I see an OrderedList or a BulletList I just apply minipages on all its items, the latex/pdf seems to come out fine.

import Text.Pandoc

main = interact $ jsonFilter $ \(Pandoc meta blocks) ->
              Pandoc meta (addMinipages blocks)

addMinipages :: [Block] -> [Block]
addMinipages (OrderedList attr lst : xs) = 
    [ OrderedList attr (map addMinipages lst) ] ++ addMinipages xs
addMinipages (BulletList lst : xs) = 
    [ BulletList (map addMinipages lst) ] ++ addMinipages xs
addMinipages (CodeBlock attr code : xs) =
            [ RawBlock "latex" "\\begin{minipage}{\\linewidth}"
            , CodeBlock attr code
            , RawBlock "latex" "\\end{minipage}" ]
            ++ addMinipages xs
addMinipages (x:xs) = x : addMinipages xs
addMinipages [] = []

@jgm
Copy link
Owner

jgm commented Jan 21, 2013

Here's a variant that should work on all embeddings

import Text.Pandoc

main = toJsonFilter addMinipages

addMinipages :: [Block] -> [Block]
addMinipages (CodeBlock attr code : xs)
  | not (beginsWithEndMinipage xs) =
            [ RawBlock "latex" "\\begin{minipage}{\\linewidth}"
            , CodeBlock attr code
            , RawBlock "latex" "\\end{minipage}" ]
            ++ addMinipages xs
addMinipages (x:xs) = x : addMinipages xs
addMinipages [] = []

beginsWithEndMinipage (RawBlock "latex" "\\end{minipage}":_) = True
beginsWithEndMinipage _ = False

@jimhigson
Copy link

Is there any way to make smaller code blocks not wrap but allow longer ones to span multiple pages? I have a document with a mix of short in-line examples which look really bad wrapped over pages and longer code listings which are too big to fit on a single page.

@kotp
Copy link

kotp commented Oct 16, 2013

I haven't been being careful about scripts not spanning multiple pages, but I have at times just put in a human readable link in a footnote for where to see the code. Such as this:

Code listing^code can be found in the footnotes.

Also, it seems that if the link is https: it breaks the display in the footer. So I have to make those un-clickable for PDF.

@jamtur01
Copy link

I just upgraded to 1.12.3 and I now get:

minipages: fromJSON: field does not exist docTitle

When I run the script above.

I've had a bit of poke but I can't see what's broken.

I tried to compile the later script in #703 (comment) but got:

[1 of 1] Compiling Main             ( minipages.hs, minipages.o )

minipages.hs:3:8:
    No instance for (ToJsonFilter ([Block] -> [Block]))
      arising from a use of `toJsonFilter'
    Possible fix:
      add an instance declaration for (ToJsonFilter ([Block] -> [Block]))
    In the expression: toJsonFilter addMinipages
    In an equation for `main': main = toJsonFilter addMinipages

minipages.hs:8:24:
    Couldn't match expected type `Format' with actual type `[Char]'
    In the first argument of `RawBlock', namely `"latex"'
    In the expression:
      RawBlock "latex" "\\begin{minipage}{\\linewidth}"
    In the first argument of `(++)', namely
      `[RawBlock "latex" "\\begin{minipage}{\\linewidth}",
        CodeBlock attr code, RawBlock "latex" "\\end{minipage}"]'

minipages.hs:15:33:
    Couldn't match expected type `Format' with actual type `[Char]'
    In the pattern: "latex"
    In the pattern: RawBlock "latex" "\\end{minipage}"
    In the pattern: RawBlock "latex" "\\end{minipage}" : _

Any ideas?

@jgm
Copy link
Owner

jgm commented Jan 27, 2014

Modified for latest API (not tested though):

import Text.Pandoc

main = toJsonFilter addMinipages'

addMinipages' :: Pandoc -> Pandoc
addMinipages' = bottomUp addMinipages

addMinipages :: [Block] -> [Block]
addMinipages (CodeBlock attr code : xs)
  | not (beginsWithEndMinipage xs) =
            [ RawBlock (Format "latex") "\\begin{minipage}{\\linewidth}"
            , CodeBlock attr code
            , RawBlock (Format "latex") "\\end{minipage}" ]
            ++ addMinipages xs
addMinipages (x:xs) = x : addMinipages xs
addMinipages [] = []

beginsWithEndMinipage (RawBlock (Format "latex") "\\end{minipage}":_) = True
beginsWithEndMinipage _ = False

@jamtur01
Copy link

I got this to work with the following modified version.

import Text.Pandoc
import Text.Pandoc.JSON

main = toJSONFilter addMinipages'

addMinipages' :: Pandoc -> Pandoc
addMinipages' = bottomUp addMinipages

addMinipages :: [Block] -> [Block]
addMinipages (CodeBlock attr code : xs)
  | not (beginsWithEndMinipage xs) =
            [ RawBlock (Format "latex") "\\begin{minipage}{\\linewidth}"
            , CodeBlock attr code
            , RawBlock (Format "latex") "\\end{minipage}" ]
            ++ addMinipages xs
addMinipages (x:xs) = x : addMinipages xs
addMinipages [] = []

beginsWithEndMinipage (RawBlock (Format "latex") "\\end{minipage}":_) = True
beginsWithEndMinipage _ = False

@wladston
Copy link

wladston commented Jan 6, 2016

Can anyone explain how can I use that code with pandoc to get the desired result?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

6 participants