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.Int (Int64)
16 import Data.Monoid (Monoid(..))
17 import Data.Ord (Ord(..))
18 import Data.Semigroup (Semigroup(..))
19 import Data.Sequence (ViewL(..), ViewR(..))
20 import Data.String (String)
21 import Data.Text (Text)
22 import Data.TreeSeq.Strict (Tree(..),Trees)
23 import Prelude (Num(..), undefined, Integral(..))
24 import Text.Show (Show(..))
25 import qualified Control.Monad.Trans.State as S
26 import qualified Data.List as L
27 import qualified Data.Sequence as Seq
28 import qualified Data.Text as Text
29 import qualified Data.Text.Lazy as TL
31 import Language.TCT.Tree
32 import Language.TCT.Cell
33 import Language.TCT.Token
34 import Language.TCT.Elem hiding (trac,dbg)
36 import Debug.Trace (trace)
37 trac :: String -> a -> a
40 dbg :: Show a => String -> a -> a
41 dbg m x = trac (m <> ": " <> show x) x
46 -- * Type 'Config_Text'
49 { config_text_escape :: Bool
52 config_text :: Config_Text
55 { config_text_escape = True
58 text :: Config_Text -> Trees (Cell Key) Tokens -> TL.Text
59 text cfg = t_TreesCell cfg . treePosLastCell
61 treeRackUpLeft :: Tree (Cell k) (Cell a) -> Tree (Cell k) (Cell a)
62 treeRackUpLeft t = go t
67 (linePos pos - l0 + 1)
68 (columnPos pos - c0 + 1)
69 go :: Tree (Cell k) (Cell a) -> Tree (Cell k) (Cell a)
70 go (Tree0 (Cell pos posEnd c)) =
71 Tree0 $ Cell (rackUpLeft pos) (rackUpLeft posEnd) c
72 go (TreeN (Cell pos posEnd c) ts) =
74 (Cell (rackUpLeft pos) (rackUpLeft posEnd) c)
78 Trees (Cell k) Tokens ->
79 Trees (Pos,Cell k) (Pos,Tokens)
80 treePosLastCell t = S.evalState (go`mapM`t) (Pos 1 1)
82 go :: Tree (Cell k) Tokens ->
83 S.State Pos (Tree (Pos,Cell k) (Pos,Tokens))
88 return $ Tree0 (lastPos,ts)
90 S.put $ posEndCell cell
91 return $ Tree0 (lastPos,ts)
92 go (TreeN cell ts) = do
94 S.put $ posEndCell cell
96 return $ TreeN (lastPos,cell) ts'
98 int64 :: Integral i => i -> Int64
99 int64 = fromInteger . toInteger
103 Tree (Pos,Cell Key) (Pos,Tokens) ->
105 t_TreeCell cfg (TreeN (posEnd, Cell pos _ (KeySection lvl)) ts) =
106 t_IndentCell (posEnd,pos) <>
107 TL.replicate (int64 lvl) "#" <> " " <>
108 (case Seq.viewl ts of
109 Tree0 (_,title) :< _ ->
110 t_IndentToken cfg title
113 (case Seq.viewl ts of
114 Tree0{} :< ts' -> ts'
116 t_TreeCell cfg (Tree0 (posEnd,toks)) =
117 case Seq.viewl toks of
118 EmptyL -> t_IndentToken cfg toks
119 t0:<_ -> t_IndentCell (posEnd,posCell t0) <> t_IndentToken cfg toks
120 t_TreeCell cfg (TreeN (posEnd,cell@(Cell pos _ _)) cs) =
121 t_IndentCell (posEnd,pos) <>
122 t_CellKey cfg cell cs
124 t_IndentCell :: (Pos,Pos) -> TL.Text
125 t_IndentCell (Pos lineLast colLast,Pos line col)
127 TL.replicate (int64 $ line - (lineLast+1)) "\n" <>
128 TL.replicate (int64 $ col - 1) " "
129 | lineLast == line && colLast <= col =
130 TL.replicate (int64 $ col - colLast) " "
131 | otherwise = undefined
136 Trees (Pos,Cell Key) (Pos,Tokens) ->
138 t_CellKey cfg (Cell _pos _posEnd key) cells = do
140 KeyColon n wh -> t_Key n wh ":"
141 KeyGreat n wh -> t_Key n wh ">"
142 KeyEqual n wh -> t_Key n wh "="
143 KeyBar n wh -> t_Key n wh "|"
144 KeyDash -> t_Key "" "" "- "
145 KeyDashDash -> t_Key "" "" "-- "
146 KeyLower name attrs ->
147 "<" <> tl name <> t_Attrs attrs <>
148 t_TreesCell cfg cells
149 KeySection{} -> undefined
152 t_TreesCell cfg cells
154 t_Key :: Text -> White -> TL.Text -> TL.Text
156 tl name <> tl wh <> mark <>
157 t_TreesCell cfg cells
161 Trees (Pos,Cell Key) (Pos,Tokens) ->
163 t_TreesCell cfg = foldMap (t_TreeCell cfg)
165 t_IndentToken :: Config_Text -> Tokens -> TL.Text
166 t_IndentToken _cfg (Seq.viewl -> EmptyL) = ""
167 t_IndentToken cfg toks@(Seq.viewl -> Cell pos _ _ :< _) =
168 goTokens toks `S.evalState` linePos pos
170 indent = TL.replicate (int64 $ columnPos pos - 1) " "
171 go :: Cell Token -> S.State Int TL.Text
176 let lines = Text.splitOn "\n" txt
177 S.put (lnum - 1 + L.length lines)
181 (l0:ls) -> tl l0 <> mconcat ((\l -> "\n"<>indent<>tl l)<$>ls)
182 TokenTag v -> return $ "#"<>tl v
185 if config_text_escape cfg
186 then tl $ Text.pack ['\\',c]
188 TokenLink lnk -> return $ tl lnk
189 TokenPair grp ts -> do
191 return $ tl o<>ts'<>tl c
192 where (o,c) = pairBorders grp ts
193 goTokens :: Tokens -> S.State Int TL.Text
196 return $ foldr (<>) mempty ts'
198 t_Attrs :: Attrs -> TL.Text
199 t_Attrs = foldMap t_Attr
201 t_Attr :: (Text,Attr) -> TL.Text
202 t_Attr (attr_white,Attr{..}) =
211 t_Token :: Token -> TL.Text
212 t_Token (TokenPlain txt) = tl txt
213 t_Token (TokenTag v) = "#"<>tl v
214 t_Token (TokenEscape c) = TL.singleton c -- tl $ Text.pack ['\\',c]
215 t_Token (TokenLink lnk) = tl lnk
216 t_Token (TokenPair grp t) = tl o<>t_Tokens t<>tl c
217 where (o,c) = pairBorders grp t
219 t_Tokens :: Tokens -> TL.Text
220 t_Tokens ts = foldMap (t_Token . unCell) ts