module Language.LaTeX.Slicer (marknote, mark, marker, (^$), slice) where import Data.Monoid import Control.Monad.Writer import Language.LaTeX.Types import Language.LaTeX.Builder.MonoidUtils import qualified Language.LaTeX.Builder.Internal as BI import qualified Data.Generics.Uniplate.Data as U marknote :: ParItm marknote = ParNote (MkKey "slicemark") BI.nilNote ΓΈ mark :: ParItemW mark = tell $ return marknote marker :: Writer ParItem a -> Writer ParItem a marker f = do mark x <- f mark return x infixr 0 ^$ (^$) :: (b -> Writer ParItem a) -> b -> Writer ParItem a f ^$ x = marker (f x) slice :: Functor f => f ParItm -> f ParItm slice = fmap $ mconcat . mconcat . comb [maySlice1, maySlice2, id] . uncatParItm where notMark = (/= marknote) -- Is there a mark in a subterm? isMarked = any (== marknote) . U.universe -- slicing strategy (1): drop until the mark, -- drop the mark, -- take until the next mark maySlice1 = takeWhile notMark . drop 1 . dropWhile notMark -- slicing strategy (2): -- keep only items which contains a mark as a subterm maySlice2 = filter isMarked -- Combine multiple strategies: -- takes the result of the first succeeding strategy comb fs xs = take 1 . filter (not . null) . map ($xs) $ fs