    {-# LANGUAGE OverloadedStrings #-}
    {- |
       Module      : Text.Pandoc.Writers.BibTeX
       Copyright   : Copyright (C) 2021-2024 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