{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE DeriveGeneric     #-}
{-# LANGUAGE DeriveFunctor     #-}
{-# LANGUAGE FlexibleContexts  #-}

-- | <https://ctan.org/tex-archive/macros/latex/contrib/biblatex BibLaTeX>
--   is a reference-citation package using @.bib@ files (BibTeX) but no extra style-files.
--
module Text.LaTeX.Packages.BibLaTeX
 ( biblatex
 , addbibresource
 , cite
 , printbibliography
 -- * Automatic bibliography retrieval
 , documentWithDOIReferences
 , PlainDOI
 , citeDOI
 , textc
 , textC
 , DOIReference
 , ReferenceQueryT
 , applyDOIReferenceResolves
 , masterBibFile
 ) where

import Text.LaTeX.Base.Syntax hiding ((<>))
import Text.LaTeX.Base.Class (LaTeXC(..), liftL, fromLaTeX, comm0, raw)
import Text.LaTeX.Base.Render
import Text.LaTeX.Base.Types
import Text.LaTeX.Base.Commands (cite, footnote, document)

import Data.Char (toLower)
import qualified Data.Semigroup as SG
import GHC.Generics (Generic)
import qualified Data.Traversable as Tr

import qualified Data.Map as Map
import Data.Maybe (catMaybes)
import Data.Hashable (hash)
import Numeric (showHex)

import qualified Data.List as List

import Control.Applicative
import Control.Monad (forM)
import Control.Monad.IO.Class

import qualified Text.BibTeX.Entry as BibTeX
import qualified Text.BibTeX.Format as BibTeX
import qualified Text.BibTeX.Parse as BibTeX (file)
import qualified Text.Parsec.String as Parsec

-- | BibLaTeX package. Use it to import it like this:
--
-- > usepackage [] biblatex
biblatex :: PackageName
biblatex :: PackageName
biblatex = PackageName
"biblatex"

-- | Use a bibliography file as resource for reference information.
addbibresource :: LaTeXC l => FilePath -> l
addbibresource :: forall l. LaTeXC l => PackageName -> l
addbibresource PackageName
fp = forall l. LaTeXC l => LaTeX -> l
fromLaTeX forall a b. (a -> b) -> a -> b
$ PackageName -> [TeXArg] -> LaTeX
TeXComm PackageName
"addbibresource" [LaTeX -> TeXArg
FixArg forall a b. (a -> b) -> a -> b
$ Text -> LaTeX
TeXRaw forall a b. (a -> b) -> a -> b
$ forall a. IsString a => PackageName -> a
fromString PackageName
fp]

printbibliography :: LaTeXC l => l
printbibliography :: forall l. LaTeXC l => l
printbibliography = forall l. LaTeXC l => PackageName -> l
comm0 PackageName
"printbibliography"


-- | All-inclusive preparation of a document containing DOI references.
--   Uses 'applyDOIReferenceResolves' under the hood.
documentWithDOIReferences :: (MonadIO m, LaTeXC (m ()), SG.Semigroup (m ()), r ~ DOIReference)
  => (r -> m (Maybe BibTeX.T)) -- ^ Reference-resolver function, for looking up BibTeX
                               --   entries for a given DOI.
                               --   If the DOI cannot be looked up (@Nothing@), we just
                               --   include a footnote with a synopsis and the DOI in
                               --   literal form. (Mostly intended to ease offline editing.)
  -> ReferenceQueryT r m ()    -- ^ The document content, possibly containing citations
                               --   in DOI-only form.
  -> m ()                      -- ^ LaTeX rendition. The content will already be wrapped
                               --   in @\\begin…end{document}@ here and an
                               --   automatically-generated @.bib@ file included, but
                               --   you still need to 'usepackage' 'biblatex' yourself.
documentWithDOIReferences :: forall (m :: * -> *) r.
(MonadIO m, LaTeXC (m ()), Semigroup (m ()), r ~ DOIReference) =>
(r -> m (Maybe T)) -> ReferenceQueryT r m () -> m ()
documentWithDOIReferences r -> m (Maybe T)
resolver ReferenceQueryT r m ()
docW = do
    (Map DOIReference T
refsMap, m ()
docConts) <- forall (m :: * -> *) r.
(MonadIO m, LaTeXC (m ()), Semigroup (m ()), r ~ DOIReference) =>
(r -> m (Maybe T))
-> ReferenceQueryT r m () -> m (Map DOIReference T, m ())
applyDOIReferenceResolves r -> m (Maybe T)
resolver ReferenceQueryT r m ()
docW
    let bibfileConts :: PackageName
bibfileConts = [PackageName] -> PackageName
unlines forall a b. (a -> b) -> a -> b
$ T -> PackageName
BibTeX.entry forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a b. (a, b) -> b
snd forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> forall k a. Map k a -> [(k, a)]
Map.toList Map DOIReference T
refsMap
        bibfileName :: PackageName
bibfileName = forall a. (Integral a, Show a) => a -> ShowS
showHex (forall a. Num a => a -> a
abs forall a b. (a -> b) -> a -> b
$ forall a. Hashable a => a -> Int
hash PackageName
bibfileConts) forall a b. (a -> b) -> a -> b
$ PackageName
".bib"
    forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO forall a b. (a -> b) -> a -> b
$ PackageName -> PackageName -> IO ()
writeFile PackageName
bibfileName PackageName
bibfileConts
    () <- forall l. LaTeXC l => PackageName -> l
addbibresource PackageName
bibfileName
    forall l. LaTeXC l => l -> l
document m ()
docConts
    
-- | More manual version of 'documentWithDOIReferences', only retrieving suitable
--   BibTeX entries for the DOI-references contained in the document, but not
--   generating any @.bib@ files or wrapping the content in it.
applyDOIReferenceResolves :: (MonadIO m, LaTeXC (m ()), SG.Semigroup (m ()), r ~ DOIReference)
  => (r -> m (Maybe BibTeX.T)) -- ^ Reference-resolver function.
  -> ReferenceQueryT r m ()    -- ^ The document content.
  -> m ( Map.Map DOIReference BibTeX.T
       , m ())                 -- ^ All the BibTeX entries found, and a version of the
                               --   document with all its doi-references changed to point to
                               --   the identifiers in that file.
applyDOIReferenceResolves :: forall (m :: * -> *) r.
(MonadIO m, LaTeXC (m ()), Semigroup (m ()), r ~ DOIReference) =>
(r -> m (Maybe T))
-> ReferenceQueryT r m () -> m (Map DOIReference T, m ())
applyDOIReferenceResolves r -> m (Maybe T)
resolver (ReferenceQueryT m (DList r, (), (r -> CitationFlavour -> m ()) -> m ())
refq) = do
    (DList r
allRefs, (), (r -> CitationFlavour -> m ()) -> m ()
useRefs) <- m (DList r, (), (r -> CitationFlavour -> m ()) -> m ())
refq
    [(r, T)]
resolved <- forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
fmap forall a. [Maybe a] -> [a]
catMaybes forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall (t :: * -> *) (m :: * -> *) a b.
(Traversable t, Monad m) =>
t a -> (a -> m b) -> m (t b)
forM (DList r
allRefs[]) forall a b. (a -> b) -> a -> b
$ \r
r -> do
       Maybe T
r' <- r -> m (Maybe T)
resolver r
r
       forall (m :: * -> *) a. Monad m => a -> m a
return forall a b. (a -> b) -> a -> b
$ case Maybe T
r' of
         Just T
entry -> forall a. a -> Maybe a
Just (r
r, T
entry)
         Maybe T
Nothing -> forall a. Maybe a
Nothing
    let refsMap :: Map r T
refsMap = forall k a. Ord k => [(k, a)] -> Map k a
Map.fromList [(r, T)]
resolved
    forall (m :: * -> *) a. Monad m => a -> m a
return (Map r T
refsMap, (r -> CitationFlavour -> m ()) -> m ()
useRefs forall a b. (a -> b) -> a -> b
$ \r
r CitationFlavour
flavour -> case forall k a. Ord k => k -> Map k a -> Maybe a
Map.lookup r
r Map r T
refsMap of
        Just T
a -> let citeC :: m () -> m ()
citeC = forall l. LaTeXC l => (LaTeX -> LaTeX) -> l -> l
liftL forall a b. (a -> b) -> a -> b
$ \LaTeX
l -> (PackageName -> [TeXArg] -> LaTeX
`TeXComm`[LaTeX -> TeXArg
FixArg LaTeX
l]) forall a b. (a -> b) -> a -> b
$ case CitationFlavour
flavour of
                        CitationFlavour
Flavour_cite      -> PackageName
"cite" 
                        CitationFlavour
Flavour_Cite      -> PackageName
"Cite"
                        CitationFlavour
Flavour_parencite -> PackageName
"parencite"
                        CitationFlavour
Flavour_Parencite -> PackageName
"Parencite"
                        CitationFlavour
Flavour_footcite  -> PackageName
"footcite"
                        CitationFlavour
Flavour_Footcite  -> PackageName
"Footcite"
                        CitationFlavour
Flavour_textcite  -> PackageName
"textcite"
                        CitationFlavour
Flavour_Textcite  -> PackageName
"Textcite"
                        CitationFlavour
Flavour_smartcite -> PackageName
"smartcite"
                        CitationFlavour
Flavour_Smartcite -> PackageName
"Smartcite"
                  in m () -> m ()
citeC forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall l. LaTeXC l => Text -> l
raw forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a. IsString a => PackageName -> a
fromString forall a b. (a -> b) -> a -> b
$ T -> PackageName
BibTeX.identifier T
a
        Maybe T
Nothing -> forall l. (LaTeXC l, Semigroup l) => DOIReference -> l
makeshift r
r
     )
 where makeshift :: (LaTeXC l, SG.Semigroup l) => DOIReference -> l
       makeshift :: forall l. (LaTeXC l, Semigroup l) => DOIReference -> l
makeshift (DOIReference PackageName
doi LaTeX
synops) = forall l. LaTeXC l => l -> l
footnote forall a b. (a -> b) -> a -> b
$
           forall l. LaTeXC l => LaTeX -> l
fromLaTeX LaTeX
synops forall a. Semigroup a => a -> a -> a
SG.<> l
". DOI:" forall a. Semigroup a => a -> a -> a
SG.<> forall a. IsString a => PackageName -> a
fromString PackageName
doi
    

type PlainDOI = String

data DOIReference = DOIReference {
       DOIReference -> PackageName
_referenceDOI :: PlainDOI
     , DOIReference -> LaTeX
_referenceSynopsis :: LaTeX
     } deriving (forall x. Rep DOIReference x -> DOIReference
forall x. DOIReference -> Rep DOIReference x
forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
$cto :: forall x. Rep DOIReference x -> DOIReference
$cfrom :: forall x. DOIReference -> Rep DOIReference x
Generic, Int -> DOIReference -> ShowS
[DOIReference] -> ShowS
DOIReference -> PackageName
forall a.
(Int -> a -> ShowS)
-> (a -> PackageName) -> ([a] -> ShowS) -> Show a
showList :: [DOIReference] -> ShowS
$cshowList :: [DOIReference] -> ShowS
show :: DOIReference -> PackageName
$cshow :: DOIReference -> PackageName
showsPrec :: Int -> DOIReference -> ShowS
$cshowsPrec :: Int -> DOIReference -> ShowS
Show)
instance Eq DOIReference where
  DOIReference PackageName
doi₀ LaTeX
_ == :: DOIReference -> DOIReference -> Bool
== DOIReference PackageName
doi₁ LaTeX
_ = PackageName
doi₀ forall a. Eq a => a -> a -> Bool
== PackageName
doi₁
instance Ord DOIReference where
  compare :: DOIReference -> DOIReference -> Ordering
compare (DOIReference PackageName
doi₀ LaTeX
_) (DOIReference PackageName
doi₁ LaTeX
_) = forall a. Ord a => a -> a -> Ordering
compare PackageName
doi₀ PackageName
doi₁

type DList r = [r] -> [r]

data CitationFlavour
       = Flavour_cite
       | Flavour_Cite
       | Flavour_parencite
       | Flavour_Parencite
       | Flavour_footcite
       | Flavour_Footcite
       | Flavour_textcite
       | Flavour_Textcite
       | Flavour_smartcite
       | Flavour_Smartcite
     deriving (CitationFlavour -> CitationFlavour -> Bool
forall a. (a -> a -> Bool) -> (a -> a -> Bool) -> Eq a
/= :: CitationFlavour -> CitationFlavour -> Bool
$c/= :: CitationFlavour -> CitationFlavour -> Bool
== :: CitationFlavour -> CitationFlavour -> Bool
$c== :: CitationFlavour -> CitationFlavour -> Bool
Eq, Eq CitationFlavour
CitationFlavour -> CitationFlavour -> Bool
CitationFlavour -> CitationFlavour -> Ordering
CitationFlavour -> CitationFlavour -> CitationFlavour
forall a.
Eq a
-> (a -> a -> Ordering)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> Bool)
-> (a -> a -> a)
-> (a -> a -> a)
-> Ord a
min :: CitationFlavour -> CitationFlavour -> CitationFlavour
$cmin :: CitationFlavour -> CitationFlavour -> CitationFlavour
max :: CitationFlavour -> CitationFlavour -> CitationFlavour
$cmax :: CitationFlavour -> CitationFlavour -> CitationFlavour
>= :: CitationFlavour -> CitationFlavour -> Bool
$c>= :: CitationFlavour -> CitationFlavour -> Bool
> :: CitationFlavour -> CitationFlavour -> Bool
$c> :: CitationFlavour -> CitationFlavour -> Bool
<= :: CitationFlavour -> CitationFlavour -> Bool
$c<= :: CitationFlavour -> CitationFlavour -> Bool
< :: CitationFlavour -> CitationFlavour -> Bool
$c< :: CitationFlavour -> CitationFlavour -> Bool
compare :: CitationFlavour -> CitationFlavour -> Ordering
$ccompare :: CitationFlavour -> CitationFlavour -> Ordering
Ord, Int -> CitationFlavour -> ShowS
[CitationFlavour] -> ShowS
CitationFlavour -> PackageName
forall a.
(Int -> a -> ShowS)
-> (a -> PackageName) -> ([a] -> ShowS) -> Show a
showList :: [CitationFlavour] -> ShowS
$cshowList :: [CitationFlavour] -> ShowS
show :: CitationFlavour -> PackageName
$cshow :: CitationFlavour -> PackageName
showsPrec :: Int -> CitationFlavour -> ShowS
$cshowsPrec :: Int -> CitationFlavour -> ShowS
Show)

newtype ReferenceQueryT r m a = ReferenceQueryT {
       forall r (m :: * -> *) a.
ReferenceQueryT r m a
-> m (DList r, a, (r -> CitationFlavour -> m ()) -> m ())
runReferenceQueryT :: m (DList r, a, (r -> CitationFlavour -> m ()) -> m ())
     }
  deriving (forall a.
(forall x. a -> Rep a x) -> (forall x. Rep a x -> a) -> Generic a
forall r (m :: * -> *) a x.
Rep (ReferenceQueryT r m a) x -> ReferenceQueryT r m a
forall r (m :: * -> *) a x.
ReferenceQueryT r m a -> Rep (ReferenceQueryT r m a) x
$cto :: forall r (m :: * -> *) a x.
Rep (ReferenceQueryT r m a) x -> ReferenceQueryT r m a
$cfrom :: forall r (m :: * -> *) a x.
ReferenceQueryT r m a -> Rep (ReferenceQueryT r m a) x
Generic, forall a b. a -> ReferenceQueryT r m b -> ReferenceQueryT r m a
forall a b.
(a -> b) -> ReferenceQueryT r m a -> ReferenceQueryT r m b
forall r (m :: * -> *) a b.
Functor m =>
a -> ReferenceQueryT r m b -> ReferenceQueryT r m a
forall r (m :: * -> *) a b.
Functor m =>
(a -> b) -> ReferenceQueryT r m a -> ReferenceQueryT r m b
forall (f :: * -> *).
(forall a b. (a -> b) -> f a -> f b)
-> (forall a b. a -> f b -> f a) -> Functor f
<$ :: forall a b. a -> ReferenceQueryT r m b -> ReferenceQueryT r m a
$c<$ :: forall r (m :: * -> *) a b.
Functor m =>
a -> ReferenceQueryT r m b -> ReferenceQueryT r m a
fmap :: forall a b.
(a -> b) -> ReferenceQueryT r m a -> ReferenceQueryT r m b
$cfmap :: forall r (m :: * -> *) a b.
Functor m =>
(a -> b) -> ReferenceQueryT r m a -> ReferenceQueryT r m b
Functor)

instance Applicative m => Applicative (ReferenceQueryT r m) where
  pure :: forall a. a -> ReferenceQueryT r m a
pure a
x = forall r (m :: * -> *) a.
m (DList r, a, (r -> CitationFlavour -> m ()) -> m ())
-> ReferenceQueryT r m a
ReferenceQueryT forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall (f :: * -> *) a. Applicative f => a -> f a
pure forall a b. (a -> b) -> a -> b
$ (forall a. a -> a
id, a
x, forall a b. a -> b -> a
const forall a b. (a -> b) -> a -> b
$ forall (f :: * -> *) a. Applicative f => a -> f a
pure ())
  ReferenceQueryT m (DList r, a -> b, (r -> CitationFlavour -> m ()) -> m ())
refqf <*> :: forall a b.
ReferenceQueryT r m (a -> b)
-> ReferenceQueryT r m a -> ReferenceQueryT r m b
<*> ReferenceQueryT m (DList r, a, (r -> CitationFlavour -> m ()) -> m ())
refqx = forall r (m :: * -> *) a.
m (DList r, a, (r -> CitationFlavour -> m ()) -> m ())
-> ReferenceQueryT r m a
ReferenceQueryT forall a b. (a -> b) -> a -> b
$
       forall (f :: * -> *) a b c.
Applicative f =>
(a -> b -> c) -> f a -> f b -> f c
liftA2 (\(DList r
urefsf, a -> b
f, (r -> CitationFlavour -> m ()) -> m ()
refref)
                (DList r
urefsx, a
x, (r -> CitationFlavour -> m ()) -> m ()
refrex)
                  -> ( DList r
urefsf forall b c a. (b -> c) -> (a -> b) -> a -> c
. DList r
urefsx
                     , a -> b
f a
x
                     , \r -> CitationFlavour -> m ()
resolv -> forall a. Monoid a => a -> a -> a
mappend forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> (r -> CitationFlavour -> m ()) -> m ()
refref r -> CitationFlavour -> m ()
resolv forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> (r -> CitationFlavour -> m ()) -> m ()
refrex r -> CitationFlavour -> m ()
resolv ) )
              m (DList r, a -> b, (r -> CitationFlavour -> m ()) -> m ())
refqf m (DList r, a, (r -> CitationFlavour -> m ()) -> m ())
refqx
instance Monad m => Monad (ReferenceQueryT r m) where
  return :: forall a. a -> ReferenceQueryT r m a
return = forall (f :: * -> *) a. Applicative f => a -> f a
pure
  ReferenceQueryT m (DList r, a, (r -> CitationFlavour -> m ()) -> m ())
refsx >>= :: forall a b.
ReferenceQueryT r m a
-> (a -> ReferenceQueryT r m b) -> ReferenceQueryT r m b
>>= a -> ReferenceQueryT r m b
f
     = forall r (m :: * -> *) a.
m (DList r, a, (r -> CitationFlavour -> m ()) -> m ())
-> ReferenceQueryT r m a
ReferenceQueryT forall a b. (a -> b) -> a -> b
$ m (DList r, a, (r -> CitationFlavour -> m ()) -> m ())
refsx forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= \(DList r
urefsx, a
x, (r -> CitationFlavour -> m ()) -> m ()
refrex)
           -> case a -> ReferenceQueryT r m b
f a
x of
                ReferenceQueryT m (DList r, b, (r -> CitationFlavour -> m ()) -> m ())
refsfx
                  -> (\(DList r
urefsfx,b
fx,(r -> CitationFlavour -> m ()) -> m ()
refrefx)
                        -> ( DList r
urefsxforall b c a. (b -> c) -> (a -> b) -> a -> c
.DList r
urefsfx
                           , b
fx
                           , \r -> CitationFlavour -> m ()
resolve -> forall a. Monoid a => a -> a -> a
mappend forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> (r -> CitationFlavour -> m ()) -> m ()
refrex r -> CitationFlavour -> m ()
resolve forall (f :: * -> *) a b. Applicative f => f (a -> b) -> f a -> f b
<*> (r -> CitationFlavour -> m ()) -> m ()
refrefx r -> CitationFlavour -> m ()
resolve ))
                     forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> m (DList r, b, (r -> CitationFlavour -> m ()) -> m ())
refsfx
instance MonadIO m => MonadIO (ReferenceQueryT r m) where
  liftIO :: forall a. IO a -> ReferenceQueryT r m a
liftIO IO a
a = forall r (m :: * -> *) a.
m (DList r, a, (r -> CitationFlavour -> m ()) -> m ())
-> ReferenceQueryT r m a
ReferenceQueryT forall a b. (a -> b) -> a -> b
$ (\a
r -> (forall a. a -> a
id, a
r, forall a b. a -> b -> a
const forall a b. (a -> b) -> a -> b
$ forall (f :: * -> *) a. Applicative f => a -> f a
pure ())) forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO IO a
a

instance (Functor m, Monoid (m a), IsString (m ()), a ~ ())
           => IsString (ReferenceQueryT r m a) where
  fromString :: PackageName -> ReferenceQueryT r m a
fromString PackageName
s = forall r (m :: * -> *) a.
m (DList r, a, (r -> CitationFlavour -> m ()) -> m ())
-> ReferenceQueryT r m a
ReferenceQueryT forall a b. (a -> b) -> a -> b
$ (\a
a -> (forall a. a -> a
id, a
a, forall a b. a -> b -> a
const forall a b. (a -> b) -> a -> b
$ forall a. IsString a => PackageName -> a
fromString PackageName
s)) forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> forall a. Monoid a => a
mempty

instance (Applicative m, SG.Semigroup (m a), a ~ ())
             => SG.Semigroup (ReferenceQueryT r m a) where
  ReferenceQueryT m (DList r, a, (r -> CitationFlavour -> m ()) -> m ())
p <> :: ReferenceQueryT r m a
-> ReferenceQueryT r m a -> ReferenceQueryT r m a
<> ReferenceQueryT m (DList r, a, (r -> CitationFlavour -> m ()) -> m ())
q
      = forall r (m :: * -> *) a.
m (DList r, a, (r -> CitationFlavour -> m ()) -> m ())
-> ReferenceQueryT r m a
ReferenceQueryT forall a b. (a -> b) -> a -> b
$ forall (f :: * -> *) a b c.
Applicative f =>
(a -> b -> c) -> f a -> f b -> f c
liftA2 (\(DList r
rp,(),(r -> CitationFlavour -> m ()) -> m ()
ρp) (DList r
rq,(),(r -> CitationFlavour -> m ()) -> m ()
ρq)
                                     -> (DList r
rpforall b c a. (b -> c) -> (a -> b) -> a -> c
.DList r
rq,(),forall (f :: * -> *) a b c.
Applicative f =>
(a -> b -> c) -> f a -> f b -> f c
liftA2(forall (f :: * -> *) a b c.
Applicative f =>
(a -> b -> c) -> f a -> f b -> f c
liftA2 forall a. Semigroup a => a -> a -> a
(SG.<>))(r -> CitationFlavour -> m ()) -> m ()
ρp (r -> CitationFlavour -> m ()) -> m ()
ρq)) m (DList r, a, (r -> CitationFlavour -> m ()) -> m ())
p m (DList r, a, (r -> CitationFlavour -> m ()) -> m ())
q

instance (Applicative m, SG.Semigroup (m a), Monoid (m a), a ~ ())
    => Monoid (ReferenceQueryT r m a) where
  mempty :: ReferenceQueryT r m a
mempty = forall r (m :: * -> *) a.
m (DList r, a, (r -> CitationFlavour -> m ()) -> m ())
-> ReferenceQueryT r m a
ReferenceQueryT forall a b. (a -> b) -> a -> b
$ (\a
a -> (forall a. a -> a
id, a
a, forall a. Monoid a => a
mempty)) forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> forall a. Monoid a => a
mempty
  mappend :: ReferenceQueryT r m a
-> ReferenceQueryT r m a -> ReferenceQueryT r m a
mappend = forall a. Semigroup a => a -> a -> a
(SG.<>)

instance (Applicative m, LaTeXC (m a), SG.Semigroup (m a), a ~ ())
             => LaTeXC (ReferenceQueryT r m a) where
  liftListL :: ([LaTeX] -> LaTeX)
-> [ReferenceQueryT r m a] -> ReferenceQueryT r m a
liftListL [LaTeX] -> LaTeX
f [ReferenceQueryT r m a]
xs = forall r (m :: * -> *) a.
m (DList r, a, (r -> CitationFlavour -> m ()) -> m ())
-> ReferenceQueryT r m a
ReferenceQueryT forall a b. (a -> b) -> a -> b
$
    (\[(DList r, a, (r -> CitationFlavour -> m ()) -> m ())]
components -> case forall a b c. [(a, b, c)] -> ([a], [b], [c])
List.unzip3 [(DList r, a, (r -> CitationFlavour -> m ()) -> m ())]
components of
          ([DList r]
refs, [a]
_, [(r -> CitationFlavour -> m ()) -> m ()]
rebuilds) -> ( forall (t :: * -> *) a b.
Foldable t =>
(a -> b -> b) -> b -> t a -> b
foldr forall b c a. (b -> c) -> (a -> b) -> a -> c
(.) forall a. a -> a
id [DList r]
refs
                                 , ()
                                 , \r -> CitationFlavour -> m ()
resolve -> forall l. LaTeXC l => ([LaTeX] -> LaTeX) -> [l] -> l
liftListL [LaTeX] -> LaTeX
f forall a b. (a -> b) -> a -> b
$ (forall a b. (a -> b) -> a -> b
$ r -> CitationFlavour -> m ()
resolve)forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$>[(r -> CitationFlavour -> m ()) -> m ()]
rebuilds )
       ) forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> forall (t :: * -> *) (f :: * -> *) a b.
(Traversable t, Applicative f) =>
(a -> f b) -> t a -> f (t b)
Tr.traverse forall r (m :: * -> *) a.
ReferenceQueryT r m a
-> m (DList r, a, (r -> CitationFlavour -> m ()) -> m ())
runReferenceQueryT [ReferenceQueryT r m a]
xs

citeDOI :: (Functor m, Monoid (m ()), IsString (m ()))
        => PlainDOI  -- ^ The unambiguous document identifier.
        -> String    -- ^ Synopsis of the cited work, in the form
                     --   @"J Doe et al 1950: Investigation of a Foo"@;
                     --   this is strictly speaking optional, the synopsis will /not/
                     --   be included in the final document (provided the DOI
                     --   can be properly resolved).
        -> ReferenceQueryT DOIReference m ()
citeDOI :: forall (m :: * -> *).
(Functor m, Monoid (m ()), IsString (m ())) =>
PackageName -> PackageName -> ReferenceQueryT DOIReference m ()
citeDOI PackageName
doi PackageName
synops = forall r (m :: * -> *) a.
m (DList r, a, (r -> CitationFlavour -> m ()) -> m ())
-> ReferenceQueryT r m a
ReferenceQueryT forall a b. (a -> b) -> a -> b
$ (\()
a -> ( (DOIReference
r forall a. a -> [a] -> [a]
:), ()
a, \DOIReference -> CitationFlavour -> m ()
f -> DOIReference -> CitationFlavour -> m ()
f DOIReference
r CitationFlavour
Flavour_cite ))
                       forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> forall a. Monoid a => a
mempty
 where r :: DOIReference
r = PackageName -> LaTeX -> DOIReference
DOIReference PackageName
doi forall a b. (a -> b) -> a -> b
$ forall a. IsString a => PackageName -> a
fromString PackageName
synops

-- | Transform a citation into @\\textcite@, i.e. so that it can be used as a noun in a sentence.
textc :: Functor m => ReferenceQueryT DOIReference m () -> ReferenceQueryT DOIReference m ()
textc :: forall (m :: * -> *).
Functor m =>
ReferenceQueryT DOIReference m ()
-> ReferenceQueryT DOIReference m ()
textc (ReferenceQueryT m (DList DOIReference, (),
   (DOIReference -> CitationFlavour -> m ()) -> m ())
y) = forall r (m :: * -> *) a.
m (DList r, a, (r -> CitationFlavour -> m ()) -> m ())
-> ReferenceQueryT r m a
ReferenceQueryT
        forall a b. (a -> b) -> a -> b
$ (\(DList DOIReference
r,()
m,(DOIReference -> CitationFlavour -> m ()) -> m ()
a) -> (DList DOIReference
r, ()
m, \DOIReference -> CitationFlavour -> m ()
f -> (DOIReference -> CitationFlavour -> m ()) -> m ()
a (\DOIReference
x CitationFlavour
_ -> DOIReference -> CitationFlavour -> m ()
f DOIReference
x CitationFlavour
Flavour_textcite))) forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> m (DList DOIReference, (),
   (DOIReference -> CitationFlavour -> m ()) -> m ())
y

-- | Transform a citation into @\\Textcite@, i.e. so that it can be used as the first word in a sentence.
textC :: Functor m => ReferenceQueryT DOIReference m () -> ReferenceQueryT DOIReference m ()
textC :: forall (m :: * -> *).
Functor m =>
ReferenceQueryT DOIReference m ()
-> ReferenceQueryT DOIReference m ()
textC (ReferenceQueryT m (DList DOIReference, (),
   (DOIReference -> CitationFlavour -> m ()) -> m ())
y) = forall r (m :: * -> *) a.
m (DList r, a, (r -> CitationFlavour -> m ()) -> m ())
-> ReferenceQueryT r m a
ReferenceQueryT
        forall a b. (a -> b) -> a -> b
$ (\(DList DOIReference
r,()
m,(DOIReference -> CitationFlavour -> m ()) -> m ()
a) -> (DList DOIReference
r, ()
m, \DOIReference -> CitationFlavour -> m ()
f -> (DOIReference -> CitationFlavour -> m ()) -> m ()
a (\DOIReference
x CitationFlavour
_ -> DOIReference -> CitationFlavour -> m ()
f DOIReference
x CitationFlavour
Flavour_Textcite))) forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> m (DList DOIReference, (),
   (DOIReference -> CitationFlavour -> m ()) -> m ())
y

masterBibFile :: MonadIO m
      => FilePath    -- ^ A @.bib@ file containing entries for all relevant literature.
      -> (DOIReference -> m (Maybe BibTeX.T))
                     -- ^ Lookup-function, suitable for 'documentWithDOIReferences'.
masterBibFile :: forall (m :: * -> *).
MonadIO m =>
PackageName -> DOIReference -> m (Maybe T)
masterBibFile PackageName
master (DOIReference PackageName
doi LaTeX
_) = do
   Either ParseError [T]
entries <- forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO forall a b. (a -> b) -> a -> b
$ Parser [T]
BibTeX.file forall a. Parser a -> PackageName -> IO (Either ParseError a)
`Parsec.parseFromFile` PackageName
master
   forall (m :: * -> *) a. Monad m => a -> m a
return forall a b. (a -> b) -> a -> b
$ case Either ParseError [T]
entries of
     Right [T]
bibs -> forall (t :: * -> *) a. Foldable t => (a -> Bool) -> t a -> Maybe a
List.find T -> Bool
hasThisDOI [T]
bibs
     Left ParseError
err   -> forall a. HasCallStack => PackageName -> a
error forall a b. (a -> b) -> a -> b
$ forall a. Show a => a -> PackageName
show ParseError
err
 where hasThisDOI :: T -> Bool
hasThisDOI T
bib = (forall a b. (a -> b) -> [a] -> [b]
map Char -> Char
toLower forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> forall a b. Eq a => a -> [(a, b)] -> Maybe b
List.lookup PackageName
"doi" (T -> [(PackageName, PackageName)]
BibTeX.fields T
bib))
                          forall a. Eq a => a -> a -> Bool
== forall a. a -> Maybe a
Just (Char -> Char
toLowerforall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$>PackageName
doi)