1 {-# LANGUAGE OverloadedStrings #-}
2 {-# LANGUAGE RecordWildCards #-}
3 {-# LANGUAGE ViewPatterns #-}
4 {-# OPTIONS_GHC -fno-warn-orphans #-}
5 -- | Render a TCT file in plain Text.
6 module Language.TCT.Text where
8 import Control.Monad (Monad(..), mapM)
10 import Data.Eq (Eq(..))
11 import Data.Foldable (Foldable(..))
12 import Data.Function (($), (.))
13 import Data.Functor ((<$>))
15 import Data.Int (Int64)
16 import Data.Monoid (Monoid(..))
17 import Data.Ord (Ord(..))
18 import Data.Semigroup (Semigroup(..))
19 import Data.Sequence (ViewL(..))
20 import Data.String (String)
21 import Data.Text (Text)
22 import Prelude (Num(..), undefined, Integral(..))
23 import Text.Show (Show(..))
24 import qualified Control.Monad.Trans.State as S
25 import qualified Data.List as L
26 import qualified Data.Sequence as Seq
27 import qualified Data.Text as Text
28 import qualified Data.Text.Lazy as TL
30 import Language.TCT.Tree
31 import Language.TCT.Token
32 import Language.TCT.Elem hiding (trac,dbg)
34 import Debug.Trace (trace)
35 trac :: String -> a -> a
38 dbg :: Show a => String -> a -> a
39 dbg m x = trac (m <> ": " <> show x) x
44 text :: Trees (Cell Key) (Cell Token) -> TL.Text
45 text tct = foldMap t_TreeCell (treePosLastCell tct)
47 t_Value :: Text -> TL.Text
50 int64 :: Integral i => i -> Int64
51 int64 = fromInteger . toInteger
53 t_TreeCell :: Tree (Pos,Cell Key) (Pos,Cell Token) -> TL.Text
54 t_TreeCell (TreeN c@(_, unCell -> KeySection lvl) ts) =
56 TL.replicate (int64 lvl) "#" <> " " <>
58 Tree0 (_,Cell posTitle _ title) :< _ -> t_IndentToken posTitle title
60 foldMap t_TreeCell (case Seq.viewl ts of {Tree0{} :< ts' -> ts'; _ -> ts})
61 t_TreeCell (Tree0 c@(_,cell)) =
64 t_TreeCell (TreeN c@(_,cell) cs) =
68 t_IndentCell :: (Pos,Cell a) -> TL.Text
69 t_IndentCell ((lineLast,colLast),posCell -> (line,col))
71 TL.replicate (int64 $ line - (lineLast+1)) "\n" <>
72 TL.replicate (int64 $ col - 1) " "
74 && colLast <= col = TL.replicate (int64 $ col - colLast) " "
75 | otherwise = undefined
77 t_CellKey :: Cell Key -> Trees (Pos,Cell Key) (Pos,Cell Token) -> TL.Text
78 t_CellKey (Cell _pos _posEnd key) cells = do
80 KeyColon n wh -> t_Key n wh ":"
81 KeyGreat n wh -> t_Key n wh ">"
82 KeyEqual n wh -> t_Key n wh "="
83 KeyBar n wh -> t_Key n wh "|"
84 KeyDash -> "- " <> foldMap t_TreeCell cells
85 KeyLower name attrs ->
86 "<" <> tl name <> t_Attrs attrs <>
87 foldMap t_TreeCell cells
89 t_Key :: Text -> White -> TL.Text -> TL.Text
90 t_Key name wh mark = tl name <> tl wh <> mark <> foldMap t_TreeCell cells
92 t_CellToken :: Cell Token -> TL.Text
93 t_CellToken (Cell pos _posEnd tok) =
96 t_Token :: Token -> TL.Text
97 t_Token (TokenPlain txt) = tl txt
98 t_Token (TokenTag v) = "#"<>tl v
99 t_Token (TokenEscape c) = tl $ Text.pack ['\\',c]
100 t_Token (TokenLink lnk) = tl lnk
101 t_Token (TokenGroup grp t) = tl o<>t_Token t<>tl c
102 where (o,c) = groupBorders grp t
103 t_Token (Tokens ts) = foldMap t_Token ts
105 t_IndentToken :: Pos -> Token -> TL.Text
106 t_IndentToken pos tok = go tok `S.evalState` linePos pos
108 indent = TL.replicate (int64 $ columnPos pos - 1) " "
109 go :: Token -> S.State Int TL.Text
110 go (TokenPlain txt) = do
112 let lines = Text.splitOn "\n" txt
113 let lnums = tl : -- TODO: fmap
114 [ \line -> "\n"<>indent<>tl line
117 S.put (lin - 1 + L.length lines)
118 return $ mconcat $ L.zipWith ($) lnums lines
119 go (TokenTag v) = return $ "#"<>tl v
120 go (TokenEscape c) = return $ tl $ Text.pack ['\\',c]
121 go (TokenLink lnk) = return $ tl lnk
122 go (TokenGroup grp t) = do
124 return $ tl o<>t'<>tl c
125 where (o,c) = groupBorders grp t
128 return $ foldr (<>) mempty ts'
130 t_Attrs :: Attrs -> TL.Text
131 t_Attrs = foldMap t_Attr
133 t_Attr :: (Text,Attr) -> TL.Text
134 t_Attr (attr_white,Attr{..}) =
143 treePosLastCell :: Trees (Cell k) (Cell a) -> Trees (Pos,Cell k) (Pos,Cell a)
144 treePosLastCell t = S.evalState (go`mapM`t) (1,1)
146 go :: Tree (Cell k) (Cell a) ->
147 S.State (Int, Int) (Tree (Pos, Cell k) (Pos, Cell a))
150 S.put $ posEndCell cell
151 return $ Tree0 (lastPos,cell)
152 go (TreeN cell ts) = do
154 S.put $ posEndCell cell
156 return $ TreeN (lastPos,cell) ts'
159 t_TreeCell :: [Key] -> Tree (Cell Key) (Cell Token) -> TL.Text
160 t_TreeCell path (TreeN (unCell -> key@KeySection{}) ts) =
162 Tree0 (Cell _posTitle _ (TokenPlain title)) :< _ ->
163 D.section ! DA.name (attrValue title) $
165 Tree0 (Cell _posTitle _ title) :< _ ->
167 D.name $ d_Token (key:path) title
169 _ -> D.section d_content
171 d_content = forM_ (case Seq.viewl ts of {Tree0{} :< ts' -> ts'; _ -> ts}) $ d_TreeCell (key:path)
172 t_TreeCell path (Tree0 cell) = d_CellToken path cell
173 t_TreeCell path (TreeN cell ts) = d_CellKey path cell ts
175 t_CellKey :: [Key] -> Cell Key -> Trees (Cell Key) (Cell Token) -> TL.Text
176 t_CellKey path (Cell _pos _posEnd key) cells = do
178 KeyColon n _wh -> d_Key n
179 KeyGreat n _wh -> d_Key n
180 KeyEqual n _wh -> d_Key n
181 KeyBar n _wh -> d_Key n
182 KeyDash -> "- " <> foldMap (d_TreeCell (key:path)) cells
184 KeyLower name attrs -> do
185 B.Content $ "<"<>B.toMarkup name
187 forM_ cells $ d_TreeCell path
190 d_Key :: Text -> TL.Text
192 B.CustomParent (B.Text name) $
193 forM_ cells $ d_TreeCell (key:path)
195 t_CellToken :: [Key] -> Cell Token -> TL.Text
196 t_CellToken path (Cell _pos _posEnd tok) =
197 -- case L.find (\case KeySection{} -> True; _ -> False) $ dbg "d_CellToken: path:" path of
198 case dbg "d_CellToken: path" path of
201 TokenGroup GroupElem{} _t -> d_Token path tok
202 _ -> D.para $ d_Token path tok
203 _ -> d_Token path tok