aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--pandoc.cabal1
-rw-r--r--src/Text/Pandoc/Writers/LaTeX.hs148
-rw-r--r--src/Text/Pandoc/Writers/LaTeX/Citation.hs181
3 files changed, 188 insertions, 142 deletions
diff --git a/pandoc.cabal b/pandoc.cabal
index 416641a96..135ee2f26 100644
--- a/pandoc.cabal
+++ b/pandoc.cabal
@@ -666,6 +666,7 @@ library
Text.Pandoc.Writers.LaTeX.Table,
Text.Pandoc.Writers.LaTeX.Lang,
Text.Pandoc.Writers.LaTeX.Types,
+ Text.Pandoc.Writers.LaTeX.Citation,
Text.Pandoc.Writers.Markdown.Types,
Text.Pandoc.Writers.Markdown.Inline,
Text.Pandoc.Writers.Roff,
diff --git a/src/Text/Pandoc/Writers/LaTeX.hs b/src/Text/Pandoc/Writers/LaTeX.hs
index 6b1d44b23..84c96a507 100644
--- a/src/Text/Pandoc/Writers/LaTeX.hs
+++ b/src/Text/Pandoc/Writers/LaTeX.hs
@@ -20,9 +20,8 @@ module Text.Pandoc.Writers.LaTeX (
) where
import Control.Applicative ((<|>))
import Control.Monad.State.Strict
-import Data.Char (isAlphaNum, isAscii, isDigit, isLetter, isSpace,
- isPunctuation, ord)
-import Data.List (foldl', intersperse, nubBy, (\\), uncons)
+import Data.Char (isAlphaNum, isAscii, isDigit, isLetter, isSpace, ord)
+import Data.List (intersperse, nubBy, (\\), uncons)
import Data.Maybe (catMaybes, fromMaybe, isJust, mapMaybe, isNothing)
import qualified Data.Map as M
import Data.Text (Text)
@@ -44,6 +43,8 @@ import Text.Pandoc.Slides
import Text.Pandoc.Walk (query, walk, walkM)
import Text.Pandoc.Writers.LaTeX.Caption (getCaption)
import Text.Pandoc.Writers.LaTeX.Table (tableToLaTeX)
+import Text.Pandoc.Writers.LaTeX.Citation (citationsToNatbib,
+ citationsToBiblatex)
import Text.Pandoc.Writers.LaTeX.Types (LW, WriterState (..), startingState)
import Text.Pandoc.Writers.LaTeX.Lang (toPolyglossiaEnv, toPolyglossia,
toBabel)
@@ -1026,8 +1027,8 @@ inlineToLaTeX (Cite cits lst) = do
st <- get
let opts = stOptions st
case writerCiteMethod opts of
- Natbib -> citationsToNatbib cits
- Biblatex -> citationsToBiblatex cits
+ Natbib -> citationsToNatbib inlineListToLaTeX cits
+ Biblatex -> citationsToBiblatex inlineListToLaTeX cits
_ -> inlineListToLaTeX lst
inlineToLaTeX (Code (_,classes,kvs) str) = do
@@ -1238,143 +1239,6 @@ protectCode x = [x]
setEmptyLine :: PandocMonad m => Bool -> LW m ()
setEmptyLine b = modify $ \st -> st{ stEmptyLine = b }
-citationsToNatbib :: PandocMonad m => [Citation] -> LW m (Doc Text)
-citationsToNatbib
- [one]
- = citeCommand c p s k
- where
- Citation { citationId = k
- , citationPrefix = p
- , citationSuffix = s
- , citationMode = m
- }
- = one
- c = case m of
- AuthorInText -> "citet"
- SuppressAuthor -> "citeyearpar"
- NormalCitation -> "citep"
-
-citationsToNatbib cits
- | noPrefix (tail cits) && noSuffix (init cits) && ismode NormalCitation cits
- = citeCommand "citep" p s ks
- where
- noPrefix = all (null . citationPrefix)
- noSuffix = all (null . citationSuffix)
- ismode m = all ((==) m . citationMode)
- p = citationPrefix $
- head cits
- s = citationSuffix $
- last cits
- ks = T.intercalate ", " $ map citationId cits
-
-citationsToNatbib (c:cs) | citationMode c == AuthorInText = do
- author <- citeCommand "citeauthor" [] [] (citationId c)
- cits <- citationsToNatbib (c { citationMode = SuppressAuthor } : cs)
- return $ author <+> cits
-
-citationsToNatbib cits = do
- cits' <- mapM convertOne cits
- return $ text "\\citetext{" <> foldl' combineTwo empty cits' <> text "}"
- where
- combineTwo a b | isEmpty a = b
- | otherwise = a <> text "; " <> b
- convertOne Citation { citationId = k
- , citationPrefix = p
- , citationSuffix = s
- , citationMode = m
- }
- = case m of
- AuthorInText -> citeCommand "citealt" p s k
- SuppressAuthor -> citeCommand "citeyear" p s k
- NormalCitation -> citeCommand "citealp" p s k
-
-citeCommand :: PandocMonad m
- => Text -> [Inline] -> [Inline] -> Text -> LW m (Doc Text)
-citeCommand c p s k = do
- args <- citeArguments p s k
- return $ literal ("\\" <> c) <> args
-
-type Prefix = [Inline]
-type Suffix = [Inline]
-type CiteId = Text
-data CiteGroup = CiteGroup Prefix Suffix [CiteId]
-
-citeArgumentsList :: PandocMonad m
- => CiteGroup -> LW m (Doc Text)
-citeArgumentsList (CiteGroup _ _ []) = return empty
-citeArgumentsList (CiteGroup pfxs sfxs ids) = do
- pdoc <- inlineListToLaTeX pfxs
- sdoc <- inlineListToLaTeX sfxs'
- return $ optargs pdoc sdoc <>
- braces (literal (T.intercalate "," (reverse ids)))
- where sfxs' = stripLocatorBraces $ case sfxs of
- (Str t : r) -> case T.uncons t of
- Just (x, xs)
- | T.null xs
- , isPunctuation x -> dropWhile (== Space) r
- | isPunctuation x -> Str xs : r
- _ -> sfxs
- _ -> sfxs
- optargs pdoc sdoc = case (isEmpty pdoc, isEmpty sdoc) of
- (True, True ) -> empty
- (True, False) -> brackets sdoc
- (_ , _ ) -> brackets pdoc <> brackets sdoc
-
-citeArguments :: PandocMonad m
- => [Inline] -> [Inline] -> Text -> LW m (Doc Text)
-citeArguments p s k = citeArgumentsList (CiteGroup p s [k])
-
--- strip off {} used to define locator in pandoc-citeproc; see #5722
-stripLocatorBraces :: [Inline] -> [Inline]
-stripLocatorBraces = walk go
- where go (Str xs) = Str $ T.filter (\c -> c /= '{' && c /= '}') xs
- go x = x
-
-citationsToBiblatex :: PandocMonad m => [Citation] -> LW m (Doc Text)
-citationsToBiblatex
- [one]
- = citeCommand cmd p s k
- where
- Citation { citationId = k
- , citationPrefix = p
- , citationSuffix = s
- , citationMode = m
- } = one
- cmd = case m of
- SuppressAuthor -> "autocite*"
- AuthorInText -> "textcite"
- NormalCitation -> "autocite"
-
-citationsToBiblatex (c:cs)
- | all (\cit -> null (citationPrefix cit) && null (citationSuffix cit)) (c:cs)
- = do
- let cmd = case citationMode c of
- SuppressAuthor -> "\\autocite*"
- AuthorInText -> "\\textcite"
- NormalCitation -> "\\autocite"
- return $ text cmd <>
- braces (literal (T.intercalate "," (map citationId (c:cs))))
- | otherwise
- = do
- let cmd = case citationMode c of
- SuppressAuthor -> "\\autocites*"
- AuthorInText -> "\\textcites"
- NormalCitation -> "\\autocites"
-
- groups <- mapM citeArgumentsList (reverse (foldl' grouper [] (c:cs)))
-
- return $ text cmd <> mconcat groups
-
- where grouper prev cit = case prev of
- ((CiteGroup oPfx oSfx ids):rest)
- | null oSfx && null pfx -> CiteGroup oPfx sfx (cid:ids) : rest
- _ -> CiteGroup pfx sfx [cid] : prev
- where pfx = citationPrefix cit
- sfx = citationSuffix cit
- cid = citationId cit
-
-citationsToBiblatex _ = return empty
-
-- Extract a key from divs and spans
extract :: Text -> Block -> [Text]
extract key (Div attr _) = lookKey key attr
diff --git a/src/Text/Pandoc/Writers/LaTeX/Citation.hs b/src/Text/Pandoc/Writers/LaTeX/Citation.hs
new file mode 100644
index 000000000..f48a43d7a
--- /dev/null
+++ b/src/Text/Pandoc/Writers/LaTeX/Citation.hs
@@ -0,0 +1,181 @@
+{-# LANGUAGE OverloadedStrings #-}
+{- |
+ Module : Text.Pandoc.Writers.LaTeX.Citation
+ Copyright : Copyright (C) 2006-2021 John MacFarlane
+ License : GNU GPL, version 2 or above
+
+ Maintainer : John MacFarlane <jgm@berkeley.edu>
+ Stability : alpha
+ Portability : portable
+-}
+module Text.Pandoc.Writers.LaTeX.Citation
+ ( citationsToNatbib,
+ citationsToBiblatex
+ ) where
+
+import Data.Text (Text)
+import Data.Char (isPunctuation)
+import qualified Data.Text as T
+import Text.Pandoc.Class.PandocMonad (PandocMonad)
+import Text.Pandoc.Definition
+import Data.List (foldl')
+import Text.DocLayout (Doc, brackets, empty, (<+>), text, isEmpty, literal,
+ braces)
+import Text.Pandoc.Walk
+import Text.Pandoc.Writers.LaTeX.Types ( LW )
+
+citationsToNatbib :: PandocMonad m
+ => ([Inline] -> LW m (Doc Text))
+ -> [Citation]
+ -> LW m (Doc Text)
+citationsToNatbib inlineListToLaTeX [one]
+ = citeCommand inlineListToLaTeX c p s k
+ where
+ Citation { citationId = k
+ , citationPrefix = p
+ , citationSuffix = s
+ , citationMode = m
+ }
+ = one
+ c = case m of
+ AuthorInText -> "citet"
+ SuppressAuthor -> "citeyearpar"
+ NormalCitation -> "citep"
+
+citationsToNatbib inlineListToLaTeX cits
+ | noPrefix (tail cits) && noSuffix (init cits) && ismode NormalCitation cits
+ = citeCommand inlineListToLaTeX "citep" p s ks
+ where
+ noPrefix = all (null . citationPrefix)
+ noSuffix = all (null . citationSuffix)
+ ismode m = all ((==) m . citationMode)
+ p = citationPrefix $
+ head cits
+ s = citationSuffix $
+ last cits
+ ks = T.intercalate ", " $ map citationId cits
+
+citationsToNatbib inlineListToLaTeX (c:cs)
+ | citationMode c == AuthorInText = do
+ author <- citeCommand inlineListToLaTeX "citeauthor" [] [] (citationId c)
+ cits <- citationsToNatbib inlineListToLaTeX
+ (c { citationMode = SuppressAuthor } : cs)
+ return $ author <+> cits
+
+citationsToNatbib inlineListToLaTeX cits = do
+ cits' <- mapM convertOne cits
+ return $ text "\\citetext{" <> foldl' combineTwo empty cits' <> text "}"
+ where
+ citeCommand' = citeCommand inlineListToLaTeX
+ combineTwo a b | isEmpty a = b
+ | otherwise = a <> text "; " <> b
+ convertOne Citation { citationId = k
+ , citationPrefix = p
+ , citationSuffix = s
+ , citationMode = m
+ }
+ = case m of
+ AuthorInText -> citeCommand' "citealt" p s k
+ SuppressAuthor -> citeCommand' "citeyear" p s k
+ NormalCitation -> citeCommand' "citealp" p s k
+
+citeCommand :: PandocMonad m
+ => ([Inline] -> LW m (Doc Text))
+ -> Text
+ -> [Inline]
+ -> [Inline]
+ -> Text
+ -> LW m (Doc Text)
+citeCommand inlineListToLaTeX c p s k = do
+ args <- citeArguments inlineListToLaTeX p s k
+ return $ literal ("\\" <> c) <> args
+
+type Prefix = [Inline]
+type Suffix = [Inline]
+type CiteId = Text
+data CiteGroup = CiteGroup Prefix Suffix [CiteId]
+
+citeArgumentsList :: PandocMonad m
+ => ([Inline] -> LW m (Doc Text))
+ -> CiteGroup
+ -> LW m (Doc Text)
+citeArgumentsList _inlineListToLaTeX (CiteGroup _ _ []) = return empty
+citeArgumentsList inlineListToLaTeX (CiteGroup pfxs sfxs ids) = do
+ pdoc <- inlineListToLaTeX pfxs
+ sdoc <- inlineListToLaTeX sfxs'
+ return $ optargs pdoc sdoc <>
+ braces (literal (T.intercalate "," (reverse ids)))
+ where sfxs' = stripLocatorBraces $ case sfxs of
+ (Str t : r) -> case T.uncons t of
+ Just (x, xs)
+ | T.null xs
+ , isPunctuation x -> dropWhile (== Space) r
+ | isPunctuation x -> Str xs : r
+ _ -> sfxs
+ _ -> sfxs
+ optargs pdoc sdoc = case (isEmpty pdoc, isEmpty sdoc) of
+ (True, True ) -> empty
+ (True, False) -> brackets sdoc
+ (_ , _ ) -> brackets pdoc <> brackets sdoc
+
+citeArguments :: PandocMonad m
+ => ([Inline] -> LW m (Doc Text))
+ -> [Inline]
+ -> [Inline]
+ -> Text
+ -> LW m (Doc Text)
+citeArguments inlineListToLaTeX p s k =
+ citeArgumentsList inlineListToLaTeX (CiteGroup p s [k])
+
+-- strip off {} used to define locator in pandoc-citeproc; see #5722
+stripLocatorBraces :: [Inline] -> [Inline]
+stripLocatorBraces = walk go
+ where go (Str xs) = Str $ T.filter (\c -> c /= '{' && c /= '}') xs
+ go x = x
+
+citationsToBiblatex :: PandocMonad m
+ => ([Inline] -> LW m (Doc Text))
+ -> [Citation] -> LW m (Doc Text)
+citationsToBiblatex inlineListToLaTeX [one]
+ = citeCommand inlineListToLaTeX cmd p s k
+ where
+ Citation { citationId = k
+ , citationPrefix = p
+ , citationSuffix = s
+ , citationMode = m
+ } = one
+ cmd = case m of
+ SuppressAuthor -> "autocite*"
+ AuthorInText -> "textcite"
+ NormalCitation -> "autocite"
+
+citationsToBiblatex inlineListToLaTeX (c:cs)
+ | all (\cit -> null (citationPrefix cit) && null (citationSuffix cit)) (c:cs)
+ = do
+ let cmd = case citationMode c of
+ SuppressAuthor -> "\\autocite*"
+ AuthorInText -> "\\textcite"
+ NormalCitation -> "\\autocite"
+ return $ text cmd <>
+ braces (literal (T.intercalate "," (map citationId (c:cs))))
+ | otherwise
+ = do
+ let cmd = case citationMode c of
+ SuppressAuthor -> "\\autocites*"
+ AuthorInText -> "\\textcites"
+ NormalCitation -> "\\autocites"
+
+ groups <- mapM (citeArgumentsList inlineListToLaTeX)
+ (reverse (foldl' grouper [] (c:cs)))
+
+ return $ text cmd <> mconcat groups
+
+ where grouper prev cit = case prev of
+ ((CiteGroup oPfx oSfx ids):rest)
+ | null oSfx && null pfx -> CiteGroup oPfx sfx (cid:ids) : rest
+ _ -> CiteGroup pfx sfx [cid] : prev
+ where pfx = citationPrefix cit
+ sfx = citationSuffix cit
+ cid = citationId cit
+
+citationsToBiblatex _ _ = return empty