aboutsummaryrefslogtreecommitdiff
path: root/src/Text/Pandoc/Writers/LaTeX.hs
diff options
context:
space:
mode:
Diffstat (limited to 'src/Text/Pandoc/Writers/LaTeX.hs')
-rw-r--r--src/Text/Pandoc/Writers/LaTeX.hs283
1 files changed, 131 insertions, 152 deletions
diff --git a/src/Text/Pandoc/Writers/LaTeX.hs b/src/Text/Pandoc/Writers/LaTeX.hs
index 3c952c2d1..2e340b411 100644
--- a/src/Text/Pandoc/Writers/LaTeX.hs
+++ b/src/Text/Pandoc/Writers/LaTeX.hs
@@ -168,9 +168,8 @@ pandocToLaTeX options (Pandoc meta blocks) = do
blocks''' <- if beamer
then toSlides blocks''
else return blocks''
- body <- mapM (elementToLaTeX options) $ hierarchicalize blocks'''
+ main <- blockListToLaTeX $ makeSections False Nothing blocks'''
biblioTitle <- inlineListToLaTeX lastHeader
- let main = vsep body
st <- get
titleMeta <- stringToLaTeX TextString $ stringify $ docTitle meta
authorsMeta <- mapM (stringToLaTeX TextString . stringify) $ docAuthors meta
@@ -298,16 +297,6 @@ pandocToLaTeX options (Pandoc meta blocks) = do
Nothing -> main
Just tpl -> renderTemplate tpl context'
--- | Convert Elements to LaTeX
-elementToLaTeX :: PandocMonad m => WriterOptions -> Element -> LW m (Doc Text)
-elementToLaTeX _ (Blk block) = blockToLaTeX block
-elementToLaTeX opts (Sec level _ (id',classes,_) title' elements) = do
- modify $ \s -> s{stInHeading = True}
- header' <- sectionHeader ("unnumbered" `elem` classes) id' level title'
- modify $ \s -> s{stInHeading = False}
- innerContents <- mapM (elementToLaTeX opts) elements
- return $ vsep (header' : innerContents)
-
data StringContext = TextString
| URLString
| CodeString
@@ -459,68 +448,16 @@ toSlides bs = do
opts <- gets stOptions
let slideLevel = fromMaybe (getSlideLevel bs) $ writerSlideLevel opts
let bs' = prepSlides slideLevel bs
- concat `fmap` mapM (elementToBeamer slideLevel) (hierarchicalize bs')
+ walkM (elementToBeamer slideLevel) (makeSections False Nothing bs')
-elementToBeamer :: PandocMonad m => Int -> Element -> LW m [Block]
-elementToBeamer _slideLevel (Blk (Div attrs bs)) = do
- -- make sure we support "blocks" inside divs
- bs' <- concat `fmap` mapM (elementToBeamer 0) (hierarchicalize bs)
- return [Div attrs bs']
-
-elementToBeamer _slideLevel (Blk b) = return [b]
-elementToBeamer slideLevel (Sec lvl _num (ident,classes,kvs) tit elts)
- | lvl > slideLevel = do
- bs <- concat `fmap` mapM (elementToBeamer slideLevel) elts
- return $ Para ( RawInline "latex" "\\begin{block}{"
- : tit ++ [RawInline "latex" "}"] )
- : bs ++ [RawBlock "latex" "\\end{block}"]
- | lvl < slideLevel = do
- let isSec Sec{} = True
- isSec _ = False
- let (contentElts, secElts) = break isSec elts
- let elts' = if null contentElts
- then secElts
- else Sec slideLevel [] nullAttr tit contentElts :
- secElts
- bs <- concat `fmap` mapM (elementToBeamer slideLevel) elts'
- return $ Header lvl (ident,classes,kvs) tit : bs
- | otherwise = do -- lvl == slideLevel
- -- note: [fragile] is required or verbatim breaks
- let hasCodeBlock (CodeBlock _ _) = [True]
- hasCodeBlock _ = []
- let hasCode (Code _ _) = [True]
- hasCode _ = []
- let fragile = "fragile" `elem` classes ||
- not (null $ query hasCodeBlock elts ++ query hasCode elts)
- let frameoptions = ["allowdisplaybreaks", "allowframebreaks", "fragile",
- "b", "c", "t", "environment",
- "label", "plain", "shrink", "standout",
- "noframenumbering"]
- let optionslist = ["fragile" | fragile
- , isNothing (lookup "fragile" kvs)
- , "fragile" `notElem` classes] ++
- [k | k <- classes, k `elem` frameoptions] ++
- [k ++ "=" ++ v | (k,v) <- kvs, k `elem` frameoptions]
- let options = if null optionslist
- then ""
- else "[" ++ intercalate "," optionslist ++ "]"
- let latex = RawInline (Format "latex")
- slideTitle <-
- if tit == [Str "\0"] -- marker for hrule
- then return []
- else return $ latex "{" : tit ++ [latex "}"]
- ref <- toLabel ident
- let slideAnchor = if null ident
- then []
- else [latex ("\n\\protect\\hypertarget{" ++
- ref ++ "}{}")]
- let slideStart = Para $
- RawInline "latex" ("\\begin{frame}" ++ options) :
- slideTitle ++ slideAnchor
- let slideEnd = RawBlock "latex" "\\end{frame}"
- -- now carve up slide into blocks if there are sections inside
- bs <- concat `fmap` mapM (elementToBeamer slideLevel) elts
- return $ slideStart : bs ++ [slideEnd]
+-- this creates section slides and marks slides with class "slide","block"
+elementToBeamer :: PandocMonad m => Int -> Block -> LW m Block
+elementToBeamer slideLevel d@(Div (ident,dclasses,dkvs)
+ xs@(Header lvl _ _ : _))
+ | lvl > slideLevel = return $ Div (ident,"block":dclasses,dkvs) xs
+ | lvl < slideLevel = return d
+ | otherwise = return $ Div (ident,"slide":dclasses,dkvs) xs
+elementToBeamer _ x = return x
isListBlock :: Block -> Bool
isListBlock (BulletList _) = True
@@ -533,85 +470,87 @@ blockToLaTeX :: PandocMonad m
=> Block -- ^ Block to convert
-> LW m (Doc Text)
blockToLaTeX Null = return empty
-blockToLaTeX (Div (identifier,classes,kvs) bs)
- | "incremental" `elem` classes = do
- let classes' = filter ("incremental"/=) classes
- beamer <- gets stBeamer
- if beamer
- then do oldIncremental <- gets stIncremental
- modify $ \s -> s{ stIncremental = True }
- result <- blockToLaTeX $ Div (identifier,classes',kvs) bs
- modify $ \s -> s{ stIncremental = oldIncremental }
- return result
- else blockToLaTeX $ Div (identifier,classes',kvs) bs
- | "nonincremental" `elem` classes = do
- let classes' = filter ("nonincremental"/=) classes
- beamer <- gets stBeamer
- if beamer
- then do oldIncremental <- gets stIncremental
- modify $ \s -> s{ stIncremental = False }
- result <- blockToLaTeX $ Div (identifier,classes',kvs) bs
- modify $ \s -> s{ stIncremental = oldIncremental }
- return result
- else blockToLaTeX $ Div (identifier,classes',kvs) bs
- | identifier == "refs" = do
- modify $ \st -> st{ stHasCslRefs = True
- , stCslHangingIndent =
- "hanging-indent" `elem` classes }
- contents <- blockListToLaTeX bs
- return $ "\\begin{cslreferences}" $$
- contents $$
- "\\end{cslreferences}"
- | otherwise = do
- beamer <- gets stBeamer
- linkAnchor' <- hypertarget True identifier empty
- -- see #2704 for the motivation for adding \leavevmode:
- let linkAnchor =
- case bs of
- Para _ : _
- | not (isEmpty linkAnchor')
- -> "\\leavevmode" <> linkAnchor' <> "%"
- _ -> linkAnchor'
- let align dir txt = inCmd "begin" dir $$ txt $$ inCmd "end" dir
- lang <- toLang $ lookup "lang" kvs
- let wrapColumns = if beamer && "columns" `elem` classes
- then \contents ->
- inCmd "begin" "columns" <> brackets "T"
- $$ contents
- $$ inCmd "end" "columns"
- else id
- wrapColumn = if beamer && "column" `elem` classes
- then \contents ->
- let w = maybe "0.48" fromPct (lookup "width" kvs)
- in inCmd "begin" "column" <>
- braces (text w <> "\\textwidth")
- $$ contents
- $$ inCmd "end" "column"
- else id
- fromPct xs =
- case reverse xs of
- '%':ds -> case safeRead (reverse ds) of
- Just digits -> showFl (digits / 100 :: Double)
- Nothing -> xs
- _ -> xs
- wrapDir = case lookup "dir" kvs of
- Just "rtl" -> align "RTL"
- Just "ltr" -> align "LTR"
- _ -> id
- wrapLang txt = case lang of
- Just lng -> let (l, o) = toPolyglossiaEnv lng
- ops = if null o
- then ""
- else brackets $ text o
- in inCmd "begin" (text l) <> ops
- $$ blankline <> txt <> blankline
- $$ inCmd "end" (text l)
- Nothing -> txt
- wrapNotes txt = if beamer && "notes" `elem` classes
- then "\\note" <> braces txt -- speaker notes
- else linkAnchor $$ txt
- (wrapColumns . wrapColumn . wrapDir . wrapLang . wrapNotes)
- <$> blockListToLaTeX bs
+blockToLaTeX (Div attr@(identifier,"block":_,_) (Header _ _ ils : bs)) = do
+ ref <- toLabel identifier
+ let anchor = if null identifier
+ then empty
+ else cr <> "\\protect\\hypertarget" <>
+ braces (text ref) <> braces empty
+ title' <- inlineListToLaTeX ils
+ contents <- blockListToLaTeX bs
+ wrapDiv attr $ ("\\begin{block}" <> braces title' <> anchor) $$
+ contents $$ "\\end{block}"
+blockToLaTeX (Div (identifier,"slide":dclasses,dkvs)
+ (Header _ (_,hclasses,hkvs) ils : bs)) = do
+ -- note: [fragile] is required or verbatim breaks
+ let hasCodeBlock (CodeBlock _ _) = [True]
+ hasCodeBlock _ = []
+ let hasCode (Code _ _) = [True]
+ hasCode _ = []
+ let classes = dclasses ++ hclasses
+ let kvs = dkvs ++ hkvs
+ let fragile = "fragile" `elem` classes ||
+ not (null $ query hasCodeBlock bs ++ query hasCode bs)
+ let frameoptions = ["allowdisplaybreaks", "allowframebreaks", "fragile",
+ "b", "c", "t", "environment",
+ "label", "plain", "shrink", "standout",
+ "noframenumbering"]
+ let optionslist = ["fragile" | fragile
+ , isNothing (lookup "fragile" kvs)
+ , "fragile" `notElem` classes] ++
+ [k | k <- classes, k `elem` frameoptions] ++
+ [k ++ "=" ++ v | (k,v) <- kvs, k `elem` frameoptions]
+ let options = if null optionslist
+ then empty
+ else brackets (text (intercalate "," optionslist))
+ slideTitle <- if ils == [Str "\0"] -- marker for hrule
+ then return empty
+ else braces <$> inlineListToLaTeX ils
+ ref <- toLabel identifier
+ let slideAnchor = if null identifier
+ then empty
+ else cr <> "\\protect\\hypertarget" <>
+ braces (text ref) <> braces empty
+ contents <- blockListToLaTeX bs >>= wrapDiv (identifier,classes,kvs)
+ return $ ("\\begin{frame}" <> options <> slideTitle <> slideAnchor) $$
+ contents $$
+ "\\end{frame}"
+blockToLaTeX (Div (identifier@(_:_),dclasses,dkvs)
+ (Header lvl ("",hclasses,hkvs) ils : bs)) = do
+ -- move identifier from div to header
+ blockToLaTeX (Div ("",dclasses,dkvs)
+ (Header lvl (identifier,hclasses,hkvs) ils : bs))
+blockToLaTeX (Div (identifier,classes,kvs) bs) = do
+ beamer <- gets stBeamer
+ oldIncremental <- gets stIncremental
+ if beamer && "incremental" `elem` classes
+ then modify $ \st -> st{ stIncremental = True }
+ else if beamer && "nonincremental" `elem` classes
+ then modify $ \st -> st { stIncremental = False }
+ else return ()
+ result <- if identifier == "refs"
+ then do
+ inner <- blockListToLaTeX bs
+ modify $ \st -> st{ stHasCslRefs = True
+ , stCslHangingIndent =
+ "hanging-indent" `elem` classes }
+ return $ "\\begin{cslreferences}" $$
+ inner $$
+ "\\end{cslreferences}"
+ else blockListToLaTeX bs
+ modify $ \st -> st{ stIncremental = oldIncremental }
+ linkAnchor' <- hypertarget True identifier empty
+ -- see #2704 for the motivation for adding \leavevmode:
+ let linkAnchor =
+ case bs of
+ Para _ : _
+ | not (isEmpty linkAnchor')
+ -> "\\leavevmode" <> linkAnchor' <> "%"
+ _ -> linkAnchor'
+ wrapNotes txt = if beamer && "notes" `elem` classes
+ then "\\note" <> braces txt -- speaker notes
+ else linkAnchor $$ txt
+ wrapNotes <$> wrapDiv (identifier,classes,kvs) result
blockToLaTeX (Plain lst) =
inlineListToLaTeX lst
-- title beginning with fig: indicates that the image is a figure
@@ -1077,6 +1016,46 @@ sectionHeader unnumbered ident level lst = do
braces txtNoNotes
else empty
+wrapDiv :: PandocMonad m => Attr -> Doc Text -> LW m (Doc Text)
+wrapDiv (_,classes,kvs) t = do
+ beamer <- gets stBeamer
+ let align dir txt = inCmd "begin" dir $$ txt $$ inCmd "end" dir
+ lang <- toLang $ lookup "lang" kvs
+ let wrapColumns = if beamer && "columns" `elem` classes
+ then \contents ->
+ inCmd "begin" "columns" <> brackets "T"
+ $$ contents
+ $$ inCmd "end" "columns"
+ else id
+ wrapColumn = if beamer && "column" `elem` classes
+ then \contents ->
+ let w = maybe "0.48" fromPct (lookup "width" kvs)
+ in inCmd "begin" "column" <>
+ braces (text w <> "\\textwidth")
+ $$ contents
+ $$ inCmd "end" "column"
+ else id
+ fromPct xs =
+ case reverse xs of
+ '%':ds -> case safeRead (reverse ds) of
+ Just digits -> showFl (digits / 100 :: Double)
+ Nothing -> xs
+ _ -> xs
+ wrapDir = case lookup "dir" kvs of
+ Just "rtl" -> align "RTL"
+ Just "ltr" -> align "LTR"
+ _ -> id
+ wrapLang txt = case lang of
+ Just lng -> let (l, o) = toPolyglossiaEnv lng
+ ops = if null o
+ then ""
+ else brackets $ text o
+ in inCmd "begin" (text l) <> ops
+ $$ blankline <> txt <> blankline
+ $$ inCmd "end" (text l)
+ Nothing -> txt
+ return $ wrapColumns . wrapColumn . wrapDir . wrapLang $ t
+
hypertarget :: PandocMonad m => Bool -> String -> Doc Text -> LW m (Doc Text)
hypertarget _ "" x = return x
hypertarget addnewline ident x = do