{-# 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 = Variant -> WriterOptions -> Pandoc -> m Text
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 = Variant -> WriterOptions -> Pandoc -> m Text
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
"" -> Maybe Lang
forall a. Maybe a
Nothing
                 Text
t  -> (String -> Maybe Lang)
-> (Lang -> Maybe Lang) -> Either String Lang -> Maybe Lang
forall a c b. (a -> c) -> (b -> c) -> Either a b -> c
either (Maybe Lang -> String -> Maybe Lang
forall a b. a -> b -> a
const Maybe Lang
forall a. Maybe a
Nothing) Lang -> Maybe Lang
forall a. a -> Maybe a
Just (Either String Lang -> Maybe Lang)
-> Either String Lang -> Maybe Lang
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) -> (MetaValue -> Maybe (Reference Inlines))
-> [MetaValue] -> [Reference Inlines]
forall a b. (a -> Maybe b) -> [a] -> [b]
mapMaybe MetaValue -> Maybe (Reference Inlines)
metaValueToReference [MetaValue]
xs
               Maybe MetaValue
_ -> []
  let main :: Doc Text
main = [Doc Text] -> Doc Text
forall a. [Doc a] -> Doc a
vcat ([Doc Text] -> Doc Text) -> [Doc Text] -> Doc Text
forall a b. (a -> b) -> a -> b
$ (Reference Inlines -> Doc Text)
-> [Reference Inlines] -> [Doc Text]
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  = Text -> Doc Text -> Context Text -> Context Text
forall a b. ToContext a b => Text -> b -> Context a -> Context a
defField Text
"body" Doc Text
main
                 (Context Text -> Context Text) -> Context Text -> Context Text
forall a b. (a -> b) -> a -> b
$ WriterOptions -> Context Text -> Context Text
forall a.
TemplateTarget a =>
WriterOptions -> Context a -> Context a
addVariablesToContext WriterOptions
opts (Context Text
forall a. Monoid a => a
mempty :: Context Text)
  let colwidth :: Maybe Int
colwidth = if WriterOptions -> WrapOption
writerWrapText WriterOptions
opts WrapOption -> WrapOption -> Bool
forall a. Eq a => a -> a -> Bool
== WrapOption
WrapAuto
                    then Int -> Maybe Int
forall a. a -> Maybe a
Just (Int -> Maybe Int) -> Int -> Maybe Int
forall a b. (a -> b) -> a -> b
$ WriterOptions -> Int
writerColumns WriterOptions
opts
                    else Maybe Int
forall a. Maybe a
Nothing
  Text -> m Text
forall a. a -> m a
forall (m :: * -> *) a. Monad m => a -> m a
return (Text -> m Text) -> Text -> m Text
forall a b. (a -> b) -> a -> b
$ Maybe Int -> Doc Text -> Text
forall a. HasChars a => Maybe Int -> Doc a -> a
render Maybe Int
colwidth (Doc Text -> Text) -> Doc Text -> Text
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 -> Template Text -> Context Text -> Doc Text
forall a b.
(TemplateTarget a, ToContext a b) =>
Template a -> b -> Doc a
renderTemplate Template Text
tpl Context Text
context