{-# LANGUAGE ViewPatterns #-}
{-# LANGUAGE OverloadedStrings #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE FlexibleContexts #-}
{-# OPTIONS_GHC -fno-warn-unused-do-bind #-}
module Text.Pandoc.Citeproc.Name
( toName
, NameOpts(..)
, emptyName
)
where
import Text.Pandoc.Definition
import Text.Pandoc.Shared (stringify)
import Citeproc.Types
import Citeproc.Pandoc ()
import Text.Pandoc.Citeproc.Util (splitStrWhen)
import qualified Data.Text as T
import Data.List.Split (splitWhen, wordsBy)
import Data.Char (isUpper, isDigit)
import Data.List (foldl')
emptyName :: Name
emptyName :: Name
emptyName =
Name { nameFamily :: Maybe Text
nameFamily = Maybe Text
forall a. Maybe a
Nothing
, nameGiven :: Maybe Text
nameGiven = Maybe Text
forall a. Maybe a
Nothing
, nameDroppingParticle :: Maybe Text
nameDroppingParticle = Maybe Text
forall a. Maybe a
Nothing
, nameNonDroppingParticle :: Maybe Text
nameNonDroppingParticle = Maybe Text
forall a. Maybe a
Nothing
, nameSuffix :: Maybe Text
nameSuffix = Maybe Text
forall a. Maybe a
Nothing
, nameLiteral :: Maybe Text
nameLiteral = Maybe Text
forall a. Maybe a
Nothing
, nameCommaSuffix :: Bool
nameCommaSuffix = Bool
False
, nameStaticOrdering :: Bool
nameStaticOrdering = Bool
False
}
data NameOpts =
NameOpts
{ NameOpts -> Bool
nameOptsPrefixIsNonDroppingParticle :: Bool
, NameOpts -> Bool
nameOptsUseJuniorComma :: Bool
} deriving (Int -> NameOpts -> ShowS
[NameOpts] -> ShowS
NameOpts -> String
(Int -> NameOpts -> ShowS)
-> (NameOpts -> String) -> ([NameOpts] -> ShowS) -> Show NameOpts
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> NameOpts -> ShowS
showsPrec :: Int -> NameOpts -> ShowS
$cshow :: NameOpts -> String
show :: NameOpts -> String
$cshowList :: [NameOpts] -> ShowS
showList :: [NameOpts] -> ShowS
Show)
toName :: Monad m => NameOpts -> [Inline] -> m Name
toName :: forall (m :: * -> *). Monad m => NameOpts -> [Inline] -> m Name
toName NameOpts
_ [Str Text
"others"] =
Name -> m Name
forall a. a -> m a
forall (m :: * -> *) a. Monad m => a -> m a
return Name
emptyName{ nameLiteral :: Maybe Text
nameLiteral = Text -> Maybe Text
forall a. a -> Maybe a
Just Text
"others" }
toName NameOpts
_ [Span (Text
"",[],[]) [Inline]
ils] =
Name -> m Name
forall a. a -> m a
forall (m :: * -> *) a. Monad m => a -> m a
return Name
emptyName{ nameLiteral :: Maybe Text
nameLiteral = Text -> Maybe Text
forall a. a -> Maybe a
Just (Text -> Maybe Text) -> Text -> Maybe Text
forall a b. (a -> b) -> a -> b
$ [Inline] -> Text
forall a. Walkable Inline a => a -> Text
stringify [Inline]
ils }
toName NameOpts
_ ils :: [Inline]
ils@(Str Text
ys:[Inline]
_) | (Char -> Bool) -> Text -> Bool
T.any (Char -> Char -> Bool
forall a. Eq a => a -> a -> Bool
== Char
'=') Text
ys = do
let commaParts :: [[Inline]]
commaParts = (Inline -> Bool) -> [Inline] -> [[Inline]]
forall a. (a -> Bool) -> [a] -> [[a]]
splitWhen (Inline -> Inline -> Bool
forall a. Eq a => a -> a -> Bool
== Text -> Inline
Str Text
",")
([Inline] -> [[Inline]])
-> ([Inline] -> [Inline]) -> [Inline] -> [[Inline]]
forall b c a. (b -> c) -> (a -> b) -> a -> c
. (Char -> Bool) -> [Inline] -> [Inline]
splitStrWhen (\Char
c -> Char
c Char -> Char -> Bool
forall a. Eq a => a -> a -> Bool
== Char
',' Bool -> Bool -> Bool
|| Char
c Char -> Char -> Bool
forall a. Eq a => a -> a -> Bool
== Char
'=' Bool -> Bool -> Bool
|| Char
c Char -> Char -> Bool
forall a. Eq a => a -> a -> Bool
== Char
'\160')
([Inline] -> [[Inline]]) -> [Inline] -> [[Inline]]
forall a b. (a -> b) -> a -> b
$ [Inline]
ils
let addPart :: Name -> [Inline] -> Name
addPart Name
ag (Str Text
"given" : Str Text
"=" : [Inline]
xs) =
Name
ag{ nameGiven :: Maybe Text
nameGiven = case Name -> Maybe Text
nameGiven Name
ag of
Maybe Text
Nothing -> Text -> Maybe Text
forall a. a -> Maybe a
Just (Text -> Maybe Text) -> Text -> Maybe Text
forall a b. (a -> b) -> a -> b
$ [Inline] -> Text
forall a. Walkable Inline a => a -> Text
stringify [Inline]
xs
Just Text
t -> Text -> Maybe Text
forall a. a -> Maybe a
Just (Text -> Maybe Text) -> Text -> Maybe Text
forall a b. (a -> b) -> a -> b
$ Text
t Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> Text
" " Text -> Text -> Text
forall a. Semigroup a => a -> a -> a
<> [Inline] -> Text
forall a. Walkable Inline a => a -> Text
stringify [Inline]
xs }
addPart Name
ag (Str Text
"family" : Str Text
"=" : [Inline]
xs) =
Name
ag{ nameFamily :: Maybe Text
nameFamily = Text -> Maybe Text
forall a. a -> Maybe a
Just (Text -> Maybe Text) -> Text -> Maybe Text
forall a b. (a -> b) -> a -> b
$ [Inline] -> Text
forall a. Walkable Inline a => a -> Text
stringify [Inline]
xs }
addPart Name
ag (Str Text
"prefix" : Str Text
"=" : [Inline]
xs) =
Name
ag{ nameDroppingParticle :: Maybe Text
nameDroppingParticle = Text -> Maybe Text
forall a. a -> Maybe a
Just (Text -> Maybe Text) -> Text -> Maybe Text
forall a b. (a -> b) -> a -> b
$ [Inline] -> Text
forall a. Walkable Inline a => a -> Text
stringify [Inline]
xs }
addPart Name
ag (Str Text
"useprefix" : Str Text
"=" : Str Text
"true" : [Inline]
_) =
Name
ag{ nameNonDroppingParticle :: Maybe Text
nameNonDroppingParticle = Name -> Maybe Text
nameDroppingParticle Name
ag
, nameDroppingParticle :: Maybe Text
nameDroppingParticle = Maybe Text
forall a. Maybe a
Nothing }
addPart Name
ag (Str Text
"suffix" : Str Text
"=" : [Inline]
xs) =
Name
ag{ nameSuffix :: Maybe Text
nameSuffix = Text -> Maybe Text
forall a. a -> Maybe a
Just (Text -> Maybe Text) -> Text -> Maybe Text
forall a b. (a -> b) -> a -> b
$ [Inline] -> Text
forall a. Walkable Inline a => a -> Text
stringify [Inline]
xs }
addPart Name
ag (Inline
Space : [Inline]
xs) = Name -> [Inline] -> Name
addPart Name
ag [Inline]
xs
addPart Name
ag [Inline]
_ = Name
ag
Name -> m Name
forall a. a -> m a
forall (m :: * -> *) a. Monad m => a -> m a
return (Name -> m Name) -> Name -> m Name
forall a b. (a -> b) -> a -> b
$ (Name -> [Inline] -> Name) -> Name -> [[Inline]] -> Name
forall b a. (b -> a -> b) -> b -> [a] -> b
forall (t :: * -> *) b a.
Foldable t =>
(b -> a -> b) -> b -> t a -> b
foldl' Name -> [Inline] -> Name
addPart Name
emptyName [[Inline]]
commaParts
toName NameOpts
opts [Inline]
ils = do
let words' :: [Inline] -> [[Inline]]
words' = (Inline -> Bool) -> [Inline] -> [[Inline]]
forall a. (a -> Bool) -> [a] -> [[a]]
wordsBy (\Inline
x -> Inline
x Inline -> Inline -> Bool
forall a. Eq a => a -> a -> Bool
== Inline
Space Bool -> Bool -> Bool
|| Inline
x Inline -> Inline -> Bool
forall a. Eq a => a -> a -> Bool
== Text -> Inline
Str Text
"\160")
let commaParts :: [[[Inline]]]
commaParts = ([Inline] -> [[Inline]]) -> [[Inline]] -> [[[Inline]]]
forall a b. (a -> b) -> [a] -> [b]
map [Inline] -> [[Inline]]
words' ([[Inline]] -> [[[Inline]]]) -> [[Inline]] -> [[[Inline]]]
forall a b. (a -> b) -> a -> b
$ (Inline -> Bool) -> [Inline] -> [[Inline]]
forall a. (a -> Bool) -> [a] -> [[a]]
splitWhen (Inline -> Inline -> Bool
forall a. Eq a => a -> a -> Bool
== Text -> Inline
Str Text
",")
([Inline] -> [[Inline]]) -> [Inline] -> [[Inline]]
forall a b. (a -> b) -> a -> b
$ (Char -> Bool) -> [Inline] -> [Inline]
splitStrWhen
(\Char
c -> Char
c Char -> Char -> Bool
forall a. Eq a => a -> a -> Bool
== Char
',' Bool -> Bool -> Bool
|| Char
c Char -> Char -> Bool
forall a. Eq a => a -> a -> Bool
== Char
'\160') [Inline]
ils
let ([[Inline]]
first, [[Inline]]
vonlast, [[Inline]]
jr) =
case [[[Inline]]]
commaParts of
[[[Inline]]
fvl] -> let ([[Inline]]
caps', [[Inline]]
rest') = ([Inline] -> Bool) -> [[Inline]] -> ([[Inline]], [[Inline]])
forall a. (a -> Bool) -> [a] -> ([a], [a])
span [Inline] -> Bool
isCapitalized [[Inline]]
fvl
in if [[Inline]] -> Bool
forall a. [a] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null [[Inline]]
rest' Bool -> Bool -> Bool
&& Bool -> Bool
not ([[Inline]] -> Bool
forall a. [a] -> Bool
forall (t :: * -> *) a. Foldable t => t a -> Bool
null [[Inline]]
caps')
then ([[Inline]] -> [[Inline]]
forall a. HasCallStack => [a] -> [a]
init [[Inline]]
caps', [[[Inline]] -> [Inline]
forall a. HasCallStack => [a] -> a
last [[Inline]]
caps'], [])
else ([[Inline]]
caps', [[Inline]]
rest', [])
[[[Inline]]
vl,[[Inline]]
f] -> ([[Inline]]
f, [[Inline]]
vl, [])
([[Inline]]
vl:[[Inline]]
j:[[Inline]]
f:[[[Inline]]]
_) -> ([[Inline]]
f, [[Inline]]
vl, [[Inline]]
j )
[] -> ([], [], [])
let ([[Inline]]
von, [[Inline]]
lastname) =
case ([Inline] -> Bool) -> [[Inline]] -> ([[Inline]], [[Inline]])
forall a. (a -> Bool) -> [a] -> ([a], [a])
break [Inline] -> Bool
isCapitalized [[Inline]]
vonlast of
(vs :: [[Inline]]
vs@([Inline]
_:[[Inline]]
_), []) -> ([[Inline]] -> [[Inline]]
forall a. HasCallStack => [a] -> [a]
init [[Inline]]
vs, [[[Inline]] -> [Inline]
forall a. HasCallStack => [a] -> a
last [[Inline]]
vs])
([[Inline]]
vs, [[Inline]]
ws) -> ([[Inline]]
vs, [[Inline]]
ws)
let prefix :: Text
prefix = [Text] -> Text
T.unwords ([Text] -> Text) -> [Text] -> Text
forall a b. (a -> b) -> a -> b
$ ([Inline] -> Text) -> [[Inline]] -> [Text]
forall a b. (a -> b) -> [a] -> [b]
map [Inline] -> Text
forall a. Walkable Inline a => a -> Text
stringify [[Inline]]
von
let family :: Text
family = [Text] -> Text
T.unwords ([Text] -> Text) -> [Text] -> Text
forall a b. (a -> b) -> a -> b
$ ([Inline] -> Text) -> [[Inline]] -> [Text]
forall a b. (a -> b) -> [a] -> [b]
map [Inline] -> Text
forall a. Walkable Inline a => a -> Text
stringify [[Inline]]
lastname
let suffix :: Text
suffix = [Text] -> Text
T.unwords ([Text] -> Text) -> [Text] -> Text
forall a b. (a -> b) -> a -> b
$ ([Inline] -> Text) -> [[Inline]] -> [Text]
forall a b. (a -> b) -> [a] -> [b]
map [Inline] -> Text
forall a. Walkable Inline a => a -> Text
stringify [[Inline]]
jr
let given :: Text
given = [Text] -> Text
T.unwords ([Text] -> Text) -> [Text] -> Text
forall a b. (a -> b) -> a -> b
$ ([Inline] -> Text) -> [[Inline]] -> [Text]
forall a b. (a -> b) -> [a] -> [b]
map [Inline] -> Text
forall a. Walkable Inline a => a -> Text
stringify [[Inline]]
first
Name -> m Name
forall a. a -> m a
forall (m :: * -> *) a. Monad m => a -> m a
return
Name { nameFamily :: Maybe Text
nameFamily = if Text -> Bool
T.null Text
family
then Maybe Text
forall a. Maybe a
Nothing
else Text -> Maybe Text
forall a. a -> Maybe a
Just Text
family
, nameGiven :: Maybe Text
nameGiven = if Text -> Bool
T.null Text
given
then Maybe Text
forall a. Maybe a
Nothing
else Text -> Maybe Text
forall a. a -> Maybe a
Just Text
given
, nameDroppingParticle :: Maybe Text
nameDroppingParticle = if NameOpts -> Bool
nameOptsPrefixIsNonDroppingParticle NameOpts
opts Bool -> Bool -> Bool
||
Text -> Bool
T.null Text
prefix
then Maybe Text
forall a. Maybe a
Nothing
else Text -> Maybe Text
forall a. a -> Maybe a
Just Text
prefix
, nameNonDroppingParticle :: Maybe Text
nameNonDroppingParticle = if NameOpts -> Bool
nameOptsPrefixIsNonDroppingParticle NameOpts
opts Bool -> Bool -> Bool
&&
Bool -> Bool
not (Text -> Bool
T.null Text
prefix)
then Text -> Maybe Text
forall a. a -> Maybe a
Just Text
prefix
else Maybe Text
forall a. Maybe a
Nothing
, nameSuffix :: Maybe Text
nameSuffix = if Text -> Bool
T.null Text
suffix
then Maybe Text
forall a. Maybe a
Nothing
else Text -> Maybe Text
forall a. a -> Maybe a
Just Text
suffix
, nameLiteral :: Maybe Text
nameLiteral = Maybe Text
forall a. Maybe a
Nothing
, nameCommaSuffix :: Bool
nameCommaSuffix = NameOpts -> Bool
nameOptsUseJuniorComma NameOpts
opts
, nameStaticOrdering :: Bool
nameStaticOrdering = Bool
False
}
isCapitalized :: [Inline] -> Bool
isCapitalized :: [Inline] -> Bool
isCapitalized (Str (Text -> Maybe (Char, Text)
T.uncons -> Just (Char
c,Text
cs)) : [Inline]
rest)
| Char -> Bool
isUpper Char
c = Bool
True
| Char -> Bool
isDigit Char
c = [Inline] -> Bool
isCapitalized (Text -> Inline
Str Text
cs Inline -> [Inline] -> [Inline]
forall a. a -> [a] -> [a]
: [Inline]
rest)
| Bool
otherwise = Bool
False
isCapitalized (Inline
_:[Inline]
rest) = [Inline] -> Bool
isCapitalized [Inline]
rest
isCapitalized [] = Bool
True