{-# LANGUAGE OverloadedStrings #-}
{- |
   Module      : Text.Pandoc.Writers.BibTeX
   Copyright   : Copyright (C) 2021-2023 John MacFarlane
   License     : GNU GPL, version 2 or above

   Maintainer  : John MacFarlane <jgm@berkeley.edu>
   Stability   : alpha
   Portability : portable

Writes a BibTeX or BibLaTeX bibliographies based on the
'references' metadata in a Pandoc document.
-}
module Text.Pandoc.Writers.BibTeX
  ( writeBibTeX
  , writeBibLaTeX
  )
where

import Text.Pandoc.Options
import Text.Pandoc.Definition
import Data.Text (Text)
import Data.Maybe (mapMaybe)
import Citeproc (parseLang)
import Text.Pandoc.Class (PandocMonad)
import Text.Pandoc.Citeproc.BibTeX as BibTeX
import Text.Pandoc.Citeproc.MetaValue (metaValueToReference)
import Text.Pandoc.Writers.Shared (lookupMetaString, defField,
                                    addVariablesToContext)
import Text.DocLayout (render, vcat)
import Text.DocTemplates (Context(..))
import Text.Pandoc.Templates (renderTemplate)

-- | Write BibTeX based on the references metadata from a Pandoc document.
writeBibTeX :: PandocMonad m => WriterOptions -> Pandoc -> m Text
writeBibTeX :: forall (m :: * -> *).
PandocMonad m =>
WriterOptions -> Pandoc -> m Text
writeBibTeX = forall (m :: * -> *).
PandocMonad m =>
Variant -> WriterOptions -> Pandoc -> m Text
writeBibTeX' Variant
BibTeX.Bibtex

-- | Write BibLaTeX based on the references metadata from a Pandoc document.
writeBibLaTeX :: PandocMonad m => WriterOptions -> Pandoc -> m Text
writeBibLaTeX :: forall (m :: * -> *).
PandocMonad m =>
WriterOptions -> Pandoc -> m Text
writeBibLaTeX = forall (m :: * -> *).
PandocMonad m =>
Variant -> WriterOptions -> Pandoc -> m Text
writeBibTeX' Variant
BibTeX.Biblatex

writeBibTeX' :: PandocMonad m => Variant -> WriterOptions -> Pandoc -> m Text
writeBibTeX' :: forall (m :: * -> *).
PandocMonad m =>
Variant -> WriterOptions -> Pandoc -> m Text
writeBibTeX' Variant
variant WriterOptions
opts (Pandoc Meta
meta [Block]
_) = do
  let mblang :: Maybe Lang
mblang = case Text -> Meta -> Text
lookupMetaString Text
"lang" Meta
meta of
                 Text
"" -> forall a. Maybe a
Nothing
                 Text
t  -> forall a c b. (a -> c) -> (b -> c) -> Either a b -> c
either (forall a b. a -> b -> a
const forall a. Maybe a
Nothing) forall a. a -> Maybe a
Just forall a b. (a -> b) -> a -> b
$ Text -> Either String Lang
parseLang Text
t
  let refs :: [Reference Inlines]
refs = case Text -> Meta -> Maybe MetaValue
lookupMeta Text
"references" Meta
meta of
               Just (MetaList [MetaValue]
xs) -> forall a b. (a -> Maybe b) -> [a] -> [b]
mapMaybe MetaValue -> Maybe (Reference Inlines)
metaValueToReference [MetaValue]
xs
               Maybe MetaValue
_ -> []
  let main :: Doc Text
main = forall a. [Doc a] -> Doc a
vcat forall a b. (a -> b) -> a -> b
$ forall a b. (a -> b) -> [a] -> [b]
map (WriterOptions
-> Variant -> Maybe Lang -> Reference Inlines -> Doc Text
BibTeX.writeBibtexString WriterOptions
opts Variant
variant Maybe Lang
mblang) [Reference Inlines]
refs
  let context :: Context Text
context  = forall a b. ToContext a b => Text -> b -> Context a -> Context a
defField Text
"body" Doc Text
main
                 forall a b. (a -> b) -> a -> b
$ forall a.
TemplateTarget a =>
WriterOptions -> Context a -> Context a
addVariablesToContext WriterOptions
opts (forall a. Monoid a => a
mempty :: Context Text)
  let colwidth :: Maybe Int
colwidth = if WriterOptions -> WrapOption
writerWrapText WriterOptions
opts forall a. Eq a => a -> a -> Bool
== WrapOption
WrapAuto
                    then forall a. a -> Maybe a
Just forall a b. (a -> b) -> a -> b
$ WriterOptions -> Int
writerColumns WriterOptions
opts
                    else forall a. Maybe a
Nothing
  forall (m :: * -> *) a. Monad m => a -> m a
return forall a b. (a -> b) -> a -> b
$ forall a. HasChars a => Maybe Int -> Doc a -> a
render Maybe Int
colwidth forall a b. (a -> b) -> a -> b
$
    case WriterOptions -> Maybe (Template Text)
writerTemplate WriterOptions
opts of
      Maybe (Template Text)
Nothing  -> Doc Text
main
      Just Template Text
tpl -> forall a b.
(TemplateTarget a, ToContext a b) =>
Template a -> b -> Doc a
renderTemplate Template Text
tpl Context Text
context