aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorNathan Gass <gass@search.ch>2010-12-13 21:18:01 +0100
committerJohn MacFarlane <jgm@berkeley.edu>2010-12-13 20:41:37 -0800
commit48600fd5473d1a3c596c6ac8c29f1d7b17f1dc92 (patch)
tree71119dae7eb1673f818891ce9a6f415faf527999 /src
parent1a4a0d0283ef915d0e10fcb24027ff8bc93154e5 (diff)
downloadpandoc-48600fd5473d1a3c596c6ac8c29f1d7b17f1dc92.tar.gz
Added support to write natbib or biblatex citations in latex output.
Diffstat (limited to 'src')
-rw-r--r--src/Text/Pandoc.hs1
-rw-r--r--src/Text/Pandoc/Shared.hs10
-rw-r--r--src/Text/Pandoc/Writers/LaTeX.hs118
-rw-r--r--src/pandoc.hs37
4 files changed, 148 insertions, 18 deletions
diff --git a/src/Text/Pandoc.hs b/src/Text/Pandoc.hs
index 7d3468461..61d1098b9 100644
--- a/src/Text/Pandoc.hs
+++ b/src/Text/Pandoc.hs
@@ -97,6 +97,7 @@ module Text.Pandoc
, WriterOptions (..)
, HTMLSlideVariant (..)
, HTMLMathMethod (..)
+ , CiteMethod (..)
, defaultWriterOptions
-- * Rendering templates and default templates
, module Text.Pandoc.Templates
diff --git a/src/Text/Pandoc/Shared.hs b/src/Text/Pandoc/Shared.hs
index ee959931d..1975b7e4c 100644
--- a/src/Text/Pandoc/Shared.hs
+++ b/src/Text/Pandoc/Shared.hs
@@ -66,6 +66,7 @@ module Text.Pandoc.Shared (
headerShift,
-- * Writer options
HTMLMathMethod (..),
+ CiteMethod (..),
ObfuscationMethod (..),
HTMLSlideVariant (..),
WriterOptions (..),
@@ -472,6 +473,11 @@ data HTMLMathMethod = PlainMath
| MathJax String -- url of MathJax.js
deriving (Show, Read, Eq)
+data CiteMethod = Citeproc -- use citeproc to render them
+ | Natbib -- output natbib cite commands
+ | Biblatex -- output biblatex cite commands
+ deriving (Show, Read, Eq)
+
-- | Methods for obfuscating email addresses in HTML.
data ObfuscationMethod = NoObfuscation
| ReferenceObfuscation
@@ -507,6 +513,8 @@ data WriterOptions = WriterOptions
, writerIdentifierPrefix :: String -- ^ Prefix for section & note ids in HTML
, writerSourceDirectory :: FilePath -- ^ Directory path of 1st source file
, writerUserDataDir :: Maybe FilePath -- ^ Path of user data directory
+ , writerCiteMethod :: CiteMethod -- ^ How to print cites
+ , writerBiblioFile :: String -- ^ Biblio file to use for citations
} deriving Show
-- | Default writer options.
@@ -533,6 +541,8 @@ defaultWriterOptions =
, writerIdentifierPrefix = ""
, writerSourceDirectory = "."
, writerUserDataDir = Nothing
+ , writerCiteMethod = Citeproc
+ , writerBiblioFile = ""
}
--
diff --git a/src/Text/Pandoc/Writers/LaTeX.hs b/src/Text/Pandoc/Writers/LaTeX.hs
index 0f5ae0eb2..e791d1332 100644
--- a/src/Text/Pandoc/Writers/LaTeX.hs
+++ b/src/Text/Pandoc/Writers/LaTeX.hs
@@ -32,7 +32,7 @@ import Text.Pandoc.Definition
import Text.Pandoc.Shared
import Text.Pandoc.Templates
import Text.Printf ( printf )
-import Data.List ( (\\), isSuffixOf, isPrefixOf, intersperse )
+import Data.List ( (\\), isSuffixOf, isPrefixOf, intersperse, intercalate )
import Data.Char ( toLower )
import Control.Monad.State
import Text.PrettyPrint.HughesPJ hiding ( Str )
@@ -76,7 +76,16 @@ pandocToLaTeX options (Pandoc (Meta title authors date) blocks) = do
body <- blockListToLaTeX blocks
let main = render body
st <- get
- let context = writerVariables options ++
+ let biblio = takeWhile ((/=) '.') $ writerBiblioFile options
+ citecontext = case writerCiteMethod options of
+ Natbib -> [ ("biblio", biblio)
+ , ("natbib", "yes")
+ ]
+ Biblatex -> [ ("biblio", biblio)
+ , ("biblatex", "yes")
+ ]
+ _ -> []
+ context = writerVariables options ++
[ ("toc", if writerTableOfContents options then "yes" else "")
, ("body", main)
, ("title", titletext)
@@ -91,7 +100,8 @@ pandocToLaTeX options (Pandoc (Meta title authors date) blocks) = do
[ ("url", "yes") | stUrl st ] ++
[ ("numbersections", "yes") | writerNumberSections options ] ++
[ ("lhs", "yes") | stLHS st ] ++
- [ ("graphics", "yes") | stGraphics st ]
+ [ ("graphics", "yes") | stGraphics st ] ++
+ citecontext
return $ if writerStandalone options
then renderTemplate context template
else main
@@ -298,8 +308,14 @@ inlineToLaTeX (Subscript lst) = do
return $ inCmd "textsubscr" contents
inlineToLaTeX (SmallCaps lst) =
inlineListToLaTeX (deVerb lst) >>= return . inCmd "textsc"
-inlineToLaTeX (Cite _ lst) =
- inlineListToLaTeX lst
+inlineToLaTeX (Cite cits lst) = do
+ st <- get
+ let opts = stOptions st
+ case writerCiteMethod opts of
+ Natbib -> citationsToNatbib cits
+ Biblatex -> citationsToBiblatex cits
+ _ -> inlineListToLaTeX lst
+
inlineToLaTeX (Code str) = do
st <- get
when (stInNote st) $ modify $ \s -> s{ stVerbInNote = True }
@@ -355,3 +371,95 @@ inlineToLaTeX (Note contents) = do
let optNewline = "\\end{Verbatim}" `isSuffixOf` rawnote
return $ text "\\footnote{" <>
text rawnote <> (if optNewline then char '\n' else empty) <> char '}'
+
+
+citationsToNatbib :: [Citation] -> State WriterState Doc
+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 = and . map (null . citationPrefix)
+ noSuffix = and . map (null . citationSuffix)
+ ismode m = and . map (((==) m) . citationMode)
+ p = citationPrefix $ head $ cits
+ s = citationSuffix $ last $ cits
+ ks = 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 :: String -> [Inline] -> [Inline] -> String -> State WriterState Doc
+citeCommand c p s k = do
+ args <- citeArguments p s k
+ return $ text ("\\" ++ c) <> args
+
+citeArguments :: [Inline] -> [Inline] -> String -> State WriterState Doc
+citeArguments p s k = do
+ pdoc <- inlineListToLaTeX p
+ sdoc <- inlineListToLaTeX s
+ let optargs = case (isEmpty pdoc, isEmpty sdoc) of
+ (True, True ) -> empty
+ (True, False) -> brackets sdoc
+ (_ , _ ) -> brackets pdoc <> brackets sdoc
+ return $ optargs <> braces (text k)
+
+citationsToBiblatex :: [Citation] -> State WriterState Doc
+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) = do
+ args <- mapM convertOne (c:cs)
+ return $ text cmd <> foldl (<>) empty args
+ where
+ cmd = case citationMode c of
+ AuthorInText -> "\\textcites"
+ _ -> "\\autocites"
+ convertOne Citation { citationId = k
+ , citationPrefix = p
+ , citationSuffix = s
+ }
+ = citeArguments p s k
+
+citationsToBiblatex _ = return empty
diff --git a/src/pandoc.hs b/src/pandoc.hs
index 13f285f15..87e72298a 100644
--- a/src/pandoc.hs
+++ b/src/pandoc.hs
@@ -116,7 +116,8 @@ data Opt = Opt
, optIdentifierPrefix :: String
, optIndentedCodeClasses :: [String] -- ^ Default classes for indented code blocks
, optDataDir :: Maybe FilePath
- , optBibliography :: [Reference]
+ , optCiteMethod :: CiteMethod -- ^ Method to output cites
+ , optBibliography :: [String]
, optCslFile :: FilePath
}
@@ -154,6 +155,7 @@ defaultOpts = Opt
, optIdentifierPrefix = ""
, optIndentedCodeClasses = []
, optDataDir = Nothing
+ , optCiteMethod = Citeproc
, optBibliography = []
, optCslFile = ""
}
@@ -453,14 +455,7 @@ options =
"" -- "Print default template for FORMAT"
, Option "" ["bibliography"]
(ReqArg
- (\arg opt -> do
- refs <- catch (readBiblioFile arg) $ \e -> do
- UTF8.hPutStrLn stderr $
- "Error reading bibliography `" ++ arg ++ "'"
- UTF8.hPutStrLn stderr $ show e
- exitWith (ExitFailure 23)
- return opt { optBibliography =
- optBibliography opt ++ refs } )
+ (\arg opt -> return opt { optBibliography = (optBibliography opt) ++ [arg] })
"FILENAME")
""
, Option "" ["csl"]
@@ -468,6 +463,14 @@ options =
(\arg opt -> return opt { optCslFile = arg })
"FILENAME")
""
+ , Option "" ["natbib"]
+ (NoArg
+ (\opt -> return opt { optCiteMethod = Natbib }))
+ "" -- "Use natbib cite commands in LaTeX output"
+ , Option "" ["biblatex"]
+ (NoArg
+ (\opt -> return opt { optCiteMethod = Biblatex }))
+ "" -- "Use biblatex cite commands in LaTeX output"
, Option "" ["data-dir"]
(ReqArg
(\arg opt -> return opt { optDataDir = Just arg })
@@ -618,8 +621,9 @@ main = do
, optIdentifierPrefix = idPrefix
, optIndentedCodeClasses = codeBlockClasses
, optDataDir = mbDataDir
- , optBibliography = refs
+ , optBibliography = reffiles
, optCslFile = cslfile
+ , optCiteMethod = citeMethod
} = opts
when dumpArgs $
@@ -693,6 +697,11 @@ main = do
return $ ("mathml-script", s) : variables'
_ -> return variables'
+ refs <- mapM (\f -> catch (readBiblioFile f) $ \e -> do
+ UTF8.hPutStrLn stderr $ "Error reading bibliography `" ++ f ++ "'"
+ UTF8.hPutStrLn stderr $ show e
+ exitWith (ExitFailure 23)) reffiles >>= \rs -> return $ concat rs
+
let sourceDir = if null sources
then "."
else takeDirectory (head sources)
@@ -729,6 +738,8 @@ main = do
writerSlideVariant = slideVariant,
writerIncremental = incremental,
writerXeTeX = xetex,
+ writerCiteMethod = citeMethod,
+ writerBiblioFile = head reffiles,
writerIgnoreNotes = False,
writerNumberSections = numberSections,
writerSectionDivs = sectionDivs,
@@ -766,9 +777,8 @@ main = do
let doc' = foldr ($) doc transforms
doc'' <- do
- if null refs
- then return doc'
- else do
+ if citeMethod == Citeproc && not (null refs)
+ then do
csldir <- getAppUserDataDirectory "csl"
cslfile' <- if null cslfile
then findDataFile datadir "default.csl"
@@ -781,6 +791,7 @@ main = do
(replaceExtension cslfile "csl")
csldir
processBiblio cslfile' refs doc'
+ else return doc'
writerOutput <- writer writerOptions doc''