Use Tree Zipper for rendering DTC ToF in HTML5.
[doclang.git] / Language / TCT / Token.hs
index 69047a4b9d0bcb105ef4f8045554cd800e36bcfc..c7635c47ddbf6767f4db16667014dfd5faf1b998 100644 (file)
 {-# LANGUAGE OverloadedStrings #-}
 {-# LANGUAGE RecordWildCards #-}
+{-# LANGUAGE TypeFamilies #-}
 module Language.TCT.Token where
 
-import Control.Monad (Monad(..))
-import Data.Bool (Bool(..))
+import Data.Bool
 import Data.Char (Char)
 import Data.Eq (Eq(..))
-import Data.Monoid (Monoid(..))
 import Data.Function ((.))
-import Data.Foldable (Foldable(..))
+import Data.Foldable (foldMap, foldr)
+import Data.Maybe (Maybe(..))
 import Data.Semigroup (Semigroup(..))
-import Data.Sequence (Seq, ViewL(..), ViewR(..), (<|), (|>))
+import Data.Sequence (Seq)
+import Data.Ord (Ord)
 import Data.Text (Text)
 import Data.Text.Buildable (Buildable(..))
+import Data.Text.Lazy.Builder (Builder)
+import GHC.Exts (IsList(..))
 import Text.Show (Show(..))
+import qualified Data.Char as Char
 import qualified Data.Sequence as Seq
 import qualified Data.Text as Text
 
+import Language.TCT.Cell
 import Language.TCT.Elem
 
 -- * Type 'Token'
 data Token
- =   Tokens      (Seq Token)
- |   TokenPlain  Text
- |   TokenPair   Pair Token
- |   TokenTag    Tag
- |   TokenEscape Char
- |   TokenLink   Text
- deriving (Eq, Show)
-instance Semigroup Token where
-       TokenPlain (Text.null -> True) <> y = y
-       x <> TokenPlain (Text.null -> True) = x
-       
-       TokenPlain x <> TokenPlain y                               = TokenPlain (x<>y)
-       Tokens (Seq.viewr -> xs:>x@TokenPlain{}) <> y@TokenPlain{} = Tokens (xs|>(x<>y))
-       x@TokenPlain{} <> Tokens (Seq.viewl -> y@TokenPlain{}:<ys) = Tokens ((x<>y)<|ys)
-       
+ =   TokenPlain  !Text
+ |   TokenPair   !Pair !Tokens
+ |   TokenTag    !Tag
+ |   TokenEscape !Char
+ |   TokenLink   !Text
+ deriving (Eq, Ord, Show)
+
+instance Buildable Token where
+       build (TokenPlain t)   = build t
+       build (TokenTag t)     = "#"<>build t
+       build (TokenLink lnk)  = build lnk
+       build (TokenEscape c)  = "\\"<>build c
+       build (TokenPair p ts) = build c<>buildTokens ts<>build o
+               where (o,c) = pairBorders p ts
+
+buildTokens :: Tokens -> Builder
+buildTokens = foldr (\a -> (<> build (unCell a))) ""
+
+-- * Type 'Tokens'
+type Tokens = Seq (Cell Token)
+
+{-
+instance Semigroup Tokens where
+       Tokens (Seq.viewr -> xs:>TokenPlain x) <>
+        Tokens (Seq.viewl -> TokenPlain y:<ys) =
+               Tokens (xs<>(TokenPlain (x<>y)<|ys))
        Tokens x <> Tokens y = Tokens (x<>y)
-       Tokens x <> y        = Tokens (x|>y)
-       x <> Tokens y        = Tokens (x<|y)
-       
-       x <> y = Tokens (Seq.fromList [x,y])
-instance Monoid Token where
-       mempty  = TokenPlain mempty
+instance Monoid Tokens where
+       mempty  = Tokens mempty
        mappend = (<>)
-instance Buildable Token where
-       build (TokenPlain t)  = build t
-       build (Tokens ms)     = foldr (\a b -> b <> build a) "" ms
-       build (TokenTag t)    = "#"<>build t
-       build (TokenLink lnk) = build lnk
-       build (TokenEscape c) = "\\"<>build c
-       build (TokenPair g m) =
-               let (o,c) = pairBorders g m in
-               build c<>build m<>build o
-
--- | Build a 'Token' from many.
-tokens :: [Token] -> Token
-tokens = Tokens . Seq.fromList
-
--- | Remove 'Tokens' in given 'Token'
--- by flattening all 'Token's in a single 'Seq'.
-unTokens :: Token -> Seq Token
-unTokens (Tokens ts) = ts >>= unTokens
-unTokens tok = Seq.singleton tok
+instance Buildable Tokens where
+       build (Tokens ts) = foldr (\a -> (<> build a)) "" ts
+instance IsList Tokens where
+       type Item Tokens = Token
+       fromList = Tokens . fromList
+       toList (Tokens ts) = toList ts
+
+unTokens :: Tokens -> Seq Token
+unTokens (Tokens ts) = ts
+-}
+
+-- | Build 'Tokens' from many 'Token's.
+tokens :: [Cell Token] -> Tokens
+tokens = Seq.fromList
+
+-- | Build 'Tokens' from one 'Token'.
+tokens1 :: Cell Token -> Tokens
+tokens1 = Seq.singleton
+
+tokensPlainEmpty :: Tokens
+tokensPlainEmpty = Seq.singleton (cell1 (TokenPlain ""))
+
+isTokenWhite :: Token -> Bool
+isTokenWhite (TokenPlain t) = Text.all Char.isSpace t
+isTokenWhite _              = False
+
+unTokenElem :: Tokens -> Maybe (Cell (Elem,Attrs,Tokens))
+unTokenElem ts =
+       case toList (Seq.dropWhileR (isTokenWhite . unCell) ts) of
+        [Cell bp ep (TokenPair (PairElem e as) toks)] -> Just (Cell bp ep (e,as,toks))
+        _ -> Nothing
+
+isTokenElem :: Tokens -> Bool
+isTokenElem ts =
+       case toList (Seq.dropWhileR (isTokenWhite . unCell) ts) of
+        [unCell -> TokenPair PairElem{} _] -> True
+        _ -> False
 
 -- ** Type 'Tag'
 type Tag = Text
 
 -- ** Type 'Pair'
 data Pair
- =   PairHash            -- ^ @#value#@
- |   PairElem Elem Attrs -- ^ @<elem n0=v0 n1=v1>value</elem>@
- |   PairStar            -- ^ @*value*@
- |   PairSlash           -- ^ @/value/@
- |   PairUnderscore      -- ^ @_value_@
- |   PairDash            -- ^ @-value-@
- |   PairBackquote       -- ^ @`value`@
- |   PairSinglequote     -- ^ @'value'@
- |   PairDoublequote     -- ^ @"value"@
- |   PairFrenchquote     -- ^ @«value»@
- |   PairParen           -- ^ @(value)@
- |   PairBrace           -- ^ @{value}@
- |   PairBracket         -- ^ @[value]@
- deriving (Eq, Show)
-
-pairBorders :: Pair -> Token -> (Text,Text)
-pairBorders g m =
-       case g of
+ =   PairHash              -- ^ @#value#@
+ |   PairElem !Elem !Attrs -- ^ @<elem n0=v0 n1=v1>value</elem>@
+ |   PairStar              -- ^ @*value*@
+ |   PairSlash             -- ^ @/value/@
+ |   PairUnderscore        -- ^ @_value_@
+ |   PairDash              -- ^ @-value-@
+ |   PairBackquote         -- ^ @`value`@
+ |   PairSinglequote       -- ^ @'value'@
+ |   PairDoublequote       -- ^ @"value"@
+ |   PairFrenchquote       -- ^ @«value»@
+ |   PairParen             -- ^ @(value)@
+ |   PairBrace             -- ^ @{value}@
+ |   PairBracket           -- ^ @[value]@
+ deriving (Eq, Ord, Show)
+
+pairBorders :: Pair -> Tokens -> (Text,Text)
+pairBorders p ts =
+       case p of
         PairElem e attrs ->
-               case m of
-                Tokens ms | Seq.null ms -> ("<"<>e<>foldMap f attrs<>"/>","")
-                _ -> ("<"<>e<>foldMap f attrs<>">","</"<>e<>">")
+               if Seq.null ts
+               then ("<"<>e<>foldMap f attrs<>"/>","")
+               else ("<"<>e<>foldMap f attrs<>">","</"<>e<>">")
                where f (attr_white,Attr{..}) =
                        attr_white <>
                        attr_name  <>