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,posTree 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
127 return $ goTokens st toks `S.evalState` linePos pos
130 indent = TL.replicate (int64 $ columnPos pos - 1) " "
131 go :: State -> Token -> S.State Int TL.Text
132 go st@State{..} = \case
133 TreeN (unCell -> p) ts -> do
134 ts' <- goTokens st ts
135 return $ textify o<>ts'<>textify c
136 where (o,c) = pairBorders p ts
137 Tree0 (unCell -> tok) ->
141 let lines = Text.splitOn "\n" txt
142 S.put (lnum - 1 + L.length lines)
146 (l0:ls) -> textify l0 <> mconcat ((\l -> "\n"<>indent<>textify l)<$>ls)
147 TokenTag v -> return $ "#"<>textify v
151 then textify $ Text.pack ['\\',c]
153 TokenLink lnk -> return $ textify lnk
154 goTokens :: State -> Tokens -> S.State Int TL.Text
157 return $ foldr (<>) mempty ts'
158 instance Plainify Attrs where
159 plainify = plainify . textify
162 class Textify a where
163 textify :: a -> TL.Text
164 instance Textify Text where
165 textify = TL.fromStrict
166 instance Textify TL.Text where
168 instance Textify Attrs where
169 textify = foldMap textify
170 instance Textify (Text,Attr) where
171 textify (attr_white,Attr{..}) =
172 mconcat $ textify <$>
179 instance Textify Token where
181 TreeN (unCell -> p) ts -> textify o<>textify ts<>textify c
182 where (o,c) = pairBorders p ts
183 Tree0 (unCell -> t) ->
185 TokenPlain txt -> textify txt
186 TokenTag v -> "#"<>textify v
187 TokenEscape c -> TL.singleton c -- textify $ Text.pack ['\\',c]
188 TokenLink lnk -> textify lnk
189 instance Textify Tokens where
190 textify = foldMap textify
194 plainifyIndentCell :: (Pos,Pos) -> Plain
195 plainifyIndentCell (Pos lineLast colLast,Pos line col)
198 TL.replicate (int64 $ line - (lineLast+1)) "\n" <>
199 TL.replicate (int64 $ col - 1) " "
200 | lineLast == line && colLast <= col =
202 TL.replicate (int64 $ col - colLast) " "
203 | otherwise = undefined
206 treeRackUpLeft :: Tree (Cell k) (Cell a) -> Tree (Cell k) (Cell a)
207 treeRackUpLeft t = go t
209 Pos l0 c0 = posTree t
212 (linePos pos - l0 + 1)
213 (columnPos pos - c0 + 1)
214 go :: Tree (Cell k) (Cell a) -> Tree (Cell k) (Cell a)
215 go (Tree0 (Cell pos posEnd c)) =
216 Tree0 $ Cell (rackUpLeft pos) (rackUpLeft posEnd) c
217 go (TreeN (Cell pos posEnd c) ts) =
219 (Cell (rackUpLeft pos) (rackUpLeft posEnd) c)
223 Trees (Cell k) Tokens ->
224 Trees (Pos,Cell k) (Pos,Tokens)
225 treePosLastCell t = S.evalState (go`mapM`t) (Pos 1 1)
227 go :: Tree (Cell k) Tokens ->
228 S.State Pos (Tree (Pos,Cell k) (Pos,Tokens))
233 return $ Tree0 (lastPos,ts)
236 return $ Tree0 (lastPos,ts)
241 return $ TreeN (lastPos,p) ts'
244 int64 :: Integral i => i -> Int64
245 int64 = fromInteger . toInteger