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.Write.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.Monoid (Monoid(..))
16 import Data.Ord (Ord(..))
17 import Data.Semigroup (Semigroup(..))
18 import Data.Sequence (ViewL(..))
19 import Data.String (String)
20 import Data.Text (Text)
21 import Prelude (Num(..), undefined)
22 import Text.Show (Show(..))
23 import qualified Control.Monad.Trans.State as S
24 import qualified Data.List as L
25 import qualified Data.Sequence as Seq
26 import qualified Data.Text as Text
27 import qualified Data.Text.Lazy as TL
29 import Language.TCT.Tree
30 import Language.TCT.Token
31 import Language.TCT.Elem hiding (trac,dbg)
33 import Debug.Trace (trace)
34 trac :: String -> a -> a
37 dbg :: Show a => String -> a -> a
38 dbg m x = trac (m <> ": " <> show x) x
43 -- * Type 'Config_Text'
46 { config_text_escape :: Bool
49 config_text :: Config_Text
52 { config_text_escape = True
55 text :: Config_Text -> Trees (Cell Key) (Cell Tokens) -> TL.Text
56 text cfg tct = foldMap (t_TreeCell cfg) (treePosLastCell tct)
58 treeRackUpLeft :: Tree (Cell k) (Cell a) -> Tree (Cell k) (Cell a)
59 treeRackUpLeft t = go t
64 (linePos pos - l0 + 1)
65 (columnPos pos - c0 + 1)
66 go :: Tree (Cell k) (Cell a) -> Tree (Cell k) (Cell a)
67 go (Tree0 (Cell pos posEnd c)) =
68 Tree0 $ Cell (rackUpLeft pos) (rackUpLeft posEnd) c
69 go (TreeN (Cell pos posEnd c) ts) =
71 (Cell (rackUpLeft pos) (rackUpLeft posEnd) c)
74 treePosLastCell :: Trees (Cell k) (Cell a) -> Trees (Pos,Cell k) (Pos,Cell a)
75 treePosLastCell t = S.evalState (go`mapM`t) (Pos 1 1)
77 go :: Tree (Cell k) (Cell a) ->
78 S.State Pos (Tree (Pos, Cell k) (Pos, Cell a))
81 S.put $ posEndCell cell
82 return $ Tree0 (lastPos,cell)
83 go (TreeN cell ts) = do
85 S.put $ posEndCell cell
87 return $ TreeN (lastPos,cell) ts'
89 t_Value :: Text -> TL.Text
92 t_TreeCell :: Config_Text -> Tree (Pos,Cell Key) (Pos,Cell Tokens) -> TL.Text
93 t_TreeCell cfg (TreeN c@(_, unCell -> KeySection lvl) ts) =
95 TL.replicate (int64 lvl) "#" <> " " <>
97 Tree0 (_,Cell posTitle _ title) :< _ -> t_IndentToken cfg posTitle title
99 foldMap (t_TreeCell cfg) (case Seq.viewl ts of {Tree0{} :< ts' -> ts'; _ -> ts})
100 t_TreeCell cfg (Tree0 c@(_,cell)) =
103 t_TreeCell cfg (TreeN c@(_,cell) cs) =
105 t_CellKey cfg cell cs
107 t_IndentCell :: (Pos,Cell a) -> TL.Text
108 t_IndentCell (Pos lineLast colLast,posCell -> Pos line col)
110 TL.replicate (int64 $ line - (lineLast+1)) "\n" <>
111 TL.replicate (int64 $ col - 1) " "
113 && colLast <= col = TL.replicate (int64 $ col - colLast) " "
114 | otherwise = undefined
116 t_CellKey :: Config_Text -> Cell Key -> Trees (Pos,Cell Key) (Pos,Cell Tokens) -> TL.Text
117 t_CellKey cfg (Cell _pos _posEnd key) cells = do
119 KeyColon n wh -> t_Key n wh ":"
120 KeyGreat n wh -> t_Key n wh ">"
121 KeyEqual n wh -> t_Key n wh "="
122 KeyBar n wh -> t_Key n wh "|"
123 KeyDash -> "- " <> foldMap (t_TreeCell cfg) cells
124 KeyLower name attrs ->
125 "<" <> tl name <> t_Attrs attrs <>
126 foldMap (t_TreeCell cfg) cells
127 KeySection{} -> undefined
129 t_Key :: Text -> White -> TL.Text -> TL.Text
130 t_Key name wh mark = tl name <> tl wh <> mark <> foldMap (t_TreeCell cfg) cells
132 t_CellToken :: Config_Text -> Cell Tokens -> TL.Text
133 t_CellToken cfg (Cell pos _posEnd tok) =
134 t_IndentToken cfg pos tok
136 t_IndentToken :: Config_Text -> Pos -> Tokens -> TL.Text
137 t_IndentToken cfg pos toks = goTokens toks `S.evalState` linePos pos
139 indent = TL.replicate (int64 $ columnPos pos - 1) " "
140 go :: Token -> S.State Int TL.Text
141 go (TokenPlain txt) = do
143 let lines = TL.splitOn "\n" txt
144 S.put (lnum - 1 + L.length lines)
148 (l0:ls) -> l0 <> mconcat ((\l -> "\n"<>indent<>l)<$>ls)
149 go (TokenTag v) = return $ "#"<>tl v
152 if config_text_escape cfg
153 then tl $ Text.pack ['\\',c]
155 go (TokenLink lnk) = return $ tl lnk
156 go (TokenPair grp ts) = do
159 where (o,c) = pairBorders grp ts
160 goTokens :: Tokens -> S.State Int TL.Text
161 goTokens (Tokens ts) = do
163 return $ foldr (<>) mempty ts'
165 t_Attrs :: Attrs -> TL.Text
166 t_Attrs = foldMap t_Attr
168 t_Attr :: (Text,Attr) -> TL.Text
169 t_Attr (attr_white,Attr{..}) =
179 t_Token :: Token -> TL.Text
180 t_Token (TokenPlain txt) = txt
181 t_Token (TokenTag v) = "#"<>tl v
182 t_Token (TokenEscape c) = TL.singleton c -- tl $ Text.pack ['\\',c]
183 t_Token (TokenLink lnk) = tl lnk
184 t_Token (TokenPair grp t) = o<>t_Tokens t<>c
185 where (o,c) = pairBorders grp t
187 t_Tokens :: Tokens -> TL.Text
188 t_Tokens (Tokens ts) = foldMap t_Token ts