module Data.Text.Markup
( Markup
, markupToList
, markupSet
, fromList
, fromText
, toText
, isEmpty
, (@@)
)
where
#if !MIN_VERSION_base(4,8,0)
import Control.Applicative ((<$>))
import Data.Monoid
#endif
import qualified Data.Semigroup as Sem
import Data.String (IsString(..))
import qualified Data.Text as T
data Markup a = Markup [(Char, a)]
deriving Show
instance Sem.Semigroup (Markup a) where
(Markup t1) <> (Markup t2) = Markup (t1 `mappend` t2)
instance Monoid (Markup a) where
mempty = Markup mempty
mappend = (Sem.<>)
instance (Monoid a) => IsString (Markup a) where
fromString = fromText . T.pack
(@@) :: T.Text -> a -> Markup a
t @@ val = Markup [(c, val) | c <- T.unpack t]
fromText :: (Monoid a) => T.Text -> Markup a
fromText = (@@ mempty)
toText :: (Eq a) => Markup a -> T.Text
toText = T.concat . (fst <$>) . concat . markupToList
isEmpty :: Markup a -> Bool
isEmpty (Markup ls) = null ls
markupSet :: (Eq a) => (Int, Int) -> a -> Markup a -> Markup a
markupSet (start, len) val m@(Markup l) = if start < 0 || start + len > length l
then m
else newM
where
newM = Markup $ theHead ++ theNewEntries ++ theTail
(theHead, theLongTail) = splitAt start l
(theOldEntries, theTail) = splitAt len theLongTail
theNewEntries = zip (fst <$> theOldEntries) (repeat val)
markupToList :: (Eq a) => Markup a -> [[(T.Text, a)]]
markupToList (Markup thePairs) = toList <$> toLines [] [] thePairs
where
toLines ls cur [] = ls ++ [cur]
toLines ls cur ((ch, val):rest)
| ch == '\n' = toLines (ls ++ [cur]) [] rest
| otherwise = toLines ls (cur ++ [(ch, val)]) rest
toList [] = []
toList ((ch, val):rest) = (T.pack $ ch : (fst <$> matching), val) : toList remaining
where
(matching, remaining) = break (\(_, v) -> v /= val) rest
fromList :: [(T.Text, a)] -> Markup a
fromList pairs = Markup $ concatMap (\(t, val) -> [(c, val) | c <- T.unpack t]) pairs