pandoc-crossref-0.1.0.1: src/References/Refs.hs
module References.Refs (replaceRefs) where
import Text.Pandoc.Definition
import Text.Pandoc.Shared (normalizeInlines)
import Control.Monad.State
import Data.List
import Data.Maybe
import Data.Function
import qualified Data.Map as M
import Util.Accessor
import References.Types
import References.Accessors
import Util.Util
import Util.Options
replaceRefs :: Options -> [Inline] -> WS [Inline]
replaceRefs opts (Cite cits _:xs)
| Just prefix <- allCitsPrefix cits
= (++ xs) `fmap` replaceRefs' prefix opts cits
where
replaceRefs' = case outFormat opts of
Just f | isFormat "latex" f -> replaceRefsLatex
_ -> replaceRefsOther
replaceRefs _ x = return x
-- accessors to state variables
accMap :: M.Map String (Accessor References RefMap)
accMap = M.fromList [("fig:",imgRefs')
,("eq:" ,eqnRefs')
,("tbl:",tblRefs')
]
-- accessors to options
prefMap :: M.Map String (Options -> [Inline])
prefMap = M.fromList [("fig:",figPrefix)
,("eq:" ,eqnPrefix)
,("tbl:",tblPrefix)
]
prefixes :: [String]
prefixes = M.keys accMap
getRefPrefix :: Options -> String -> [Inline]
getRefPrefix opts prefix | null refprefix = []
| otherwise = refprefix ++ [Str "\160"]
where refprefix = lookupUnsafe prefix prefMap opts
lookupUnsafe :: Ord k => k -> M.Map k v -> v
lookupUnsafe = (fromMaybe undefined .) . M.lookup
allCitsPrefix :: [Citation] -> Maybe String
allCitsPrefix cits = foldl f Nothing prefixes
where
f x@(Just _) _ = x
f _ p | all (isPrefixOf p . citationId) cits = Just p
f _ _ = Nothing
replaceRefsLatex :: String -> Options -> [Citation] -> WS [Inline]
replaceRefsLatex prefix opts cits =
return $ p ++ [texcit]
where
texcit =
RawInline (Format "tex") $
if useCleveref opts then
" \\cref{"++listLabels prefix "" "" cits++"}"
else
listLabels prefix " \\ref{" "}" cits
p | useCleveref opts = []
| otherwise = getRefPrefix opts prefix
listLabels :: String -> String -> String -> [Citation] -> String
listLabels prefix p s = foldl' joinStr "" . mapMaybe (getLabel prefix)
where
joinStr acc i | null acc = p++i++s
| otherwise = acc++","++p++i++s
getLabel :: String -> Citation -> Maybe String
getLabel prefix Citation{citationId=cid}
| prefix `isPrefixOf` cid = Just cid
| otherwise = Nothing
replaceRefsOther :: String -> Options -> [Citation] -> WS [Inline]
replaceRefsOther prefix opts cits = do
indices <- mapM (getRefIndex prefix) cits
let
indices' = groupBy ((==) `on` fmap fst) (sort indices)
return $ normalizeInlines $ getRefPrefix opts prefix ++ concatMap (makeIndices opts) indices'
getRefIndex :: String -> Citation -> WS (Maybe (Int, Int))
getRefIndex prefix Citation{citationId=cid}
| prefix `isPrefixOf` cid
= gets (fmap refIndex . M.lookup cid . getProp prop)
| otherwise = return Nothing
where
prop = lookupUnsafe prefix accMap
makeIndices :: Options -> [Maybe (Int,Int)] -> [Inline]
makeIndices _ s | any isNothing s = [Str "??"]
makeIndices o s = intercalate sep $ reverse $ map f $ foldl' f2 [] $ catMaybes s
where
f2 [] i = [[i]]
f2 ([]:xs) i = [i]:xs
f2 l@(x@((_,hx):_):xs) i@(_,ni)
| ni-hx == 0 = l -- remove duplicates
| ni-hx == 1 = (i:x):xs -- group sequental
| otherwise = [i]:l -- new group
f [] = [] -- drop empty lists
f [w] = show' w -- single value
f [w1,w2] = show' w2 ++ sep ++ show' w1 -- two values
f (x:xs) = show' (last xs) ++ rangeDelim o ++ show' x -- shorten more than two values
sep = [Str ", "]
show' (c,n) = if sepChapters o && c>0
then [Str $ show c] ++ chapDelim o ++ [Str $ show n]
else [Str $ show n]