1 {-# LANGUAGE FlexibleInstances #-}
2 {-# LANGUAGE OverloadedStrings #-}
3 {-# LANGUAGE ViewPatterns #-}
4 {-# OPTIONS_GHC -fno-warn-orphans #-}
5 -- | Render a TCT file in plain Text.
6 module Language.TCT.Write.Plain where
8 import Control.Applicative (liftA2)
9 import Control.Monad (Monad(..), mapM)
11 import Data.Default.Class (Default(..))
12 import Data.Eq (Eq(..))
13 import Data.Foldable (Foldable(..))
14 import Data.Function (($), (.), id)
15 import Data.Functor ((<$>))
16 import Data.Int (Int,Int64)
17 import Data.Monoid (Monoid(..))
18 import Data.Ord (Ord(..))
19 import Data.Semigroup (Semigroup(..))
20 import Data.Sequence (ViewL(..), ViewR(..))
21 import Data.String (String)
22 import Data.Text (Text)
23 import Data.TreeSeq.Strict (Tree(..),Trees)
24 import GHC.Exts (IsString(..))
25 import Prelude (Num(..), undefined, Integral(..))
26 import Text.Show (Show(..))
27 import qualified Control.Monad.Trans.Reader as R
28 import qualified Control.Monad.Trans.State as S
29 import qualified Data.List as L
30 import qualified Data.Sequence as Seq
31 import qualified Data.Text as Text
32 import qualified Data.Text.Lazy as TL
34 import Language.TCT.Tree
35 import Language.TCT.Cell
36 import Language.TCT.Token
37 import Language.TCT.Elem
40 type Plain = R.Reader State TL.Text
41 instance IsString Plain where
42 fromString = return . fromString
43 instance Semigroup Plain where
45 instance Monoid Plain where
49 runPlain :: Plain -> State -> TL.Text
50 runPlain p s = {-TLB.toLazyText .-} R.runReader p s
52 text :: Plainify a => State -> a -> TL.Text
53 text st a = runPlain (plainify a) st
58 { state_escape :: Bool
60 instance Default State where
66 class Plainify a where
67 plainify :: a -> Plain
68 instance Plainify String where
69 plainify = return . fromString
70 instance Plainify Text where
71 plainify = return . TL.fromStrict
72 instance Plainify TL.Text where
74 instance Plainify (Trees (Cell Key) Tokens) where
75 plainify = plainify . treePosLastCell
76 instance Plainify (Trees (Pos,Cell Key) (Pos,Tokens)) where
77 plainify = foldMap plainify
78 instance Plainify (Tree (Pos,Cell Key) (Pos,Tokens)) where
79 plainify (TreeN (posEnd, Cell pos _ (KeySection lvl)) ts) =
80 plainifyIndentCell (posEnd,pos) <>
81 plainify (TL.replicate (int64 lvl) "#") <> " " <>
83 Tree0 (_,title) :< _ ->
90 plainify (Tree0 (posEnd,toks)) =
91 case Seq.viewl toks of
92 EmptyL -> plainify toks
93 t0:<_ -> plainifyIndentCell (posEnd,posCell t0) <> plainify toks
94 plainify (TreeN (posEnd,cell@(Cell pos _ _)) cs) =
95 plainifyIndentCell (posEnd,pos) <>
97 instance Plainify (Cell Key, Trees (Pos,Cell Key) (Pos,Tokens)) where
98 plainify (Cell _pos _posEnd key, cells) = do
100 KeyColon n wh -> textKey n wh ":"
101 KeyGreat n wh -> textKey n wh ">"
102 KeyEqual n wh -> textKey n wh "="
103 KeyBar n wh -> textKey n wh "|"
104 KeyDash -> textKey "" "" "- "
105 KeyDashDash -> textKey "" "" "-- "
106 KeyLower name attrs ->
111 KeySection{} -> undefined
113 plainify ("./"::TL.Text) <>
117 textKey :: Text -> White -> TL.Text -> Plain
118 textKey name wh mark =
119 plainify (textify name <> textify wh <> mark) <>
121 instance Plainify Tokens where
123 case Seq.viewl toks of
125 Cell pos _ _ :< _ -> do
127 return $ goTokens st toks `S.evalState` linePos pos
129 indent = TL.replicate (int64 $ columnPos pos - 1) " "
130 go :: State -> Cell Token -> S.State Int TL.Text
131 go st@State{..} tok =
135 let lines = Text.splitOn "\n" txt
136 S.put (lnum - 1 + L.length lines)
140 (l0:ls) -> textify l0 <> mconcat ((\l -> "\n"<>indent<>textify l)<$>ls)
141 TokenTag v -> return $ "#"<>textify v
145 then textify $ Text.pack ['\\',c]
147 TokenLink lnk -> return $ textify lnk
148 TokenPair grp ts -> do
149 ts' <- goTokens st ts
150 return $ textify o<>ts'<>textify c
151 where (o,c) = pairBorders grp ts
152 goTokens :: State -> Tokens -> S.State Int TL.Text
155 return $ foldr (<>) mempty ts'
156 instance Plainify Attrs where
157 plainify = plainify . textify
160 class Textify a where
161 textify :: a -> TL.Text
162 instance Textify Text where
163 textify = TL.fromStrict
164 instance Textify TL.Text where
166 instance Textify Attrs where
167 textify = foldMap textify
168 instance Textify (Text,Attr) where
169 textify (attr_white,Attr{..}) =
170 mconcat $ textify <$>
177 instance Textify Token where
178 textify (TokenPlain txt) = textify txt
179 textify (TokenTag v) = "#"<>textify v
180 textify (TokenEscape c) = TL.singleton c -- textify $ Text.pack ['\\',c]
181 textify (TokenLink lnk) = textify lnk
182 textify (TokenPair grp t) = textify o<>textify t<>textify c
183 where (o,c) = pairBorders grp t
184 instance Textify Tokens where
185 textify ts = foldMap (textify . unCell) ts
189 plainifyIndentCell :: (Pos,Pos) -> Plain
190 plainifyIndentCell (Pos lineLast colLast,Pos line col)
193 TL.replicate (int64 $ line - (lineLast+1)) "\n" <>
194 TL.replicate (int64 $ col - 1) " "
195 | lineLast == line && colLast <= col =
197 TL.replicate (int64 $ col - colLast) " "
198 | otherwise = undefined
201 treeRackUpLeft :: Tree (Cell k) (Cell a) -> Tree (Cell k) (Cell a)
202 treeRackUpLeft t = go t
204 Pos l0 c0 = posTree t
207 (linePos pos - l0 + 1)
208 (columnPos pos - c0 + 1)
209 go :: Tree (Cell k) (Cell a) -> Tree (Cell k) (Cell a)
210 go (Tree0 (Cell pos posEnd c)) =
211 Tree0 $ Cell (rackUpLeft pos) (rackUpLeft posEnd) c
212 go (TreeN (Cell pos posEnd c) ts) =
214 (Cell (rackUpLeft pos) (rackUpLeft posEnd) c)
218 Trees (Cell k) Tokens ->
219 Trees (Pos,Cell k) (Pos,Tokens)
220 treePosLastCell t = S.evalState (go`mapM`t) (Pos 1 1)
222 go :: Tree (Cell k) Tokens ->
223 S.State Pos (Tree (Pos,Cell k) (Pos,Tokens))
228 return $ Tree0 (lastPos,ts)
230 S.put $ posEndCell cell
231 return $ Tree0 (lastPos,ts)
232 go (TreeN cell ts) = do
234 S.put $ posEndCell cell
236 return $ TreeN (lastPos,cell) ts'
239 int64 :: Integral i => i -> Int64
240 int64 = fromInteger . toInteger