pandoc-crossref 0.1.6.2 → 0.1.6.3
raw patch · 40 files changed
+1044/−1038 lines, 40 filesPVP ok
version bump matches the API change (PVP)
API changes (from Hackage documentation)
Files
- README.md +2/−0
- lib/Text/Pandoc/CrossRef.hs +143/−0
- lib/Text/Pandoc/CrossRef/References.hs +7/−0
- lib/Text/Pandoc/CrossRef/References/Accessors.hs +19/−0
- lib/Text/Pandoc/CrossRef/References/Blocks.hs +194/−0
- lib/Text/Pandoc/CrossRef/References/List.hs +37/−0
- lib/Text/Pandoc/CrossRef/References/Refs.hs +142/−0
- lib/Text/Pandoc/CrossRef/References/Types.hs +36/−0
- lib/Text/Pandoc/CrossRef/Util/Accessor.hs +17/−0
- lib/Text/Pandoc/CrossRef/Util/CodeBlockCaptions.hs +37/−0
- lib/Text/Pandoc/CrossRef/Util/Gap.hs +12/−0
- lib/Text/Pandoc/CrossRef/Util/Meta.hs +59/−0
- lib/Text/Pandoc/CrossRef/Util/ModifyMeta.hs +84/−0
- lib/Text/Pandoc/CrossRef/Util/Options.hs +74/−0
- lib/Text/Pandoc/CrossRef/Util/Settings.hs +41/−0
- lib/Text/Pandoc/CrossRef/Util/Settings/Gen.hs +61/−0
- lib/Text/Pandoc/CrossRef/Util/Settings/Template.hs +8/−0
- lib/Text/Pandoc/CrossRef/Util/Template.hs +26/−0
- lib/Text/Pandoc/CrossRef/Util/Util.hs +26/−0
- pandoc-crossref.cabal +5/−5
- pandoc-crossref.hs +0/−14
- src/Text/Pandoc/CrossRef.hs +0/−143
- src/Text/Pandoc/CrossRef/References.hs +0/−7
- src/Text/Pandoc/CrossRef/References/Accessors.hs +0/−19
- src/Text/Pandoc/CrossRef/References/Blocks.hs +0/−190
- src/Text/Pandoc/CrossRef/References/List.hs +0/−37
- src/Text/Pandoc/CrossRef/References/Refs.hs +0/−142
- src/Text/Pandoc/CrossRef/References/Types.hs +0/−36
- src/Text/Pandoc/CrossRef/Util/Accessor.hs +0/−17
- src/Text/Pandoc/CrossRef/Util/CodeBlockCaptions.hs +0/−37
- src/Text/Pandoc/CrossRef/Util/Gap.hs +0/−12
- src/Text/Pandoc/CrossRef/Util/Meta.hs +0/−59
- src/Text/Pandoc/CrossRef/Util/ModifyMeta.hs +0/−84
- src/Text/Pandoc/CrossRef/Util/Options.hs +0/−74
- src/Text/Pandoc/CrossRef/Util/Settings.hs +0/−41
- src/Text/Pandoc/CrossRef/Util/Settings/Gen.hs +0/−61
- src/Text/Pandoc/CrossRef/Util/Settings/Template.hs +0/−8
- src/Text/Pandoc/CrossRef/Util/Template.hs +0/−26
- src/Text/Pandoc/CrossRef/Util/Util.hs +0/−26
- src/pandoc-crossref.hs +14/−0
README.md view
@@ -296,6 +296,8 @@ lotTitle: "# Lista de tablas" ``` +pandoc-crossref will send this data to pandoc wrapped in lines of `---`. The YAML file's first line should specify a variable; it will not pass the variables if it is `---` or a blank line.+ One could use this with pandoc-crossref as follows: `pandoc -F pandoc-crossref.hs -M "crossrefYaml=$HOME/misc/pandoc-crossref-es.yaml"`
+ lib/Text/Pandoc/CrossRef.hs view
@@ -0,0 +1,143 @@+{- |+ Module : Text.Pandoc.CrossRef+ Copyright : Copyright (C) 2015 Nikolay Yakimov+ License : GNU GPL, version 2 or above++ Maintainer : Nikolay Yakimov <root@livid.pp.ru>+ Stability : alpha+ Portability : portable++Public interface to pandoc-crossref library++Example of use:++> import Text.Pandoc+> import Text.Pandoc.JSON+>+> import Text.Pandoc.CrossRef+>+> main :: IO ()+> main = toJSONFilter go+> where+> go fmt p@(Pandoc meta _) = runCrossRefIO meta fmt action p+> where+> action (Pandoc _ bs) = do+> meta' <- crossRefMeta+> bs' <- crossRefBlocks bs+> return $ Pandoc meta' bs'++This module also exports utility functions for setting up meta-settings for+pandoc-crossref. Refer to documentation for a complete list of metadata field+names. All functions accept a single argument of type, returned by+"Text.Pandoc.Builder" functions, and return 'Meta'.++Example:++> runCrossRefIO meta fmt crossRefBlocks blocks+> where+> meta =+> figureTitle (str "Figura")+> <> tableTitle (str "Tabla")+> <> figPrefix (str "fig.")+> <> eqnPrefix (str "ec.")+> <> tblPrefix (str "tbl.")+> <> loftitle (header 1 $ text "Lista de figuras")+> <> lotTitle (header 1 $ text "Lista de tablas")+> <> chaptersDepth (MetaString "2")++-}+{-# LANGUAGE RankNTypes #-}++module Text.Pandoc.CrossRef (+ crossRefBlocks+ , crossRefMeta+ , defaultCrossRefAction+ , runCrossRef+ , runCrossRefIO+ , module SG+ , CrossRefM+ , CrossRefEnv(..)+ ) where++import Control.Monad.State+import qualified Control.Monad.Reader as R+import Text.Pandoc+import Text.Pandoc.Walk+import Data.Monoid ((<>))++import Text.Pandoc.CrossRef.References+import Text.Pandoc.CrossRef.Util.Settings+import Text.Pandoc.CrossRef.Util.Options+import Text.Pandoc.CrossRef.Util.CodeBlockCaptions+import Text.Pandoc.CrossRef.Util.ModifyMeta+import Text.Pandoc.CrossRef.Util.Settings.Gen as SG++-- | Enviromnent for 'CrossRefM'+data CrossRefEnv = CrossRefEnv {+ creSettings :: Meta -- ^Metadata settings+ , creOptions :: Options -- ^Internal pandoc-crossref options+ }++-- | Essentially a reader monad for basic pandoc-crossref environment+type CrossRefM a = R.Reader CrossRefEnv a++{- | Walk over blocks, while inserting cross-references, list-of, etc.++Works in 'CrossRefM' monad. -}+crossRefBlocks :: [Block] -> CrossRefM [Block]+crossRefBlocks blocks = do+ opts <- R.asks creOptions+ let+ doWalk =+ bottomUpM (codeBlockCaptions opts) (walk divBlocks blocks)+ >>= walkM (replaceBlocks opts)+ >>= bottomUpM (replaceRefs opts)+ >>= bottomUpM (listOf opts)+ return $ evalState doWalk def++{- | Modifies metadata for LaTeX output, adding header-includes instructions+to setup custom and builtin environments.++Note, that if output format is not "latex", this function does nothing.++Works in 'CrossRefM' monad. -}+crossRefMeta :: CrossRefM Meta+crossRefMeta = do+ opts <- R.asks creOptions+ dtv <- R.asks creSettings+ return $ modifyMeta opts dtv++{- | Combines 'crossRefMeta' and 'crossRefBlocks'++Works in 'CrossRefM' monad. -}+defaultCrossRefAction :: Pandoc -> CrossRefM Pandoc+defaultCrossRefAction (Pandoc _ bs) = do+ meta' <- crossRefMeta+ bs' <- crossRefBlocks bs+ return $ Pandoc meta' bs'++{- | Run an action in 'CrossRefM' monad with argument, and return pure result.++This is primary function to work with 'CrossRefM' -}+runCrossRef :: forall a b. Meta -> Maybe Format -> (a -> CrossRefM b) -> a -> b+runCrossRef meta fmt action arg = R.runReader (action arg) env+ where+ settings = meta <> defaultMeta+ env = CrossRefEnv {+ creSettings = settings+ , creOptions = getOptions settings fmt+ }++{- | Run an action in 'CrossRefM' monad with argument, and return 'IO' result.++This function will attempt to read pandoc-crossref settings from settings+file specified by crossrefYaml metadata field. -}+runCrossRefIO :: forall a b. Meta -> Maybe Format -> (a -> CrossRefM b) -> a -> IO b+runCrossRefIO meta fmt action arg = do+ settings <- getSettings meta+ let+ env = CrossRefEnv {+ creSettings = settings+ , creOptions = getOptions settings fmt+ }+ return $ R.runReader (action arg) env
+ lib/Text/Pandoc/CrossRef/References.hs view
@@ -0,0 +1,7 @@+module Text.Pandoc.CrossRef.References ( module X ) where++import Text.Pandoc.CrossRef.References.Accessors as X+import Text.Pandoc.CrossRef.References.Types as X+import Text.Pandoc.CrossRef.References.Blocks as X (divBlocks, replaceBlocks)+import Text.Pandoc.CrossRef.References.Refs as X+import Text.Pandoc.CrossRef.References.List as X
+ lib/Text/Pandoc/CrossRef/References/Accessors.hs view
@@ -0,0 +1,19 @@+module Text.Pandoc.CrossRef.References.Accessors where++import Text.Pandoc.CrossRef.References.Types+import Text.Pandoc.CrossRef.Util.Accessor++imgRefs' :: Accessor References RefMap+imgRefs' new r@References{imgRefs=old} = (old, r{imgRefs=new})++eqnRefs' :: Accessor References RefMap+eqnRefs' new r@References{eqnRefs=old} = (old, r{eqnRefs=new})++tblRefs' :: Accessor References RefMap+tblRefs' new r@References{tblRefs=old} = (old, r{tblRefs=new})++lstRefs' :: Accessor References RefMap+lstRefs' new r@References{lstRefs=old} = (old, r{lstRefs=new})++secRefs' :: Accessor References RefMap+secRefs' new r@References{secRefs=old} = (old, r{secRefs=new})
+ lib/Text/Pandoc/CrossRef/References/Blocks.hs view
@@ -0,0 +1,194 @@+{-# LANGUAGE CPP #-}+module Text.Pandoc.CrossRef.References.Blocks+ ( divBlocks+ , replaceBlocks+ , spanInlines+ , replaceInlines+ ) where++import Text.Pandoc.Definition+import Text.Pandoc.Generic+import Text.Pandoc.Builder (text, toList)+import Text.Pandoc.Shared (stringify, normalizeSpaces)+import Control.Monad.State+import Data.List+import qualified Data.Map as M++import Text.Pandoc.CrossRef.Util.Accessor+import Text.Pandoc.CrossRef.References.Types+import Text.Pandoc.CrossRef.References.Accessors+import Text.Pandoc.CrossRef.Util.Util+import Text.Pandoc.CrossRef.Util.Options+import Text.Pandoc.CrossRef.Util.Template++replaceBlocks :: Options -> Block -> WS Block+replaceBlocks opts (Header n (label, cls, attrs) text')+ = do+ let label' = if autoSecLab opts && not ("sec:" `isPrefixOf` label)+ then "sec:"++label+ else label+ unless ("unnumbered" `elem` cls) $ do+ modify $ \r@References{curChap=cc} ->+ let ln = length cc+ cl = lookup "label" attrs+ inc l = init l ++ [(fst (last l) + 1, cl)]+ cc' | ln > n = inc $ take n cc+ | ln == n = inc cc+ | otherwise = cc ++ take (n-ln-1) (zip [1,1..] $ repeat Nothing) ++ [(1,cl)]+ in r{curChap=cc'}+ when ("sec:" `isPrefixOf` label') $ replaceAttrSec label' text' secRefs'+ return $ Header n (label', cls, attrs) text'+#if MIN_VERSION_pandoc(1,16,0)+#else+replaceBlocks opts (Div (label,_,attrs) [Plain [Image alt img]])+ | "fig:" `isPrefixOf` label+ = do+ idxStr <- replaceAttr opts label (lookup "label" attrs) alt imgRefs'+ let alt' = case outFormat opts of+ f | isFormat "latex" f ->+ RawInline (Format "tex") ("\\label{"++label++"}") : alt+ _ -> applyTemplate idxStr alt $ figureTemplate opts+ return $ Para [Image alt' img]+#endif+replaceBlocks opts (Div (label,_,attrs) [Table title align widths header cells])+ | not $ null title+ , "tbl:" `isPrefixOf` label+ = do+ idxStr <- replaceAttr opts label (lookup "label" attrs) title tblRefs'+ let title' =+ case outFormat opts of+ f | isFormat "latex" f ->+ RawInline (Format "tex") ("\\label{"++label++"}") : title+ _ -> applyTemplate idxStr title $ tableTemplate opts+ return $ Table title' align widths header cells+replaceBlocks opts cb@(CodeBlock (label, classes, attrs) code)+ | not $ null label+ , "lst:" `isPrefixOf` label+ , Just caption <- lookup "caption" attrs+ = case outFormat opts of+ f+ --if used with listings package,nothing shoud be done+ | isFormat "latex" f, useListings opts -> return cb+ --if not using listings, however, wrap it in a codelisting environment+ | isFormat "latex" f ->+ return $ Div nullAttr [+ RawBlock (Format "tex")+ $ "\\begin{codelisting}\n\\caption{"++caption++"}"+ , cb+ , RawBlock (Format "tex") "\\end{codelisting}"+ ]+ _ -> do+ let cap = toList $ text caption+ idxStr <- replaceAttr opts label (lookup "label" attrs) cap lstRefs'+ let caption' = applyTemplate idxStr cap $ listingTemplate opts+ return $ Div (label, "listing":classes, []) [+ Para caption'+ , CodeBlock ([], classes, attrs \\ [("caption", caption)]) code+ ]+replaceBlocks opts+ (Div (label,"listing":_, [])+ [Para caption, CodeBlock ([],classes,attrs) code])+ | not $ null label+ , "lst:" `isPrefixOf` label+ = case outFormat opts of+ f+ --if used with listings package, return code block with caption+ | isFormat "latex" f, useListings opts ->+ return $ CodeBlock (label,classes,("caption",stringify caption):attrs) code+ --if not using listings, however, wrap it in a codelisting environment+ | isFormat "latex" f ->+ return $ Div nullAttr [+ RawBlock (Format "tex") "\\begin{codelisting}"+ , Para [+ RawInline (Format "tex") "\\caption{"+ , Span nullAttr caption+ , RawInline (Format "tex") "}"+ ]+ , CodeBlock (label,classes,attrs) code+ , RawBlock (Format "tex") "\\end{codelisting}"+ ]+ _ -> do+ idxStr <- replaceAttr opts label (lookup "label" attrs) caption lstRefs'+ let caption' = applyTemplate idxStr caption $ listingTemplate opts+ return $ Div (label, "listing":classes, []) [+ Para caption'+ , CodeBlock ([], classes, attrs) code+ ]+replaceBlocks opts x = bottomUpM (replaceInlines opts) x++replaceInlines :: Options -> [Inline] -> WS [Inline]+replaceInlines opts (Span (label,_,attrs) [Math DisplayMath eq]:ils')+ | "eq:" `isPrefixOf` label+ = case outFormat opts of+ f | isFormat "latex" f ->+ let eqn = "\\begin{equation}"++eq++"\\label{"++label++"}\\end{equation}"+ in return $ RawInline (Format "tex") eqn : ils'+ _ -> do+ idxStr <- replaceAttr opts label (lookup "label" attrs) [] eqnRefs'+ let eq' = eq++"\\qquad("++stringify idxStr++")"+ return $ Math DisplayMath eq' : ils'+#if MIN_VERSION_pandoc(1,16,0)+replaceInlines opts (Image attr@(label,_,attrs) alt img:ils')+ | "fig:" `isPrefixOf` label, "fig:" `isPrefixOf` snd img+ = do+ idxStr <- replaceAttr opts label (lookup "label" attrs) alt imgRefs'+ let alt' = case outFormat opts of+ f | isFormat "latex" f ->+ RawInline (Format "tex") ("\\label{"++label++"}") : alt+ _ -> applyTemplate idxStr alt $ figureTemplate opts+ return $ Image attr alt' img : ils'+#else+#endif+replaceInlines _ x = return x++divBlocks :: Block -> Block+#if MIN_VERSION_pandoc(1,16,0)+#else+divBlocks (Para (Image alt (img, title):c))+ | Just label <- getRefLabel "fig" c+ = Div (label,[],[]) [Plain [Image alt (img, "fig:" ++ title)]]+#endif+divBlocks (Table title align widths header cells)+ | not $ null title+ , Just label <- getRefLabel "tbl" [last title]+ = Div (label,[],[]) [Table (init title) align widths header cells]+divBlocks x = bottomUp spanInlines x++spanInlines :: [Inline] -> [Inline]+spanInlines (math@(Math DisplayMath _eq):ils)+ | c:ils' <- dropWhile (==Space) ils+ , Just label <- getRefLabel "eq" [c]+ = Span (label,[],[]) [math]:ils'+spanInlines x = x++getRefLabel :: String -> [Inline] -> Maybe String+getRefLabel _ [] = Nothing+getRefLabel tag ils+ | Str attr <- last ils+ , all (==Space) (init ils)+ , "}" `isSuffixOf` attr+ , ("{#"++tag++":") `isPrefixOf` attr+ = init `fmap` stripPrefix "{#" attr+getRefLabel _ _ = Nothing++replaceAttr :: Options -> String -> Maybe String -> [Inline] -> Accessor References RefMap -> WS [Inline]+replaceAttr o label refLabel title prop+ = do+ chap <- take (chapDepth o) `fmap` gets curChap+ i <- (1+) `fmap` gets (M.size . M.filter ((==chap) . init . refIndex) . getProp prop)+ let index = chap ++ [(i, refLabel)]+ modify $ modifyProp prop $ M.insert label RefRec {+ refIndex= index+ , refTitle=normalizeSpaces title+ }+ return $ chapPrefix (chapDelim o) index++replaceAttrSec :: String -> [Inline] -> Accessor References RefMap -> WS ()+replaceAttrSec label title prop+ = do+ index <- gets curChap+ modify $ modifyProp prop $ M.insert label RefRec {+ refIndex=index+ , refTitle=normalizeSpaces title+ }+ return ()
+ lib/Text/Pandoc/CrossRef/References/List.hs view
@@ -0,0 +1,37 @@+module Text.Pandoc.CrossRef.References.List (listOf) where++import Text.Pandoc.Definition+import Control.Monad.State+import Control.Arrow+import Data.List+import qualified Data.Map as M++import Text.Pandoc.CrossRef.References.Types+import Text.Pandoc.CrossRef.Util.Util+import Text.Pandoc.CrossRef.Util.Options++listOf :: Options -> [Block] -> WS [Block]+listOf Options{outFormat=f} x | isFormat "latex" f = return x+listOf opts (Para [RawInline (Format "tex") "\\listoffigures"]:xs)+ = gets imgRefs >>= makeList opts lofTitle xs+listOf opts (Para [RawInline (Format "tex") "\\listoftables"]:xs)+ = gets tblRefs >>= makeList opts lotTitle xs+listOf opts (Para [RawInline (Format "tex") "\\listoflistings"]:xs)+ = gets lstRefs >>= makeList opts lolTitle xs+listOf _ x = return x++makeList :: Options -> (Options -> [Block]) -> [Block] -> M.Map String RefRec -> WS [Block]+makeList opts titlef xs refs+ = return $+ titlef opts +++ (if chapDepth opts > 0+ then Div ("", ["list"], []) (itemChap `map` refsSorted)+ else OrderedList style (item `map` refsSorted))+ : xs+ where+ refsSorted = sortBy compare' $ M.toList refs+ compare' (_,RefRec{refIndex=i}) (_,RefRec{refIndex=j}) = compare i j+ item = (:[]) . Plain . refTitle . snd+ itemChap = Para . uncurry ((. (Space :)) . (++)) . (numWithChap . refIndex &&& refTitle) . snd+ numWithChap = chapPrefix (chapDelim opts)+ style = (1,DefaultStyle,DefaultDelim)
+ lib/Text/Pandoc/CrossRef/References/Refs.hs view
@@ -0,0 +1,142 @@+module Text.Pandoc.CrossRef.References.Refs (replaceRefs) where++import Text.Pandoc.Definition+import Text.Pandoc.Shared (normalizeInlines, normalizeSpaces)+import Control.Monad.State+import Data.List+import Data.Maybe+import Data.Function+import qualified Data.Map as M+import Control.Arrow as A++import Text.Pandoc.CrossRef.Util.Accessor+import Text.Pandoc.CrossRef.References.Types+import Text.Pandoc.CrossRef.References.Accessors+import Text.Pandoc.CrossRef.Util.Util+import Text.Pandoc.CrossRef.Util.Options++replaceRefs :: Options -> [Inline] -> WS [Inline]+replaceRefs opts (Cite cits _:xs)+ = (++ xs) `fmap` intercalate [Str ",", Space] `fmap`+ mapM replaceRefs' (groupBy eqPrefix cits)+ where+ eqPrefix a b = uncurry (==) $+ (fmap uncapitalizeFirst . getLabelPrefix . citationId) <***> (a,b)+ (<***>) = join (***)+ replaceRefs' cits'+ | Just prefix <- allCitsPrefix cits'+ = replaceRefs'' prefix opts cits'+ | otherwise = return [Cite cits' il']+ where+ il' = normalizeInlines $+ [Str "["]+ ++intercalate [Str ";", Space] (map citationToInlines cits')+ ++[Str "]"]+ citationToInlines c = normalizeSpaces $+ citationPrefix c ++ [Space, Str $ "@"++citationId c] ++ citationSuffix c+ replaceRefs'' = case outFormat opts of+ 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')+ ,("lst:",lstRefs')+ ,("sec:",secRefs')+ ]++-- accessors to options+prefMap :: M.Map String (Options -> Bool -> Int -> [Inline])+prefMap = M.fromList [("fig:",figPrefix)+ ,("eq:" ,eqnPrefix)+ ,("tbl:",tblPrefix)+ ,("lst:",lstPrefix)+ ,("sec:",secPrefix)+ ]++prefixes :: [String]+prefixes = M.keys accMap++getRefPrefix :: Options -> String -> Bool -> Int -> [Inline]+getRefPrefix opts prefix capitalize num+ | null refprefix = []+ | otherwise = refprefix ++ [Str "\160"]+ where refprefix = lookupUnsafe prefix prefMap opts capitalize num++lookupUnsafe :: Ord k => k -> M.Map k v -> v+lookupUnsafe = (fromJust .) . M.lookup++allCitsPrefix :: [Citation] -> Maybe String+allCitsPrefix cits = find isCitationPrefix prefixes+ where+ isCitationPrefix p =+ all (p `isPrefixOf`) $ map (uncapitalizeFirst . citationId) cits++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 cap (length cits - 1)+ cap = maybe False isFirstUpper $ getLabelPrefix . citationId . head $ cits+ cref | cap = "\\Cref"+ | otherwise = "\\cref"++listLabels :: String -> String -> String -> String -> [Citation] -> String+listLabels prefix p sep s =+ intercalate sep . map ((p ++) . (++ s) . (prefix++) . getLabelWithoutPrefix . citationId)++getLabelWithoutPrefix :: String -> String+getLabelWithoutPrefix = drop 1 . dropWhile (/=':')++getLabelPrefix :: String -> Maybe String+getLabelPrefix lab+ | uncapitalizeFirst p `elem` prefixes = Just p+ | otherwise = Nothing+ where p = (++ ":") . takeWhile (/=':') $ lab++replaceRefsOther :: String -> Options -> [Citation] -> WS [Inline]+replaceRefsOther prefix opts cits = do+ indices <- mapM (getRefIndex prefix) cits+ let+ indices' = groupBy ((==) `on` (fmap init . fst)) (sort indices)+ cap = maybe False isFirstUpper $ getLabelPrefix . citationId . head $ cits+ return $ normalizeInlines $ getRefPrefix opts prefix cap (length cits - 1) ++ intercalate [Str ",", Space] (makeIndices opts `map` indices')++getRefIndex :: String -> Citation -> WS (Maybe Index, [Inline])+getRefIndex prefix Citation{citationId=cid,citationSuffix=suf}+ = (\x -> (x,suf)) `fmap` gets (fmap refIndex . M.lookup lab . getProp prop)+ where+ prop = lookupUnsafe prefix accMap+ lab = prefix ++ getLabelWithoutPrefix cid++makeIndices :: Options -> [(Maybe Index, [Inline])] -> [Inline]+makeIndices _ s | any (isNothing . fst) s = [Strong [Str "??"]]+makeIndices o s = intercalate sep $ reverse $ map f $ foldl' f2 [] $ map (A.first fromJust) $ filter (isJust . fst) s+ where+ f2 :: [[(Index, [Inline])]] -> (Index, [Inline]) -> [[(Index, [Inline])]]+ f2 [] (i,suf) = [[(i,suf)]]+ f2 ([]:xs) (i,suf) = [(i,suf)]:xs+ f2 l@(x@((ix,sufp):_):xs) (i,suf)+ | not (null suf) || not (null sufp) = [(i,suf)]:l+ | ni-hx == 0 = l -- remove duplicates+ | ni-hx == 1 = ((i,[]):x):xs -- group sequental+ | otherwise = [(i,[])]:l -- new group+ where+ hx = fst $ last ix+ ni = fst $ last i+ 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 ",", Space]+ show' (i,suf) = chapPrefix (chapDelim o) i ++ suf
+ lib/Text/Pandoc/CrossRef/References/Types.hs view
@@ -0,0 +1,36 @@+module Text.Pandoc.CrossRef.References.Types ( References(..)+ , WS+ , RefRec(..)+ , RefMap+ , Index+ , def+ ) where++import qualified Data.Map as M+import Text.Pandoc.Definition+import Control.Monad.State+import Data.Default++type Index = [(Int, Maybe String)]++data RefRec = RefRec { refIndex :: Index+ , refTitle :: [Inline]+ } deriving (Show, Eq)++type RefMap = M.Map String RefRec++-- state data type+data References = References { imgRefs :: RefMap+ , eqnRefs :: RefMap+ , tblRefs :: RefMap+ , lstRefs :: RefMap+ , secRefs :: RefMap+ , curChap :: Index+ } deriving (Show, Eq)++--state monad+type WS a = State References a++instance Default References where+ def = References n n n n n []+ where n = M.empty
+ lib/Text/Pandoc/CrossRef/Util/Accessor.hs view
@@ -0,0 +1,17 @@+module Text.Pandoc.CrossRef.Util.Accessor (Accessor, setProp, getProp, modifyProp) where++-- from data-accessor http://www.haskell.org/haskellwiki/Record_access+-- Copyright (c) Henning Thielemann <haskell@henning-thielemann.de>, Luke Palmer <lrpalmer@gmail.com>+-- Licensed under BSD3 -- see BSD3.md+type Accessor r a = a -> r -> (a, r)++setProp :: Accessor r a -> a -> r -> r+setProp f x = snd . f x++getProp :: Accessor r a -> r -> a+getProp f = fst . f undefined++modifyProp :: Accessor r a -> (a -> a) -> r -> r+modifyProp f g rOld =+ let (a,rNew) = f (g a) rOld+ in rNew
+ lib/Text/Pandoc/CrossRef/Util/CodeBlockCaptions.hs view
@@ -0,0 +1,37 @@+module Text.Pandoc.CrossRef.Util.CodeBlockCaptions+ (+ codeBlockCaptions+ ) where++import Text.Pandoc.Definition+import Text.Pandoc.Shared (normalizeSpaces)+import Data.List (isPrefixOf, stripPrefix)+import Data.Maybe (fromMaybe)+import Text.Pandoc.CrossRef.References.Types+import Text.Pandoc.CrossRef.Util.Options++codeBlockCaptions :: Options -> [Block] -> WS [Block]+codeBlockCaptions opts x@(cb@(CodeBlock _ _):p@(Para _):xs)+ = return $ fromMaybe x $ orderAgnostic opts $ p:cb:xs+codeBlockCaptions opts x@(p@(Para _):cb@(CodeBlock _ _):xs)+ = return $ fromMaybe x $ orderAgnostic opts $ p:cb:xs+codeBlockCaptions _ x = return x++orderAgnostic :: Options -> [Block] -> Maybe [Block]+orderAgnostic opts (Para ils:CodeBlock (label,classes,attrs) code:xs)+ | cbCaptions opts+ , Just caption <- getCodeBlockCaption ils+ , not $ null label+ , "lst" `isPrefixOf` label+ = return $ Div (label,"listing":classes, [])+ [Para caption, CodeBlock ([],classes,attrs) code] : xs+orderAgnostic _ _ = Nothing++getCodeBlockCaption :: [Inline] -> Maybe [Inline]+getCodeBlockCaption ils+ | Just caption <- [Str "Listing:",Space] `stripPrefix` normalizeSpaces ils+ = Just caption+ | Just caption <- [Str ":",Space] `stripPrefix` normalizeSpaces ils+ = Just caption+ | otherwise+ = Nothing
+ lib/Text/Pandoc/CrossRef/Util/Gap.hs view
@@ -0,0 +1,12 @@+{-# LANGUAGE CPP #-}++module Text.Pandoc.CrossRef.Util.Gap where++import qualified Text.Pandoc as P++readMarkdown :: P.ReaderOptions -> String -> P.Pandoc+#if MIN_VERSION_pandoc(1,14,0)+readMarkdown = (either (error . show) id .) . P.readMarkdown+#else+readMarkdown = P.readMarkdown+#endif
+ lib/Text/Pandoc/CrossRef/Util/Meta.hs view
@@ -0,0 +1,59 @@+{-# LANGUAGE CPP #-}+module Text.Pandoc.CrossRef.Util.Meta where++import Text.Pandoc.CrossRef.Util.Gap+import Text.Pandoc.Shared (stringify)+import Text.Pandoc.Definition+import Data.Maybe (fromMaybe)+import Data.Default++getMetaList :: (Default a) => (MetaValue -> Maybe a) -> String -> Meta -> Int -> a+getMetaList f name meta i = fromMaybe def $ lookupMeta name meta >>= getList i >>= f++getMetaBool :: String -> Meta -> Bool+getMetaBool name meta = fromMaybe False $ lookupMeta name meta >>= toBool++getMetaInlines :: String -> Meta -> [Inline]+getMetaInlines name meta = fromMaybe [] $ lookupMeta name meta >>= toInlines++getMetaBlock :: String -> Meta -> [Block]+getMetaBlock name meta = fromMaybe [] $ lookupMeta name meta >>= toBlocks++getMetaString :: String -> Meta -> String+getMetaString name meta = fromMaybe [] $ lookupMeta name meta >>= toString++toInlines :: MetaValue -> Maybe [Inline]+toInlines (MetaString s) =+ return $ getInlines $ readMarkdown def s+ where getInlines (Pandoc _ bs) = concatMap getInline bs+ getInline (Plain ils) = ils+ getInline (Para ils) = ils+ getInline _ = []+toInlines (MetaInlines s) = return s+toInlines _ = Nothing++toBool :: MetaValue -> Maybe Bool+toBool (MetaBool b) = return b+toBool _ = Nothing++toBlocks :: MetaValue -> Maybe [Block]+toBlocks (MetaBlocks bs) = return bs+toBlocks (MetaInlines ils) = return [Plain ils]+toBlocks (MetaString s) =+ return $ getBlocks $ readMarkdown def s+ where getBlocks (Pandoc _ bs) = bs+toBlocks _ = Nothing++toString :: MetaValue -> Maybe String+toString (MetaString s) = Just s+toString (MetaBlocks b) = Just $ stringify b+toString (MetaInlines i) = Just $ stringify i+toString _ = Nothing++getList :: Int -> MetaValue -> Maybe MetaValue+getList i (MetaList l) = l !!? i+ where+ list !!? index | index >= 0 && index < length list = Just $ list !! index+ | not $ null list = Just $ last list+ | otherwise = Nothing+getList _ x = Just x
+ lib/Text/Pandoc/CrossRef/Util/ModifyMeta.hs view
@@ -0,0 +1,84 @@+module Text.Pandoc.CrossRef.Util.ModifyMeta+ (+ modifyMeta+ ) where++import Text.Pandoc+import Text.Pandoc.Builder+import Text.Pandoc.CrossRef.Util.Options+import Text.Pandoc.CrossRef.Util.Meta+import Text.Pandoc.CrossRef.Util.Util++modifyMeta :: Options -> Meta -> Meta+modifyMeta opts meta+ | isFormat "latex" (outFormat opts)+ = setMeta "header-includes"+ (headerInc $ lookupMeta "header-includes" meta)+ meta+ | otherwise = meta+ where+ headerInc :: Maybe MetaValue -> MetaValue+ headerInc Nothing = MetaList incList+ headerInc (Just (MetaList x)) = MetaList $ x ++ incList+ headerInc (Just x) = MetaList $ x:incList+ incList = map MetaString $+ floatnames +++ listnames +++ [ x | x <- codelisting, not $ useListings opts] +++ lolcommand +++ [ x | x <- cleveref, useCleveref opts] +++ [ x | x <- cleverefCodelisting, useCleveref opts && not (useListings opts)] +++ []+ where+ floatnames = [+ "\\AtBeginDocument{%"+ , "\\renewcommand*\\figurename{"++metaString "figureTitle"++"}"+ , "\\renewcommand*\\tablename{"++metaString "tableTitle"++"}"+ , "}"+ ]+ listnames = [+ "\\AtBeginDocument{%"+ , "\\renewcommand*\\listfigurename{"++metaString' "lofTitle"++"}"+ , "\\renewcommand*\\listtablename{"++metaString' "lotTitle"++"}"+ , "}"+ ]+ codelisting = [+ "\\usepackage{float}"+ , "\\floatstyle{ruled}"+ , "\\makeatletter"+ , "\\@ifundefined{c@chapter}{\\newfloat{codelisting}{h}{lop}}{\\newfloat{codelisting}{h}{lop}[chapter]}"+ , "\\makeatother"+ , "\\floatname{codelisting}{"++metaString "listingTitle"++"}"+ ]+ lolcommand+ | useListings opts = [+ "\\newcommand*\\listoflistings\\lstlistoflistings"+ , "\\AtBeginDocument{%"+ , "\\renewcommand*{\\lstlistlistingname}{"++metaString' "lolTitle"++"}"+ , "}"+ ]+ | otherwise = ["\\newcommand*\\listoflistings{\\listof{codelisting}{"++metaString' "lolTitle"++"}}"]+ cleveref = [+ "\\usepackage{cleveref}"+ , "\\crefname{figure}" ++ prefix figPrefix False+ , "\\crefname{table}" ++ prefix tblPrefix False+ , "\\crefname{equation}" ++ prefix eqnPrefix False+ , "\\crefname{listing}" ++ prefix lstPrefix False+ , "\\crefname{section}" ++ prefix secPrefix False+ , "\\Crefname{figure}" ++ prefix figPrefix True+ , "\\Crefname{table}" ++ prefix tblPrefix True+ , "\\Crefname{equation}" ++ prefix eqnPrefix True+ , "\\Crefname{listing}" ++ prefix lstPrefix True+ , "\\Crefname{section}" ++ prefix secPrefix True+ ]+ cleverefCodelisting = [+ "\\makeatletter"+ , "\\crefname{codelisting}{\\cref@listing@name}{\\cref@listing@name@plural}"+ , "\\Crefname{codelisting}{\\Cref@listing@name}{\\Cref@listing@name@plural}"+ , "\\makeatother"+ ]+ toLatex = writeLaTeX def . Pandoc nullMeta . return . Plain+ metaString s = toLatex $ getMetaInlines s meta+ metaString' s = toLatex [Str $ getMetaString s meta]+ prefix f uc = "{" ++ toLatex (f opts uc 0) ++ "}" +++ "{" ++ toLatex (f opts uc 1) ++ "}"
+ lib/Text/Pandoc/CrossRef/Util/Options.hs view
@@ -0,0 +1,74 @@+{-# LANGUAGE FlexibleContexts #-}++module Text.Pandoc.CrossRef.Util.Options (Options(..), getOptions) where+import Text.Pandoc.Definition+import Text.Pandoc.CrossRef.Util.Meta+import Text.Pandoc.CrossRef.Util.Template+import Text.Pandoc.CrossRef.Util.Util (capitalizeFirst)+import Text.Pandoc.Walk+import Data.Default+-- import Control.Monad.Identity++data Options = Options { useCleveref :: Bool+ , chapDepth :: Int+ , useListings :: Bool+ , cbCaptions :: Bool+ , autoSecLab :: Bool+ , figPrefix :: Bool -> Int -> [Inline]+ , eqnPrefix :: Bool -> Int -> [Inline]+ , tblPrefix :: Bool -> Int -> [Inline]+ , lstPrefix :: Bool -> Int -> [Inline]+ , secPrefix :: Bool -> Int -> [Inline]+ , chapDelim :: [Inline]+ , rangeDelim :: [Inline]+ , lofTitle :: [Block]+ , lotTitle :: [Block]+ , lolTitle :: [Block]+ , outFormat :: Maybe Format+ , figureTemplate :: Template+ , tableTemplate :: Template+ , listingTemplate :: Template+ }++getOptions :: Meta -> Maybe Format -> Options+getOptions dtv fmt =+ Options {+ useCleveref = getMetaBool "cref" dtv+ , chapDepth = if getMetaBool "chapters" dtv+ then read $ getMetaString "chaptersDepth" dtv+ else 0+ , useListings = getMetaBool "listings" dtv+ , cbCaptions = getMetaBool "codeBlockCaptions" dtv+ , autoSecLab = getMetaBool "autoSectionLabels" dtv+ , figPrefix = tryCapitalizeM (flip (getMetaList toInlines) dtv) "figPrefix"+ , eqnPrefix = tryCapitalizeM (flip (getMetaList toInlines) dtv) "eqnPrefix"+ , tblPrefix = tryCapitalizeM (flip (getMetaList toInlines) dtv) "tblPrefix"+ , lstPrefix = tryCapitalizeM (flip (getMetaList toInlines) dtv) "lstPrefix"+ , secPrefix = tryCapitalizeM (flip (getMetaList toInlines) dtv) "secPrefix"+ , chapDelim = getMetaInlines "chapDelim" dtv+ , rangeDelim = getMetaInlines "rangeDelim" dtv+ , lofTitle = getMetaBlock "lofTitle" dtv+ , lotTitle = getMetaBlock "lotTitle" dtv+ , lolTitle = getMetaBlock "lolTitle" dtv+ , outFormat = fmt+ , figureTemplate = makeTemplate dtv $ getMetaInlines "figureTemplate" dtv+ , tableTemplate = makeTemplate dtv $ getMetaInlines "tableTemplate" dtv+ , listingTemplate = makeTemplate dtv $ getMetaInlines "listingTemplate" dtv+ }++tryCapitalizeM :: (Functor m, Monad m, Walkable Inline a, Default a, Eq a) =>+ (String -> m a) -> String -> Bool -> m a+tryCapitalizeM f varname capitalize+ | capitalize = do+ res <- f (capitalizeFirst varname)+ case res of+ xs | xs == def -> f varname >>= walkM capStrFst+ | otherwise -> return xs+ | otherwise = f varname+ where+ capStrFst (Str s) = return $ Str $ capitalizeFirst s+ capStrFst x = return x++-- tryCapitalize :: (Walkable Inline a, Default a, Eq a) =>+-- (String -> a) -> String -> Bool -> a+-- tryCapitalize = ((runIdentity .) .) . tryCapitalizeM . (return .)
+ lib/Text/Pandoc/CrossRef/Util/Settings.hs view
@@ -0,0 +1,41 @@+{-# LANGUAGE CPP #-}+module Text.Pandoc.CrossRef.Util.Settings (getSettings, defaultMeta) where++import Text.Pandoc hiding (readMarkdown)+import Text.Pandoc.CrossRef.Util.Gap+import Text.Pandoc.Builder+import Control.Exception (handle,IOException)++import Text.Pandoc.CrossRef.Util.Settings.Gen+import Text.Pandoc.CrossRef.Util.Meta++getSettings :: Meta -> IO Meta+getSettings meta = do+ let handler :: IOException -> IO String+ handler _ = return []+ yaml <- handle handler $ readFile (getMetaString "crossrefYaml" (meta <> defaultMeta))+ let Pandoc dtve _ = readMarkdown def ("---\n" ++ yaml ++ "\n---")+ return $ meta <> dtve <> defaultMeta++defaultMeta :: Meta+defaultMeta =+ figureTitle (str "Figure")+ <> tableTitle (str "Table")+ <> listingTitle (str "Listing")+ <> titleDelim (str ":")+ <> chapDelim (str ".")+ <> rangeDelim (str "-")+ <> figPrefix [str "fig.", str "figs."]+ <> eqnPrefix [str "eq." , str "eqns."]+ <> tblPrefix [str "tbl.", str "tbls."]+ <> lstPrefix [str "lst.", str "lsts."]+ <> secPrefix [str "sec.", str "secs."]+ <> lofTitle (header 1 $ text "List of Figures")+ <> lotTitle (header 1 $ text "List of Tables")+ <> lolTitle (header 1 $ text "List of Listings")+ <> figureTemplate (var "figureTitle" <> space <> var "i" <> var "titleDelim" <> space <> var "t")+ <> tableTemplate (var "tableTitle" <> space <> var "i" <> var "titleDelim" <> space <> var "t")+ <> listingTemplate (var "listingTitle" <> space <> var "i" <> var "titleDelim" <> space <> var "t")+ <> crossrefYaml (MetaString "pandoc-crossref.yaml")+ <> chaptersDepth (MetaString "1")+ where var = displayMath
+ lib/Text/Pandoc/CrossRef/Util/Settings/Gen.hs view
@@ -0,0 +1,61 @@+module Text.Pandoc.CrossRef.Util.Settings.Gen where++import Text.Pandoc.CrossRef.Util.Settings.Template+import Text.Pandoc.Builder++figureTitle :: ToMetaValue a => a -> Meta+figureTitle = template "figureTitle"++tableTitle :: ToMetaValue a => a -> Meta+tableTitle = template "tableTitle"++listingTitle :: ToMetaValue a => a -> Meta+listingTitle = template "listingTitle"++titleDelim :: ToMetaValue a => a -> Meta+titleDelim = template "titleDelim"++chapDelim :: ToMetaValue a => a -> Meta+chapDelim = template "chapDelim"++rangeDelim :: ToMetaValue a => a -> Meta+rangeDelim = template "rangeDelim"++figPrefix :: ToMetaValue a => a -> Meta+figPrefix = template "figPrefix"++eqnPrefix :: ToMetaValue a => a -> Meta+eqnPrefix = template "eqnPrefix"++tblPrefix :: ToMetaValue a => a -> Meta+tblPrefix = template "tblPrefix"++lstPrefix :: ToMetaValue a => a -> Meta+lstPrefix = template "lstPrefix"++secPrefix :: ToMetaValue a => a -> Meta+secPrefix = template "secPrefix"++lofTitle :: ToMetaValue a => a -> Meta+lofTitle = template "lofTitle"++lotTitle :: ToMetaValue a => a -> Meta+lotTitle = template "lotTitle"++lolTitle :: ToMetaValue a => a -> Meta+lolTitle = template "lolTitle"++figureTemplate :: ToMetaValue a => a -> Meta+figureTemplate = template "figureTemplate"++tableTemplate :: ToMetaValue a => a -> Meta+tableTemplate = template "tableTemplate"++listingTemplate :: ToMetaValue a => a -> Meta+listingTemplate = template "listingTemplate"++crossrefYaml :: ToMetaValue a => a -> Meta+crossrefYaml = template "crossrefYaml"++chaptersDepth :: ToMetaValue a => a -> Meta+chaptersDepth = template "chaptersDepth"
+ lib/Text/Pandoc/CrossRef/Util/Settings/Template.hs view
@@ -0,0 +1,8 @@+module Text.Pandoc.CrossRef.Util.Settings.Template where++import Text.Pandoc.Definition+import Text.Pandoc.Builder+import qualified Data.Map as M++template :: ToMetaValue a => String -> a -> Meta+template name = Meta . M.singleton name . toMetaValue
+ lib/Text/Pandoc/CrossRef/Util/Template.hs view
@@ -0,0 +1,26 @@+module Text.Pandoc.CrossRef.Util.Template (Template,makeTemplate,applyTemplate) where++import Text.Pandoc.Definition+import Text.Pandoc.Generic+import Text.Pandoc.Shared (normalizeInlines)+import Data.Maybe+import Text.Pandoc.CrossRef.Util.Meta++type VarFunc = String -> Maybe MetaValue+newtype Template = Template (VarFunc -> [Inline])++makeTemplate :: Meta -> [Inline] -> Template+makeTemplate dtv = Template . flip scan . scan (`lookupMeta` dtv)+ where+ scan = bottomUp . go+ go vf (x@(Math DisplayMath var):xs) = replaceVar (vf var) [x] ++ xs+ go _ x = x+ replaceVar val def' = fromMaybe def' $ val >>= toInlines++applyTemplate :: [Inline] -> [Inline] -> Template -> [Inline]+applyTemplate i t (Template g) =+ normalizeInlines $ g internalVars+ where+ internalVars "i" = Just $ MetaInlines i+ internalVars "t" = Just $ MetaInlines t+ internalVars _ = Nothing
+ lib/Text/Pandoc/CrossRef/Util/Util.hs view
@@ -0,0 +1,26 @@+module Text.Pandoc.CrossRef.Util.Util where++import Text.Pandoc.CrossRef.References.Types+import Text.Pandoc.Definition+import Data.Char (toUpper, toLower, isUpper)+import Data.List (intercalate)+import Data.Maybe (fromMaybe)++isFormat :: String -> Maybe Format -> Bool+isFormat fmt (Just (Format f)) = takeWhile (`notElem` "+-") f == fmt+isFormat _ Nothing = False++capitalizeFirst :: String -> String+capitalizeFirst (x:xs) = toUpper x : xs+capitalizeFirst [] = []++uncapitalizeFirst :: String -> String+uncapitalizeFirst (x:xs) = toLower x : xs+uncapitalizeFirst [] = []++isFirstUpper :: String -> Bool+isFirstUpper (x:_) = isUpper x+isFirstUpper [] = False++chapPrefix :: [Inline] -> Index -> [Inline]+chapPrefix delim index = intercalate delim (map (return . Str . uncurry (fromMaybe . show)) index)
pandoc-crossref.cabal view
@@ -2,7 +2,7 @@ -- documentation, see http://haskell.org/cabal/users-guide/ name: pandoc-crossref-version: 0.1.6.2+version: 0.1.6.3 synopsis: Pandoc filter for cross-references description: pandoc-crossref is a pandoc filter for numbering figures, equations, tables and cross-references to them. license: GPL-2@@ -24,7 +24,7 @@ source-repository this type: git location: https://github.com/lierdakil/pandoc-crossref- tag: v0.1.6.2+ tag: v0.1.6.3 library exposed-modules: Text.Pandoc.CrossRef@@ -53,7 +53,7 @@ , yaml >= 0.8 && <0.9 , data-default >= 0.4 && <0.6 , bytestring >=0.9 && <0.11- hs-source-dirs: src+ hs-source-dirs: lib Ghc-Options: -Wall default-language: Haskell2010 other-extensions: RankNTypes@@ -71,14 +71,14 @@ , data-default >= 0.4 && <0.6 , bytestring >=0.9 && <0.11 , pandoc-crossref- hs-source-dirs: .+ hs-source-dirs: src Ghc-Options: -Wall default-language: Haskell2010 Test-Suite test-pandoc-crossref Type: exitcode-stdio-1.0 Main-Is: test-pandoc-crossref.hs- hs-source-dirs: test, src+ hs-source-dirs: test, lib Build-Depends: base >=4.2 && <5 , pandoc >= 1.13 && <1.17 , mtl >= 1.1 && <2.3
− pandoc-crossref.hs
@@ -1,14 +0,0 @@-import Text.Pandoc-import Text.Pandoc.JSON--import Text.Pandoc.CrossRef--main :: IO ()-main = toJSONFilter go- where- go fmt p@(Pandoc meta _) = runCrossRefIO meta fmt action p- where- action (Pandoc _ bs) = do- meta' <- crossRefMeta- bs' <- crossRefBlocks bs- return $ Pandoc meta' bs'
− src/Text/Pandoc/CrossRef.hs
@@ -1,143 +0,0 @@-{- |- Module : Text.Pandoc.CrossRef- Copyright : Copyright (C) 2015 Nikolay Yakimov- License : GNU GPL, version 2 or above-- Maintainer : Nikolay Yakimov <root@livid.pp.ru>- Stability : alpha- Portability : portable--Public interface to pandoc-crossref library--Example of use:--> import Text.Pandoc-> import Text.Pandoc.JSON->-> import Text.Pandoc.CrossRef->-> main :: IO ()-> main = toJSONFilter go-> where-> go fmt p@(Pandoc meta _) = runCrossRefIO meta fmt action p-> where-> action (Pandoc _ bs) = do-> meta' <- crossRefMeta-> bs' <- crossRefBlocks bs-> return $ Pandoc meta' bs'--This module also exports utility functions for setting up meta-settings for-pandoc-crossref. Refer to documentation for a complete list of metadata field-names. All functions accept a single argument of type, returned by-"Text.Pandoc.Builder" functions, and return 'Meta'.--Example:--> runCrossRefIO meta fmt crossRefBlocks blocks-> where-> meta =-> figureTitle (str "Figura")-> <> tableTitle (str "Tabla")-> <> figPrefix (str "fig.")-> <> eqnPrefix (str "ec.")-> <> tblPrefix (str "tbl.")-> <> loftitle (header 1 $ text "Lista de figuras")-> <> lotTitle (header 1 $ text "Lista de tablas")-> <> chaptersDepth (MetaString "2")---}-{-# LANGUAGE RankNTypes #-}--module Text.Pandoc.CrossRef (- crossRefBlocks- , crossRefMeta- , defaultCrossRefAction- , runCrossRef- , runCrossRefIO- , module SG- , CrossRefM- , CrossRefEnv(..)- ) where--import Control.Monad.State-import qualified Control.Monad.Reader as R-import Text.Pandoc-import Text.Pandoc.Walk-import Data.Monoid ((<>))--import Text.Pandoc.CrossRef.References-import Text.Pandoc.CrossRef.Util.Settings-import Text.Pandoc.CrossRef.Util.Options-import Text.Pandoc.CrossRef.Util.CodeBlockCaptions-import Text.Pandoc.CrossRef.Util.ModifyMeta-import Text.Pandoc.CrossRef.Util.Settings.Gen as SG---- | Enviromnent for 'CrossRefM'-data CrossRefEnv = CrossRefEnv {- creSettings :: Meta -- ^Metadata settings- , creOptions :: Options -- ^Internal pandoc-crossref options- }---- | Essentially a reader monad for basic pandoc-crossref environment-type CrossRefM a = R.Reader CrossRefEnv a--{- | Walk over blocks, while inserting cross-references, list-of, etc.--Works in 'CrossRefM' monad. -}-crossRefBlocks :: [Block] -> CrossRefM [Block]-crossRefBlocks blocks = do- opts <- R.asks creOptions- let- doWalk =- bottomUpM (codeBlockCaptions opts) (walk divBlocks blocks)- >>= walkM (replaceBlocks opts)- >>= bottomUpM (replaceRefs opts)- >>= bottomUpM (listOf opts)- return $ evalState doWalk def--{- | Modifies metadata for LaTeX output, adding header-includes instructions-to setup custom and builtin environments.--Note, that if output format is not "latex", this function does nothing.--Works in 'CrossRefM' monad. -}-crossRefMeta :: CrossRefM Meta-crossRefMeta = do- opts <- R.asks creOptions- dtv <- R.asks creSettings- return $ modifyMeta opts dtv--{- | Combines 'crossRefMeta' and 'crossRefBlocks'--Works in 'CrossRefM' monad. -}-defaultCrossRefAction :: Pandoc -> CrossRefM Pandoc-defaultCrossRefAction (Pandoc _ bs) = do- meta' <- crossRefMeta- bs' <- crossRefBlocks bs- return $ Pandoc meta' bs'--{- | Run an action in 'CrossRefM' monad with argument, and return pure result.--This is primary function to work with 'CrossRefM' -}-runCrossRef :: forall a b. Meta -> Maybe Format -> (a -> CrossRefM b) -> a -> b-runCrossRef meta fmt action arg = R.runReader (action arg) env- where- settings = meta <> defaultMeta- env = CrossRefEnv {- creSettings = settings- , creOptions = getOptions settings fmt- }--{- | Run an action in 'CrossRefM' monad with argument, and return 'IO' result.--This function will attempt to read pandoc-crossref settings from settings-file specified by crossrefYaml metadata field. -}-runCrossRefIO :: forall a b. Meta -> Maybe Format -> (a -> CrossRefM b) -> a -> IO b-runCrossRefIO meta fmt action arg = do- settings <- getSettings meta- let- env = CrossRefEnv {- creSettings = settings- , creOptions = getOptions settings fmt- }- return $ R.runReader (action arg) env
− src/Text/Pandoc/CrossRef/References.hs
@@ -1,7 +0,0 @@-module Text.Pandoc.CrossRef.References ( module X ) where--import Text.Pandoc.CrossRef.References.Accessors as X-import Text.Pandoc.CrossRef.References.Types as X-import Text.Pandoc.CrossRef.References.Blocks as X (divBlocks, replaceBlocks)-import Text.Pandoc.CrossRef.References.Refs as X-import Text.Pandoc.CrossRef.References.List as X
− src/Text/Pandoc/CrossRef/References/Accessors.hs
@@ -1,19 +0,0 @@-module Text.Pandoc.CrossRef.References.Accessors where--import Text.Pandoc.CrossRef.References.Types-import Text.Pandoc.CrossRef.Util.Accessor--imgRefs' :: Accessor References RefMap-imgRefs' new r@References{imgRefs=old} = (old, r{imgRefs=new})--eqnRefs' :: Accessor References RefMap-eqnRefs' new r@References{eqnRefs=old} = (old, r{eqnRefs=new})--tblRefs' :: Accessor References RefMap-tblRefs' new r@References{tblRefs=old} = (old, r{tblRefs=new})--lstRefs' :: Accessor References RefMap-lstRefs' new r@References{lstRefs=old} = (old, r{lstRefs=new})--secRefs' :: Accessor References RefMap-secRefs' new r@References{secRefs=old} = (old, r{secRefs=new})
− src/Text/Pandoc/CrossRef/References/Blocks.hs
@@ -1,190 +0,0 @@-{-# LANGUAGE CPP #-}-module Text.Pandoc.CrossRef.References.Blocks- ( divBlocks- , replaceBlocks- , spanInlines- , replaceInlines- ) where--import Text.Pandoc.Definition-import Text.Pandoc.Generic-import Text.Pandoc.Builder (text, toList)-import Text.Pandoc.Shared (stringify, normalizeSpaces)-import Control.Monad.State-import Data.List-import qualified Data.Map as M--import Text.Pandoc.CrossRef.Util.Accessor-import Text.Pandoc.CrossRef.References.Types-import Text.Pandoc.CrossRef.References.Accessors-import Text.Pandoc.CrossRef.Util.Util-import Text.Pandoc.CrossRef.Util.Options-import Text.Pandoc.CrossRef.Util.Template--replaceBlocks :: Options -> Block -> WS Block-replaceBlocks opts (Header n (label, cls, attrs) text')- = do- let label' = if autoSecLab opts && not ("sec:" `isPrefixOf` label)- then "sec:"++label- else label- unless ("unnumbered" `elem` cls) $ do- modify $ \r@References{curChap=cc} ->- let ln = length cc- cl = lookup "label" attrs- inc l = init l ++ [(fst (last l) + 1, cl)]- cc' | ln > n = inc $ take n cc- | ln == n = inc cc- | otherwise = cc ++ take (n-ln-1) (zip [1,1..] $ repeat Nothing) ++ [(1,cl)]- in r{curChap=cc'}- when ("sec:" `isPrefixOf` label') $ replaceAttrSec label' text' secRefs'- return $ Header n (label', cls, attrs) text'-#if MIN_VERSION_pandoc(1,16,0)-#else-replaceBlocks opts (Div (label,_,attrs) [Plain [Image alt img]])- | "fig:" `isPrefixOf` label- = do- idxStr <- replaceAttr opts label (lookup "label" attrs) alt imgRefs'- let alt' = case outFormat opts of- f | isFormat "latex" f ->- RawInline (Format "tex") ("\\label{"++label++"}") : alt- _ -> applyTemplate idxStr alt $ figureTemplate opts- return $ Para [Image alt' img]-#endif-replaceBlocks opts (Div (label,_,attrs) [Table title align widths header cells])- | not $ null title- , "tbl:" `isPrefixOf` label- = do- idxStr <- replaceAttr opts label (lookup "label" attrs) title tblRefs'- let title' =- case outFormat opts of- f | isFormat "latex" f ->- RawInline (Format "tex") ("\\label{"++label++"}") : title- _ -> applyTemplate idxStr title $ tableTemplate opts- return $ Table title' align widths header cells-replaceBlocks opts cb@(CodeBlock (label, classes, attrs) code)- | not $ null label- , "lst:" `isPrefixOf` label- , Just caption <- lookup "caption" attrs- = case outFormat opts of- f- --if used with listings package,nothing shoud be done- | isFormat "latex" f, useListings opts -> return cb- --if not using listings, however, wrap it in a codelisting environment- | isFormat "latex" f ->- return $ Div nullAttr [- RawBlock (Format "tex")- $ "\\begin{codelisting}\n\\caption{"++caption++"}"- , cb- , RawBlock (Format "tex") "\\end{codelisting}"- ]- _ -> do- let cap = toList $ text caption- idxStr <- replaceAttr opts label (lookup "label" attrs) cap lstRefs'- let caption' = applyTemplate idxStr cap $ listingTemplate opts- return $ Div (label, "listing":classes, []) [- Para caption'- , CodeBlock ([], classes, attrs \\ [("caption", caption)]) code- ]-replaceBlocks opts- (Div (label,"listing":_, [])- [Para caption, CodeBlock ([],classes,attrs) code])- | not $ null label- , "lst:" `isPrefixOf` label- = case outFormat opts of- f- --if used with listings package, return code block with caption- | isFormat "latex" f, useListings opts ->- return $ CodeBlock (label,classes,("caption",stringify caption):attrs) code- --if not using listings, however, wrap it in a codelisting environment- | isFormat "latex" f ->- return $ Div nullAttr [- RawBlock (Format "tex") "\\begin{codelisting}"- , Para [RawInline (Format "tex") "\\caption",Span nullAttr caption]- , CodeBlock (label,classes,attrs) code- , RawBlock (Format "tex") "\\end{codelisting}"- ]- _ -> do- idxStr <- replaceAttr opts label (lookup "label" attrs) caption lstRefs'- let caption' = applyTemplate idxStr caption $ listingTemplate opts- return $ Div (label, "listing":classes, []) [- Para caption'- , CodeBlock ([], classes, attrs) code- ]-replaceBlocks opts x = bottomUpM (replaceInlines opts) x--replaceInlines :: Options -> [Inline] -> WS [Inline]-replaceInlines opts (Span (label,_,attrs) [Math DisplayMath eq]:ils')- | "eq:" `isPrefixOf` label- = case outFormat opts of- f | isFormat "latex" f ->- let eqn = "\\begin{equation}"++eq++"\\label{"++label++"}\\end{equation}"- in return $ RawInline (Format "tex") eqn : ils'- _ -> do- idxStr <- replaceAttr opts label (lookup "label" attrs) [] eqnRefs'- let eq' = eq++"\\qquad("++stringify idxStr++")"- return $ Math DisplayMath eq' : ils'-#if MIN_VERSION_pandoc(1,16,0)-replaceInlines opts (Image attr@(label,_,attrs) alt img:ils')- | "fig:" `isPrefixOf` label, "fig:" `isPrefixOf` snd img- = do- idxStr <- replaceAttr opts label (lookup "label" attrs) alt imgRefs'- let alt' = case outFormat opts of- f | isFormat "latex" f ->- RawInline (Format "tex") ("\\label{"++label++"}") : alt- _ -> applyTemplate idxStr alt $ figureTemplate opts- return $ Image attr alt' img : ils'-#else-#endif-replaceInlines _ x = return x--divBlocks :: Block -> Block-#if MIN_VERSION_pandoc(1,16,0)-#else-divBlocks (Para (Image alt (img, title):c))- | Just label <- getRefLabel "fig" c- = Div (label,[],[]) [Plain [Image alt (img, "fig:" ++ title)]]-#endif-divBlocks (Table title align widths header cells)- | not $ null title- , Just label <- getRefLabel "tbl" [last title]- = Div (label,[],[]) [Table (init title) align widths header cells]-divBlocks x = bottomUp spanInlines x--spanInlines :: [Inline] -> [Inline]-spanInlines (math@(Math DisplayMath _eq):ils)- | c:ils' <- dropWhile (==Space) ils- , Just label <- getRefLabel "eq" [c]- = Span (label,[],[]) [math]:ils'-spanInlines x = x--getRefLabel :: String -> [Inline] -> Maybe String-getRefLabel _ [] = Nothing-getRefLabel tag ils- | Str attr <- last ils- , all (==Space) (init ils)- , "}" `isSuffixOf` attr- , ("{#"++tag++":") `isPrefixOf` attr- = init `fmap` stripPrefix "{#" attr-getRefLabel _ _ = Nothing--replaceAttr :: Options -> String -> Maybe String -> [Inline] -> Accessor References RefMap -> WS [Inline]-replaceAttr o label refLabel title prop- = do- chap <- take (chapDepth o) `fmap` gets curChap- i <- (1+) `fmap` gets (M.size . M.filter ((==chap) . init . refIndex) . getProp prop)- let index = chap ++ [(i, refLabel)]- modify $ modifyProp prop $ M.insert label RefRec {- refIndex= index- , refTitle=normalizeSpaces title- }- return $ chapPrefix (chapDelim o) index--replaceAttrSec :: String -> [Inline] -> Accessor References RefMap -> WS ()-replaceAttrSec label title prop- = do- index <- gets curChap- modify $ modifyProp prop $ M.insert label RefRec {- refIndex=index- , refTitle=normalizeSpaces title- }- return ()
− src/Text/Pandoc/CrossRef/References/List.hs
@@ -1,37 +0,0 @@-module Text.Pandoc.CrossRef.References.List (listOf) where--import Text.Pandoc.Definition-import Control.Monad.State-import Control.Arrow-import Data.List-import qualified Data.Map as M--import Text.Pandoc.CrossRef.References.Types-import Text.Pandoc.CrossRef.Util.Util-import Text.Pandoc.CrossRef.Util.Options--listOf :: Options -> [Block] -> WS [Block]-listOf Options{outFormat=f} x | isFormat "latex" f = return x-listOf opts (Para [RawInline (Format "tex") "\\listoffigures"]:xs)- = gets imgRefs >>= makeList opts lofTitle xs-listOf opts (Para [RawInline (Format "tex") "\\listoftables"]:xs)- = gets tblRefs >>= makeList opts lotTitle xs-listOf opts (Para [RawInline (Format "tex") "\\listoflistings"]:xs)- = gets lstRefs >>= makeList opts lolTitle xs-listOf _ x = return x--makeList :: Options -> (Options -> [Block]) -> [Block] -> M.Map String RefRec -> WS [Block]-makeList opts titlef xs refs- = return $- titlef opts ++- (if chapDepth opts > 0- then Div ("", ["list"], []) (itemChap `map` refsSorted)- else OrderedList style (item `map` refsSorted))- : xs- where- refsSorted = sortBy compare' $ M.toList refs- compare' (_,RefRec{refIndex=i}) (_,RefRec{refIndex=j}) = compare i j- item = (:[]) . Plain . refTitle . snd- itemChap = Para . uncurry ((. (Space :)) . (++)) . (numWithChap . refIndex &&& refTitle) . snd- numWithChap = chapPrefix (chapDelim opts)- style = (1,DefaultStyle,DefaultDelim)
− src/Text/Pandoc/CrossRef/References/Refs.hs
@@ -1,142 +0,0 @@-module Text.Pandoc.CrossRef.References.Refs (replaceRefs) where--import Text.Pandoc.Definition-import Text.Pandoc.Shared (normalizeInlines, normalizeSpaces)-import Control.Monad.State-import Data.List-import Data.Maybe-import Data.Function-import qualified Data.Map as M-import Control.Arrow as A--import Text.Pandoc.CrossRef.Util.Accessor-import Text.Pandoc.CrossRef.References.Types-import Text.Pandoc.CrossRef.References.Accessors-import Text.Pandoc.CrossRef.Util.Util-import Text.Pandoc.CrossRef.Util.Options--replaceRefs :: Options -> [Inline] -> WS [Inline]-replaceRefs opts (Cite cits _:xs)- = (++ xs) `fmap` intercalate [Str ",", Space] `fmap`- mapM replaceRefs' (groupBy eqPrefix cits)- where- eqPrefix a b = uncurry (==) $- (fmap uncapitalizeFirst . getLabelPrefix . citationId) <***> (a,b)- (<***>) = join (***)- replaceRefs' cits'- | Just prefix <- allCitsPrefix cits'- = replaceRefs'' prefix opts cits'- | otherwise = return [Cite cits' il']- where- il' = normalizeInlines $- [Str "["]- ++intercalate [Str ";", Space] (map citationToInlines cits')- ++[Str "]"]- citationToInlines c = normalizeSpaces $- citationPrefix c ++ [Space, Str $ "@"++citationId c] ++ citationSuffix c- replaceRefs'' = case outFormat opts of- 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')- ,("lst:",lstRefs')- ,("sec:",secRefs')- ]---- accessors to options-prefMap :: M.Map String (Options -> Bool -> Int -> [Inline])-prefMap = M.fromList [("fig:",figPrefix)- ,("eq:" ,eqnPrefix)- ,("tbl:",tblPrefix)- ,("lst:",lstPrefix)- ,("sec:",secPrefix)- ]--prefixes :: [String]-prefixes = M.keys accMap--getRefPrefix :: Options -> String -> Bool -> Int -> [Inline]-getRefPrefix opts prefix capitalize num- | null refprefix = []- | otherwise = refprefix ++ [Str "\160"]- where refprefix = lookupUnsafe prefix prefMap opts capitalize num--lookupUnsafe :: Ord k => k -> M.Map k v -> v-lookupUnsafe = (fromJust .) . M.lookup--allCitsPrefix :: [Citation] -> Maybe String-allCitsPrefix cits = find isCitationPrefix prefixes- where- isCitationPrefix p =- all (p `isPrefixOf`) $ map (uncapitalizeFirst . citationId) cits--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 cap (length cits - 1)- cap = maybe False isFirstUpper $ getLabelPrefix . citationId . head $ cits- cref | cap = "\\Cref"- | otherwise = "\\cref"--listLabels :: String -> String -> String -> String -> [Citation] -> String-listLabels prefix p sep s =- intercalate sep . map ((p ++) . (++ s) . (prefix++) . getLabelWithoutPrefix . citationId)--getLabelWithoutPrefix :: String -> String-getLabelWithoutPrefix = drop 1 . dropWhile (/=':')--getLabelPrefix :: String -> Maybe String-getLabelPrefix lab- | uncapitalizeFirst p `elem` prefixes = Just p- | otherwise = Nothing- where p = (++ ":") . takeWhile (/=':') $ lab--replaceRefsOther :: String -> Options -> [Citation] -> WS [Inline]-replaceRefsOther prefix opts cits = do- indices <- mapM (getRefIndex prefix) cits- let- indices' = groupBy ((==) `on` (fmap init . fst)) (sort indices)- cap = maybe False isFirstUpper $ getLabelPrefix . citationId . head $ cits- return $ normalizeInlines $ getRefPrefix opts prefix cap (length cits - 1) ++ intercalate [Str ",", Space] (makeIndices opts `map` indices')--getRefIndex :: String -> Citation -> WS (Maybe Index, [Inline])-getRefIndex prefix Citation{citationId=cid,citationSuffix=suf}- = (\x -> (x,suf)) `fmap` gets (fmap refIndex . M.lookup lab . getProp prop)- where- prop = lookupUnsafe prefix accMap- lab = prefix ++ getLabelWithoutPrefix cid--makeIndices :: Options -> [(Maybe Index, [Inline])] -> [Inline]-makeIndices _ s | any (isNothing . fst) s = [Strong [Str "??"]]-makeIndices o s = intercalate sep $ reverse $ map f $ foldl' f2 [] $ map (A.first fromJust) $ filter (isJust . fst) s- where- f2 :: [[(Index, [Inline])]] -> (Index, [Inline]) -> [[(Index, [Inline])]]- f2 [] (i,suf) = [[(i,suf)]]- f2 ([]:xs) (i,suf) = [(i,suf)]:xs- f2 l@(x@((ix,sufp):_):xs) (i,suf)- | not (null suf) || not (null sufp) = [(i,suf)]:l- | ni-hx == 0 = l -- remove duplicates- | ni-hx == 1 = ((i,[]):x):xs -- group sequental- | otherwise = [(i,[])]:l -- new group- where- hx = fst $ last ix- ni = fst $ last i- 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 ",", Space]- show' (i,suf) = chapPrefix (chapDelim o) i ++ suf
− src/Text/Pandoc/CrossRef/References/Types.hs
@@ -1,36 +0,0 @@-module Text.Pandoc.CrossRef.References.Types ( References(..)- , WS- , RefRec(..)- , RefMap- , Index- , def- ) where--import qualified Data.Map as M-import Text.Pandoc.Definition-import Control.Monad.State-import Data.Default--type Index = [(Int, Maybe String)]--data RefRec = RefRec { refIndex :: Index- , refTitle :: [Inline]- } deriving (Show, Eq)--type RefMap = M.Map String RefRec---- state data type-data References = References { imgRefs :: RefMap- , eqnRefs :: RefMap- , tblRefs :: RefMap- , lstRefs :: RefMap- , secRefs :: RefMap- , curChap :: Index- } deriving (Show, Eq)----state monad-type WS a = State References a--instance Default References where- def = References n n n n n []- where n = M.empty
− src/Text/Pandoc/CrossRef/Util/Accessor.hs
@@ -1,17 +0,0 @@-module Text.Pandoc.CrossRef.Util.Accessor (Accessor, setProp, getProp, modifyProp) where---- from data-accessor http://www.haskell.org/haskellwiki/Record_access--- Copyright (c) Henning Thielemann <haskell@henning-thielemann.de>, Luke Palmer <lrpalmer@gmail.com>--- Licensed under BSD3 -- see BSD3.md-type Accessor r a = a -> r -> (a, r)--setProp :: Accessor r a -> a -> r -> r-setProp f x = snd . f x--getProp :: Accessor r a -> r -> a-getProp f = fst . f undefined--modifyProp :: Accessor r a -> (a -> a) -> r -> r-modifyProp f g rOld =- let (a,rNew) = f (g a) rOld- in rNew
− src/Text/Pandoc/CrossRef/Util/CodeBlockCaptions.hs
@@ -1,37 +0,0 @@-module Text.Pandoc.CrossRef.Util.CodeBlockCaptions- (- codeBlockCaptions- ) where--import Text.Pandoc.Definition-import Text.Pandoc.Shared (normalizeSpaces)-import Data.List (isPrefixOf, stripPrefix)-import Data.Maybe (fromMaybe)-import Text.Pandoc.CrossRef.References.Types-import Text.Pandoc.CrossRef.Util.Options--codeBlockCaptions :: Options -> [Block] -> WS [Block]-codeBlockCaptions opts x@(cb@(CodeBlock _ _):p@(Para _):xs)- = return $ fromMaybe x $ orderAgnostic opts $ p:cb:xs-codeBlockCaptions opts x@(p@(Para _):cb@(CodeBlock _ _):xs)- = return $ fromMaybe x $ orderAgnostic opts $ p:cb:xs-codeBlockCaptions _ x = return x--orderAgnostic :: Options -> [Block] -> Maybe [Block]-orderAgnostic opts (Para ils:CodeBlock (label,classes,attrs) code:xs)- | cbCaptions opts- , Just caption <- getCodeBlockCaption ils- , not $ null label- , "lst" `isPrefixOf` label- = return $ Div (label,"listing":classes, [])- [Para caption, CodeBlock ([],classes,attrs) code] : xs-orderAgnostic _ _ = Nothing--getCodeBlockCaption :: [Inline] -> Maybe [Inline]-getCodeBlockCaption ils- | Just caption <- [Str "Listing:",Space] `stripPrefix` normalizeSpaces ils- = Just caption- | Just caption <- [Str ":",Space] `stripPrefix` normalizeSpaces ils- = Just caption- | otherwise- = Nothing
− src/Text/Pandoc/CrossRef/Util/Gap.hs
@@ -1,12 +0,0 @@-{-# LANGUAGE CPP #-}--module Text.Pandoc.CrossRef.Util.Gap where--import qualified Text.Pandoc as P--readMarkdown :: P.ReaderOptions -> String -> P.Pandoc-#if MIN_VERSION_pandoc(1,14,0)-readMarkdown = (either (error . show) id .) . P.readMarkdown-#else-readMarkdown = P.readMarkdown-#endif
− src/Text/Pandoc/CrossRef/Util/Meta.hs
@@ -1,59 +0,0 @@-{-# LANGUAGE CPP #-}-module Text.Pandoc.CrossRef.Util.Meta where--import Text.Pandoc.CrossRef.Util.Gap-import Text.Pandoc.Shared (stringify)-import Text.Pandoc.Definition-import Data.Maybe (fromMaybe)-import Data.Default--getMetaList :: (Default a) => (MetaValue -> Maybe a) -> String -> Meta -> Int -> a-getMetaList f name meta i = fromMaybe def $ lookupMeta name meta >>= getList i >>= f--getMetaBool :: String -> Meta -> Bool-getMetaBool name meta = fromMaybe False $ lookupMeta name meta >>= toBool--getMetaInlines :: String -> Meta -> [Inline]-getMetaInlines name meta = fromMaybe [] $ lookupMeta name meta >>= toInlines--getMetaBlock :: String -> Meta -> [Block]-getMetaBlock name meta = fromMaybe [] $ lookupMeta name meta >>= toBlocks--getMetaString :: String -> Meta -> String-getMetaString name meta = fromMaybe [] $ lookupMeta name meta >>= toString--toInlines :: MetaValue -> Maybe [Inline]-toInlines (MetaString s) =- return $ getInlines $ readMarkdown def s- where getInlines (Pandoc _ bs) = concatMap getInline bs- getInline (Plain ils) = ils- getInline (Para ils) = ils- getInline _ = []-toInlines (MetaInlines s) = return s-toInlines _ = Nothing--toBool :: MetaValue -> Maybe Bool-toBool (MetaBool b) = return b-toBool _ = Nothing--toBlocks :: MetaValue -> Maybe [Block]-toBlocks (MetaBlocks bs) = return bs-toBlocks (MetaInlines ils) = return [Plain ils]-toBlocks (MetaString s) =- return $ getBlocks $ readMarkdown def s- where getBlocks (Pandoc _ bs) = bs-toBlocks _ = Nothing--toString :: MetaValue -> Maybe String-toString (MetaString s) = Just s-toString (MetaBlocks b) = Just $ stringify b-toString (MetaInlines i) = Just $ stringify i-toString _ = Nothing--getList :: Int -> MetaValue -> Maybe MetaValue-getList i (MetaList l) = l !!? i- where- list !!? index | index >= 0 && index < length list = Just $ list !! index- | not $ null list = Just $ last list- | otherwise = Nothing-getList _ x = Just x
− src/Text/Pandoc/CrossRef/Util/ModifyMeta.hs
@@ -1,84 +0,0 @@-module Text.Pandoc.CrossRef.Util.ModifyMeta- (- modifyMeta- ) where--import Text.Pandoc-import Text.Pandoc.Builder-import Text.Pandoc.CrossRef.Util.Options-import Text.Pandoc.CrossRef.Util.Meta-import Text.Pandoc.CrossRef.Util.Util--modifyMeta :: Options -> Meta -> Meta-modifyMeta opts meta- | isFormat "latex" (outFormat opts)- = setMeta "header-includes"- (headerInc $ lookupMeta "header-includes" meta)- meta- | otherwise = meta- where- headerInc :: Maybe MetaValue -> MetaValue- headerInc Nothing = MetaList incList- headerInc (Just (MetaList x)) = MetaList $ x ++ incList- headerInc (Just x) = MetaList $ x:incList- incList = map MetaString $- floatnames ++- listnames ++- [ x | x <- codelisting, not $ useListings opts] ++- lolcommand ++- [ x | x <- cleveref, useCleveref opts] ++- [ x | x <- cleverefCodelisting, useCleveref opts && not (useListings opts)] ++- []- where- floatnames = [- "\\AtBeginDocument{%"- , "\\renewcommand*\\figurename{"++metaString "figureTitle"++"}"- , "\\renewcommand*\\tablename{"++metaString "tableTitle"++"}"- , "}"- ]- listnames = [- "\\AtBeginDocument{%"- , "\\renewcommand*\\listfigurename{"++metaString' "lofTitle"++"}"- , "\\renewcommand*\\listtablename{"++metaString' "lotTitle"++"}"- , "}"- ]- codelisting = [- "\\usepackage{float}"- , "\\floatstyle{ruled}"- , "\\makeatletter"- , "\\@ifundefined{c@chapter}{\\newfloat{codelisting}{h}{lop}}{\\newfloat{codelisting}{h}{lop}[chapter]}"- , "\\makeatother"- , "\\floatname{codelisting}{"++metaString "listingTitle"++"}"- ]- lolcommand- | useListings opts = [- "\\newcommand*\\listoflistings\\lstlistoflistings"- , "\\AtBeginDocument{%"- , "\\renewcommand*{\\lstlistlistingname}{"++metaString' "lolTitle"++"}"- , "}"- ]- | otherwise = ["\\newcommand*\\listoflistings{\\listof{codelisting}{"++metaString' "lolTitle"++"}}"]- cleveref = [- "\\usepackage{cleveref}"- , "\\crefname{figure}" ++ prefix figPrefix False- , "\\crefname{table}" ++ prefix tblPrefix False- , "\\crefname{equation}" ++ prefix eqnPrefix False- , "\\crefname{listing}" ++ prefix lstPrefix False- , "\\crefname{section}" ++ prefix secPrefix False- , "\\Crefname{figure}" ++ prefix figPrefix True- , "\\Crefname{table}" ++ prefix tblPrefix True- , "\\Crefname{equation}" ++ prefix eqnPrefix True- , "\\Crefname{listing}" ++ prefix lstPrefix True- , "\\Crefname{section}" ++ prefix secPrefix True- ]- cleverefCodelisting = [- "\\makeatletter"- , "\\crefname{codelisting}{\\cref@listing@name}{\\cref@listing@name@plural}"- , "\\Crefname{codelisting}{\\Cref@listing@name}{\\Cref@listing@name@plural}"- , "\\makeatother"- ]- toLatex = writeLaTeX def . Pandoc nullMeta . return . Plain- metaString s = toLatex $ getMetaInlines s meta- metaString' s = toLatex [Str $ getMetaString s meta]- prefix f uc = "{" ++ toLatex (f opts uc 0) ++ "}" ++- "{" ++ toLatex (f opts uc 1) ++ "}"
− src/Text/Pandoc/CrossRef/Util/Options.hs
@@ -1,74 +0,0 @@-{-# LANGUAGE FlexibleContexts #-}--module Text.Pandoc.CrossRef.Util.Options (Options(..), getOptions) where-import Text.Pandoc.Definition-import Text.Pandoc.CrossRef.Util.Meta-import Text.Pandoc.CrossRef.Util.Template-import Text.Pandoc.CrossRef.Util.Util (capitalizeFirst)-import Text.Pandoc.Walk-import Data.Default--- import Control.Monad.Identity--data Options = Options { useCleveref :: Bool- , chapDepth :: Int- , useListings :: Bool- , cbCaptions :: Bool- , autoSecLab :: Bool- , figPrefix :: Bool -> Int -> [Inline]- , eqnPrefix :: Bool -> Int -> [Inline]- , tblPrefix :: Bool -> Int -> [Inline]- , lstPrefix :: Bool -> Int -> [Inline]- , secPrefix :: Bool -> Int -> [Inline]- , chapDelim :: [Inline]- , rangeDelim :: [Inline]- , lofTitle :: [Block]- , lotTitle :: [Block]- , lolTitle :: [Block]- , outFormat :: Maybe Format- , figureTemplate :: Template- , tableTemplate :: Template- , listingTemplate :: Template- }--getOptions :: Meta -> Maybe Format -> Options-getOptions dtv fmt =- Options {- useCleveref = getMetaBool "cref" dtv- , chapDepth = if getMetaBool "chapters" dtv- then read $ getMetaString "chaptersDepth" dtv- else 0- , useListings = getMetaBool "listings" dtv- , cbCaptions = getMetaBool "codeBlockCaptions" dtv- , autoSecLab = getMetaBool "autoSectionLabels" dtv- , figPrefix = tryCapitalizeM (flip (getMetaList toInlines) dtv) "figPrefix"- , eqnPrefix = tryCapitalizeM (flip (getMetaList toInlines) dtv) "eqnPrefix"- , tblPrefix = tryCapitalizeM (flip (getMetaList toInlines) dtv) "tblPrefix"- , lstPrefix = tryCapitalizeM (flip (getMetaList toInlines) dtv) "lstPrefix"- , secPrefix = tryCapitalizeM (flip (getMetaList toInlines) dtv) "secPrefix"- , chapDelim = getMetaInlines "chapDelim" dtv- , rangeDelim = getMetaInlines "rangeDelim" dtv- , lofTitle = getMetaBlock "lofTitle" dtv- , lotTitle = getMetaBlock "lotTitle" dtv- , lolTitle = getMetaBlock "lolTitle" dtv- , outFormat = fmt- , figureTemplate = makeTemplate dtv $ getMetaInlines "figureTemplate" dtv- , tableTemplate = makeTemplate dtv $ getMetaInlines "tableTemplate" dtv- , listingTemplate = makeTemplate dtv $ getMetaInlines "listingTemplate" dtv- }--tryCapitalizeM :: (Functor m, Monad m, Walkable Inline a, Default a, Eq a) =>- (String -> m a) -> String -> Bool -> m a-tryCapitalizeM f varname capitalize- | capitalize = do- res <- f (capitalizeFirst varname)- case res of- xs | xs == def -> f varname >>= walkM capStrFst- | otherwise -> return xs- | otherwise = f varname- where- capStrFst (Str s) = return $ Str $ capitalizeFirst s- capStrFst x = return x---- tryCapitalize :: (Walkable Inline a, Default a, Eq a) =>--- (String -> a) -> String -> Bool -> a--- tryCapitalize = ((runIdentity .) .) . tryCapitalizeM . (return .)
− src/Text/Pandoc/CrossRef/Util/Settings.hs
@@ -1,41 +0,0 @@-{-# LANGUAGE CPP #-}-module Text.Pandoc.CrossRef.Util.Settings (getSettings, defaultMeta) where--import Text.Pandoc hiding (readMarkdown)-import Text.Pandoc.CrossRef.Util.Gap-import Text.Pandoc.Builder-import Control.Exception (handle,IOException)--import Text.Pandoc.CrossRef.Util.Settings.Gen-import Text.Pandoc.CrossRef.Util.Meta--getSettings :: Meta -> IO Meta-getSettings meta = do- let handler :: IOException -> IO String- handler _ = return []- yaml <- handle handler $ readFile (getMetaString "crossrefYaml" (meta <> defaultMeta))- let Pandoc dtve _ = readMarkdown def ("---\n" ++ yaml ++ "\n---")- return $ meta <> dtve <> defaultMeta--defaultMeta :: Meta-defaultMeta =- figureTitle (str "Figure")- <> tableTitle (str "Table")- <> listingTitle (str "Listing")- <> titleDelim (str ":")- <> chapDelim (str ".")- <> rangeDelim (str "-")- <> figPrefix ([str "fig.", str "figs."])- <> eqnPrefix ([str "eq." , str "eqns."])- <> tblPrefix ([str "tbl.", str "tbls."])- <> lstPrefix ([str "lst.", str "lsts."])- <> secPrefix ([str "sec.", str "secs."])- <> lofTitle (header 1 $ text "List of Figures")- <> lotTitle (header 1 $ text "List of Tables")- <> lolTitle (header 1 $ text "List of Listings")- <> figureTemplate (var "figureTitle" <> space <> var "i" <> var "titleDelim" <> space <> var "t")- <> tableTemplate (var "tableTitle" <> space <> var "i" <> var "titleDelim" <> space <> var "t")- <> listingTemplate (var "listingTitle" <> space <> var "i" <> var "titleDelim" <> space <> var "t")- <> crossrefYaml (MetaString "pandoc-crossref.yaml")- <> chaptersDepth (MetaString "1")- where var = displayMath
− src/Text/Pandoc/CrossRef/Util/Settings/Gen.hs
@@ -1,61 +0,0 @@-module Text.Pandoc.CrossRef.Util.Settings.Gen where--import Text.Pandoc.CrossRef.Util.Settings.Template-import Text.Pandoc.Builder--figureTitle :: ToMetaValue a => a -> Meta-figureTitle = template "figureTitle"--tableTitle :: ToMetaValue a => a -> Meta-tableTitle = template "tableTitle"--listingTitle :: ToMetaValue a => a -> Meta-listingTitle = template "listingTitle"--titleDelim :: ToMetaValue a => a -> Meta-titleDelim = template "titleDelim"--chapDelim :: ToMetaValue a => a -> Meta-chapDelim = template "chapDelim"--rangeDelim :: ToMetaValue a => a -> Meta-rangeDelim = template "rangeDelim"--figPrefix :: ToMetaValue a => a -> Meta-figPrefix = template "figPrefix"--eqnPrefix :: ToMetaValue a => a -> Meta-eqnPrefix = template "eqnPrefix"--tblPrefix :: ToMetaValue a => a -> Meta-tblPrefix = template "tblPrefix"--lstPrefix :: ToMetaValue a => a -> Meta-lstPrefix = template "lstPrefix"--secPrefix :: ToMetaValue a => a -> Meta-secPrefix = template "secPrefix"--lofTitle :: ToMetaValue a => a -> Meta-lofTitle = template "lofTitle"--lotTitle :: ToMetaValue a => a -> Meta-lotTitle = template "lotTitle"--lolTitle :: ToMetaValue a => a -> Meta-lolTitle = template "lolTitle"--figureTemplate :: ToMetaValue a => a -> Meta-figureTemplate = template "figureTemplate"--tableTemplate :: ToMetaValue a => a -> Meta-tableTemplate = template "tableTemplate"--listingTemplate :: ToMetaValue a => a -> Meta-listingTemplate = template "listingTemplate"--crossrefYaml :: ToMetaValue a => a -> Meta-crossrefYaml = template "crossrefYaml"--chaptersDepth :: ToMetaValue a => a -> Meta-chaptersDepth = template "chaptersDepth"
− src/Text/Pandoc/CrossRef/Util/Settings/Template.hs
@@ -1,8 +0,0 @@-module Text.Pandoc.CrossRef.Util.Settings.Template where--import Text.Pandoc.Definition-import Text.Pandoc.Builder-import qualified Data.Map as M--template :: ToMetaValue a => String -> a -> Meta-template name = Meta . M.singleton name . toMetaValue
− src/Text/Pandoc/CrossRef/Util/Template.hs
@@ -1,26 +0,0 @@-module Text.Pandoc.CrossRef.Util.Template (Template,makeTemplate,applyTemplate) where--import Text.Pandoc.Definition-import Text.Pandoc.Generic-import Text.Pandoc.Shared (normalizeInlines)-import Data.Maybe-import Text.Pandoc.CrossRef.Util.Meta--type VarFunc = String -> Maybe MetaValue-newtype Template = Template (VarFunc -> [Inline])--makeTemplate :: Meta -> [Inline] -> Template-makeTemplate dtv = Template . flip scan . scan (`lookupMeta` dtv)- where- scan = bottomUp . go- go vf (x@(Math DisplayMath var):xs) = replaceVar (vf var) [x] ++ xs- go _ x = x- replaceVar val def' = fromMaybe def' $ val >>= toInlines--applyTemplate :: [Inline] -> [Inline] -> Template -> [Inline]-applyTemplate i t (Template g) =- normalizeInlines $ g internalVars- where- internalVars "i" = Just $ MetaInlines i- internalVars "t" = Just $ MetaInlines t- internalVars _ = Nothing
− src/Text/Pandoc/CrossRef/Util/Util.hs
@@ -1,26 +0,0 @@-module Text.Pandoc.CrossRef.Util.Util where--import Text.Pandoc.CrossRef.References.Types-import Text.Pandoc.Definition-import Data.Char (toUpper, toLower, isUpper)-import Data.List (intercalate)-import Data.Maybe (fromMaybe)--isFormat :: String -> Maybe Format -> Bool-isFormat fmt (Just (Format f)) = takeWhile (`notElem` "+-") f == fmt-isFormat _ Nothing = False--capitalizeFirst :: String -> String-capitalizeFirst (x:xs) = toUpper x : xs-capitalizeFirst [] = []--uncapitalizeFirst :: String -> String-uncapitalizeFirst (x:xs) = toLower x : xs-uncapitalizeFirst [] = []--isFirstUpper :: String -> Bool-isFirstUpper (x:_) = isUpper x-isFirstUpper [] = False--chapPrefix :: [Inline] -> Index -> [Inline]-chapPrefix delim index = intercalate delim (map (return . Str . uncurry (fromMaybe . show)) index)
+ src/pandoc-crossref.hs view
@@ -0,0 +1,14 @@+import Text.Pandoc+import Text.Pandoc.JSON++import Text.Pandoc.CrossRef++main :: IO ()+main = toJSONFilter go+ where+ go fmt p@(Pandoc meta _) = runCrossRefIO meta fmt action p+ where+ action (Pandoc _ bs) = do+ meta' <- crossRefMeta+ bs' <- crossRefBlocks bs+ return $ Pandoc meta' bs'