@@ -168,9 +168,8 @@ pandocToLaTeX options (Pandoc meta blocks) = do
168168 blocks''' <- if beamer
169169 then toSlides blocks''
170170 else return blocks''
171− body <- mapM (elementToLaTeX options) $ hierarchicalize blocks'''
171+ main <- blockListToLaTeX $ makeSections False Nothing blocks'''
172172 biblioTitle <- inlineListToLaTeX lastHeader
173− let main = vsep body
174173 st <- get
175174 titleMeta <- stringToLaTeX TextString $ stringify $ docTitle meta
176175 authorsMeta <- mapM (stringToLaTeX TextString . stringify) $ docAuthors meta
@@ -298,16 +297,6 @@ pandocToLaTeX options (Pandoc meta blocks) = do
298297 Nothing -> main
299298 Just tpl -> renderTemplate tpl context'
300299
301−-- | Convert Elements to LaTeX
302−elementToLaTeX :: PandocMonad m => WriterOptions -> Element -> LW m (Doc Text)
303−elementToLaTeX _ (Blk block) = blockToLaTeX block
304−elementToLaTeX opts (Sec level _ (id',classes,_) title' elements) = do
305− modify $ \s -> s{stInHeading = True}
306− header' <- sectionHeader ("unnumbered" `elem` classes) id' level title'
307− modify $ \s -> s{stInHeading = False}
308− innerContents <- mapM (elementToLaTeX opts) elements
309− return $ vsep (header' : innerContents)
310−
311300data StringContext = TextString
312301 | URLString
313302 | CodeString
@@ -459,68 +448,16 @@ toSlides bs = do
459448 opts <- gets stOptions
460449 let slideLevel = fromMaybe (getSlideLevel bs) $ writerSlideLevel opts
461450 let bs' = prepSlides slideLevel bs
462− concat `fmap` mapM (elementToBeamer slideLevel) (hierarchicalize bs')
451+ walkM (elementToBeamer slideLevel) (makeSections False Nothing bs')
463452
464−elementToBeamer :: PandocMonad m => Int -> Element -> LW m [Block]
465−elementToBeamer _slideLevel (Blk (Div attrs bs)) = do
466− -- make sure we support "blocks" inside divs
467− bs' <- concat `fmap` mapM (elementToBeamer 0) (hierarchicalize bs)
468− return [Div attrs bs']
469−
470−elementToBeamer _slideLevel (Blk b) = return [b]
471−elementToBeamer slideLevel (Sec lvl _num (ident,classes,kvs) tit elts)
472− | lvl > slideLevel = do
473− bs <- concat `fmap` mapM (elementToBeamer slideLevel) elts
474− return $ Para ( RawInline "latex" "\\begin{block}{"
475− : tit ++ [RawInline "latex" "}"] )
476− : bs ++ [RawBlock "latex" "\\end{block}"]
477− | lvl < slideLevel = do
478− let isSec Sec{} = True
479− isSec _ = False
480− let (contentElts, secElts) = break isSec elts
481− let elts' = if null contentElts
482− then secElts
483− else Sec slideLevel [] nullAttr tit contentElts :
484− secElts
485− bs <- concat `fmap` mapM (elementToBeamer slideLevel) elts'
486− return $ Header lvl (ident,classes,kvs) tit : bs
487− | otherwise = do -- lvl == slideLevel
488− -- note: [fragile] is required or verbatim breaks
489− let hasCodeBlock (CodeBlock _ _) = [True]
490− hasCodeBlock _ = []
491− let hasCode (Code _ _) = [True]
492− hasCode _ = []
493− let fragile = "fragile" `elem` classes ||
494− not (null $ query hasCodeBlock elts ++ query hasCode elts)
495− let frameoptions = ["allowdisplaybreaks", "allowframebreaks", "fragile",
496− "b", "c", "t", "environment",
497− "label", "plain", "shrink", "standout",
498− "noframenumbering"]
499− let optionslist = ["fragile" | fragile
500− , isNothing (lookup "fragile" kvs)
501− , "fragile" `notElem` classes] ++
502− [k | k <- classes, k `elem` frameoptions] ++
503− [k ++ "=" ++ v | (k,v) <- kvs, k `elem` frameoptions]
504− let options = if null optionslist
505− then ""
506− else "[" ++ intercalate "," optionslist ++ "]"
507− let latex = RawInline (Format "latex")
508− slideTitle <-
509− if tit == [Str "\0"] -- marker for hrule
510− then return []
511− else return $ latex "{" : tit ++ [latex "}"]
512− ref <- toLabel ident
513− let slideAnchor = if null ident
514− then []
515− else [latex ("\n\\protect\\hypertarget{" ++
516− ref ++ "}{}")]
517− let slideStart = Para $
518− RawInline "latex" ("\\begin{frame}" ++ options) :
519− slideTitle ++ slideAnchor
520− let slideEnd = RawBlock "latex" "\\end{frame}"
521− -- now carve up slide into blocks if there are sections inside
522− bs <- concat `fmap` mapM (elementToBeamer slideLevel) elts
523− return $ slideStart : bs ++ [slideEnd]
453+-- this creates section slides and marks slides with class "slide","block"
454+elementToBeamer :: PandocMonad m => Int -> Block -> LW m Block
455+elementToBeamer slideLevel d@(Div (ident,dclasses,dkvs)
456+ xs@(Header lvl _ _ : _))
457+ | lvl > slideLevel = return $ Div (ident,"block":dclasses,dkvs) xs
458+ | lvl < slideLevel = return d
459+ | otherwise = return $ Div (ident,"slide":dclasses,dkvs) xs
460+elementToBeamer _ x = return x
524461
525462isListBlock :: Block -> Bool
526463isListBlock (BulletList _) = True
@@ -533,85 +470,87 @@ blockToLaTeX :: PandocMonad m
533470 => Block -- ^ Block to convert
534471 -> LW m (Doc Text)
535472blockToLaTeX Null = return empty
536−blockToLaTeX (Div (identifier,classes,kvs) bs)
537− | "incremental" `elem` classes = do
538− let classes' = filter ("incremental"/=) classes
539− beamer <- gets stBeamer
540− if beamer
541− then do oldIncremental <- gets stIncremental
542− modify $ \s -> s{ stIncremental = True }
543− result <- blockToLaTeX $ Div (identifier,classes',kvs) bs
544− modify $ \s -> s{ stIncremental = oldIncremental }
545− return result
546− else blockToLaTeX $ Div (identifier,classes',kvs) bs
547− | "nonincremental" `elem` classes = do
548− let classes' = filter ("nonincremental"/=) classes
549− beamer <- gets stBeamer
550− if beamer
551− then do oldIncremental <- gets stIncremental
552− modify $ \s -> s{ stIncremental = False }
553− result <- blockToLaTeX $ Div (identifier,classes',kvs) bs
554− modify $ \s -> s{ stIncremental = oldIncremental }
555− return result
556− else blockToLaTeX $ Div (identifier,classes',kvs) bs
557− | identifier == "refs" = do
558− modify $ \st -> st{ stHasCslRefs = True
559− , stCslHangingIndent =
560− "hanging-indent" `elem` classes }
561− contents <- blockListToLaTeX bs
562− return $ "\\begin{cslreferences}" $$
563− contents $$
564− "\\end{cslreferences}"
565− | otherwise = do
566− beamer <- gets stBeamer
567− linkAnchor' <- hypertarget True identifier empty
568− -- see #2704 for the motivation for adding \leavevmode:
569− let linkAnchor =
570− case bs of
571− Para _ : _
572− | not (isEmpty linkAnchor')
573− -> "\\leavevmode" <> linkAnchor' <> "%"
574− _ -> linkAnchor'
575− let align dir txt = inCmd "begin" dir $$ txt $$ inCmd "end" dir
576− lang <- toLang $ lookup "lang" kvs
577− let wrapColumns = if beamer && "columns" `elem` classes
578− then \contents ->
579− inCmd "begin" "columns" <> brackets "T"
580− $$ contents
581− $$ inCmd "end" "columns"
582− else id
583− wrapColumn = if beamer && "column" `elem` classes
584− then \contents ->
585− let w = maybe "0.48" fromPct (lookup "width" kvs)
586− in inCmd "begin" "column" <>
587− braces (text w <> "\\textwidth")
588− $$ contents
589− $$ inCmd "end" "column"
590− else id
591− fromPct xs =
592− case reverse xs of
593− '%':ds -> case safeRead (reverse ds) of
594− Just digits -> showFl (digits / 100 :: Double)
595− Nothing -> xs
596− _ -> xs
597− wrapDir = case lookup "dir" kvs of
598− Just "rtl" -> align "RTL"
599− Just "ltr" -> align "LTR"
600− _ -> id
601− wrapLang txt = case lang of
602− Just lng -> let (l, o) = toPolyglossiaEnv lng
603− ops = if null o
604− then ""
605− else brackets $ text o
606− in inCmd "begin" (text l) <> ops
607− $$ blankline <> txt <> blankline
608− $$ inCmd "end" (text l)
609− Nothing -> txt
610− wrapNotes txt = if beamer && "notes" `elem` classes
611− then "\\note" <> braces txt -- speaker notes
612− else linkAnchor $$ txt
613− (wrapColumns . wrapColumn . wrapDir . wrapLang . wrapNotes)
614− <$> blockListToLaTeX bs
473+blockToLaTeX (Div attr@(identifier,"block":_,_) (Header _ _ ils : bs)) = do
474+ ref <- toLabel identifier
475+ let anchor = if null identifier
476+ then empty
477+ else cr <> "\\protect\\hypertarget" <>
478+ braces (text ref) <> braces empty
479+ title' <- inlineListToLaTeX ils
480+ contents <- blockListToLaTeX bs
481+ wrapDiv attr $ ("\\begin{block}" <> braces title' <> anchor) $$
482+ contents $$ "\\end{block}"
483+blockToLaTeX (Div (identifier,"slide":dclasses,dkvs)
484+ (Header _ (_,hclasses,hkvs) ils : bs)) = do
485+ -- note: [fragile] is required or verbatim breaks
486+ let hasCodeBlock (CodeBlock _ _) = [True]
487+ hasCodeBlock _ = []
488+ let hasCode (Code _ _) = [True]
489+ hasCode _ = []
490+ let classes = dclasses ++ hclasses
491+ let kvs = dkvs ++ hkvs
492+ let fragile = "fragile" `elem` classes ||
493+ not (null $ query hasCodeBlock bs ++ query hasCode bs)
494+ let frameoptions = ["allowdisplaybreaks", "allowframebreaks", "fragile",
495+ "b", "c", "t", "environment",
496+ "label", "plain", "shrink", "standout",
497+ "noframenumbering"]
498+ let optionslist = ["fragile" | fragile
499+ , isNothing (lookup "fragile" kvs)
500+ , "fragile" `notElem` classes] ++
501+ [k | k <- classes, k `elem` frameoptions] ++
502+ [k ++ "=" ++ v | (k,v) <- kvs, k `elem` frameoptions]
503+ let options = if null optionslist
504+ then empty
505+ else brackets (text (intercalate "," optionslist))
506+ slideTitle <- if ils == [Str "\0"] -- marker for hrule
507+ then return empty
508+ else braces <$> inlineListToLaTeX ils
509+ ref <- toLabel identifier
510+ let slideAnchor = if null identifier
511+ then empty
512+ else cr <> "\\protect\\hypertarget" <>
513+ braces (text ref) <> braces empty
514+ contents <- blockListToLaTeX bs >>= wrapDiv (identifier,classes,kvs)
515+ return $ ("\\begin{frame}" <> options <> slideTitle <> slideAnchor) $$
516+ contents $$
517+ "\\end{frame}"
518+blockToLaTeX (Div (identifier@(_:_),dclasses,dkvs)
519+ (Header lvl ("",hclasses,hkvs) ils : bs)) = do
520+ -- move identifier from div to header
521+ blockToLaTeX (Div ("",dclasses,dkvs)
522+ (Header lvl (identifier,hclasses,hkvs) ils : bs))
523+blockToLaTeX (Div (identifier,classes,kvs) bs) = do
524+ beamer <- gets stBeamer
525+ oldIncremental <- gets stIncremental
526+ if beamer && "incremental" `elem` classes
527+ then modify $ \st -> st{ stIncremental = True }
528+ else if beamer && "nonincremental" `elem` classes
529+ then modify $ \st -> st { stIncremental = False }
530+ else return ()
531+ result <- if identifier == "refs"
532+ then do
533+ inner <- blockListToLaTeX bs
534+ modify $ \st -> st{ stHasCslRefs = True
535+ , stCslHangingIndent =
536+ "hanging-indent" `elem` classes }
537+ return $ "\\begin{cslreferences}" $$
538+ inner $$
539+ "\\end{cslreferences}"
540+ else blockListToLaTeX bs
541+ modify $ \st -> st{ stIncremental = oldIncremental }
542+ linkAnchor' <- hypertarget True identifier empty
543+ -- see #2704 for the motivation for adding \leavevmode:
544+ let linkAnchor =
545+ case bs of
546+ Para _ : _
547+ | not (isEmpty linkAnchor')
548+ -> "\\leavevmode" <> linkAnchor' <> "%"
549+ _ -> linkAnchor'
550+ wrapNotes txt = if beamer && "notes" `elem` classes
551+ then "\\note" <> braces txt -- speaker notes
552+ else linkAnchor $$ txt
553+ wrapNotes <$> wrapDiv (identifier,classes,kvs) result
615554blockToLaTeX (Plain lst) =
616555 inlineListToLaTeX lst
617556-- title beginning with fig: indicates that the image is a figure
@@ -1077,6 +1016,46 @@ sectionHeader unnumbered ident level lst = do
10771016 braces txtNoNotes
10781017 else empty
10791018
1019+wrapDiv :: PandocMonad m => Attr -> Doc Text -> LW m (Doc Text)
1020+wrapDiv (_,classes,kvs) t = do
1021+ beamer <- gets stBeamer
1022+ let align dir txt = inCmd "begin" dir $$ txt $$ inCmd "end" dir
1023+ lang <- toLang $ lookup "lang" kvs
1024+ let wrapColumns = if beamer && "columns" `elem` classes
1025+ then \contents ->
1026+ inCmd "begin" "columns" <> brackets "T"
1027+ $$ contents
1028+ $$ inCmd "end" "columns"
1029+ else id
1030+ wrapColumn = if beamer && "column" `elem` classes
1031+ then \contents ->
1032+ let w = maybe "0.48" fromPct (lookup "width" kvs)
1033+ in inCmd "begin" "column" <>
1034+ braces (text w <> "\\textwidth")
1035+ $$ contents
1036+ $$ inCmd "end" "column"
1037+ else id
1038+ fromPct xs =
1039+ case reverse xs of
1040+ '%':ds -> case safeRead (reverse ds) of
1041+ Just digits -> showFl (digits / 100 :: Double)
1042+ Nothing -> xs
1043+ _ -> xs
1044+ wrapDir = case lookup "dir" kvs of
1045+ Just "rtl" -> align "RTL"
1046+ Just "ltr" -> align "LTR"
1047+ _ -> id
1048+ wrapLang txt = case lang of
1049+ Just lng -> let (l, o) = toPolyglossiaEnv lng
1050+ ops = if null o
1051+ then ""
1052+ else brackets $ text o
1053+ in inCmd "begin" (text l) <> ops
1054+ $$ blankline <> txt <> blankline
1055+ $$ inCmd "end" (text l)
1056+ Nothing -> txt
1057+ return $ wrapColumns . wrapColumn . wrapDir . wrapLang $ t
1058+
10801059hypertarget :: PandocMonad m => Bool -> String -> Doc Text -> LW m (Doc Text)
10811060hypertarget _ "" x = return x
10821061hypertarget addnewline ident x = do