module Text.LaTeX.Base.Warnings (
Warning (..)
, TeXCheck
, check
, checkFromFunction
, checkLabels
, checkClass
, checkDoc
, checkAll
) where
import Text.LaTeX.Base.Syntax
import Control.Monad.Trans.State
import Data.Text
import Data.Maybe
import Control.Arrow
#if !MIN_VERSION_base(4,8,0)
import Data.Monoid
#endif
data Warning =
UnusedLabel Text
| UndefinedLabel Text
| NoClassSelected
| NoDocumentInserted
| CustomWarning Text
deriving (Eq,Show)
newtype TeXCheck = TC { check :: LaTeX -> [Warning]
}
checkFromFunction :: (LaTeX -> [Warning]) -> TeXCheck
checkFromFunction = TC
instance Monoid TeXCheck where
mempty = TC $ const []
mappend (TC tc1) (TC tc2) = TC $ uncurry mappend . (tc1 &&& tc2)
checkAll :: TeXCheck
checkAll = mconcat [ checkLabels , checkClass , checkDoc ]
type BoolSt = State Bool
checkClass :: TeXCheck
checkClass = TC $ \l -> if execState (classcheck l) False then [] else [NoClassSelected]
classcheck :: LaTeX -> BoolSt ()
classcheck (TeXComm c _) =
case c of
"documentclass" -> put True
_ -> return ()
classcheck (TeXBraces l) = classcheck l
classcheck (TeXSeq l1 l2) = classcheck l1 >> classcheck l2
classcheck _ = return ()
checkDoc :: TeXCheck
checkDoc = TC $ \l -> if execState (doccheck l) False then [] else [NoDocumentInserted]
doccheck :: LaTeX -> BoolSt ()
doccheck (TeXEnv n _ _) =
case n of
"document" -> put True
_ -> return ()
doccheck (TeXBraces l) = doccheck l
doccheck (TeXSeq l1 l2) = doccheck l1 >> doccheck l2
doccheck _ = return ()
data LabWarn =
RefNoLabel Text
| LabelNoRef Text
| LabelRef Text
labWarnToWarning :: LabWarn -> Maybe Warning
labWarnToWarning (RefNoLabel n) = Just $ UndefinedLabel n
labWarnToWarning (LabelNoRef n) = Just $ UnusedLabel n
labWarnToWarning _ = Nothing
type LabSt = State [LabWarn]
checkLabels :: TeXCheck
checkLabels = TC $ \l -> catMaybes . fmap labWarnToWarning $ execState (labcheck l) []
labcheck :: LaTeX -> LabSt ()
labcheck (TeXComm c [FixArg (TeXRaw n)]) =
case c of
"label" -> newlab n
"ref" -> newref n
"pageref" -> newref n
_ -> return ()
labcheck (TeXEnv _ _ l) = labcheck l
labcheck (TeXMath _ l) = labcheck l
labcheck (TeXBraces l) = labcheck l
labcheck (TeXSeq l1 l2) = labcheck l1 >> labcheck l2
labcheck _ = return ()
newlab :: Text -> LabSt ()
newlab t = do
st <- get
let addLab :: Text -> [LabWarn] -> [LabWarn]
addLab n [] = [LabelNoRef n]
addLab n l@(x:xs) = let ys = x : addLab n xs in
case x of
RefNoLabel m -> if n == m then LabelRef n : xs
else ys
LabelNoRef m -> if n == m then l
else ys
LabelRef m -> if n == m then l
else ys
put $ addLab t st
newref :: Text -> LabSt ()
newref t = do
st <- get
let addRef :: Text -> [LabWarn] -> [LabWarn]
addRef n [] = [RefNoLabel n]
addRef n l@(x:xs) = let ys = x : addRef n xs in
case x of
RefNoLabel m -> if n == m then l
else ys
LabelNoRef m -> if n == m then LabelRef n : xs
else ys
LabelRef m -> if n == m then l
else ys
put $ addRef t st