1 {-# LANGUAGE FlexibleInstances #-}
2 {-# LANGUAGE OverloadedStrings #-}
3 {-# LANGUAGE ViewPatterns #-}
4 {-# OPTIONS_GHC -fno-warn-orphans #-}
5 module Language.TCT.Write.Plain where
7 import Control.Applicative (Applicative(..), liftA2)
8 import Control.Monad (Monad(..), mapM)
10 import Data.Char (Char)
11 import Data.Default.Class (Default(..))
12 import Data.Eq (Eq(..))
13 import Data.Foldable (Foldable(..))
14 import Data.Function (($), (.))
15 import Data.Functor ((<$>))
16 import Data.Int (Int64)
17 import Data.Maybe (Maybe(..))
18 import Data.Monoid (Monoid(..))
19 import Data.Ord (Ord(..))
20 import Data.Semigroup (Semigroup(..))
21 import Data.Sequence (Seq, ViewL(..))
22 import Data.String (String, IsString(..))
23 import Data.Text (Text)
24 import Data.TreeSeq.Strict (Tree(..),Trees)
25 import Data.Tuple (fst)
26 import Prelude (Num(..), undefined, Integral(..))
27 import Text.Show (Show(..))
28 import qualified Control.Monad.Trans.State as S
29 import qualified Data.Sequence as Seq
30 import qualified Data.Text as Text
31 import qualified Data.Text.Lazy as TL
32 import qualified Data.Text.Lazy.Builder as TLB
34 -- import Language.TCT.Tree
35 import Language.TCT.Token
36 import Language.TCT.Cell
37 import Language.TCT.Elem
38 import Language.TCT.Read.Token
41 type Plain = S.State State TLB.Builder
42 -- NOTE: To get maximum performance when building lazy Text values using a builder,
43 -- associate mappend calls to the right.
44 -- NOTE: (Semigroup.<>) associates to the right.
45 instance IsString Plain where
46 fromString = return . fromString
47 instance Semigroup Plain where
49 instance Monoid Plain where
53 runPlain :: Plain -> State -> TL.Text
54 runPlain p s = TLB.toLazyText $ fst $ S.runState p s
56 text :: Plainify a => State -> a -> TL.Text
57 text st a = runPlain (plainify a) st
62 { state_escape :: Bool -- FIXME: useful?
65 instance Default State where
72 class Plainify a where
73 plainify :: a -> Plain
74 instance Plainify () where
76 instance Plainify Char where
77 plainify = return . TLB.singleton
78 instance Plainify String where
79 plainify = return . fromString
80 instance Plainify Text where
81 plainify = plainify . TL.fromStrict
82 instance Plainify TL.Text where
83 plainify = return . TLB.fromLazyText
84 instance Plainify a => Plainify (Cell a) where
85 plainify (Cell _bp@(Pos line col) ep a) = do
86 Pos lineLast colLast <- S.gets state_pos
88 _ | lineLast < line -> do
89 S.modify $ \s -> s{state_pos=ep}
90 plainify (Text.replicate (line - lineLast - 1) "\n")
91 <> plainify (Text.replicate (col - 1) " ")
93 _ | lineLast == line && colLast <= col -> do
94 S.modify $ \s -> s{state_pos=ep}
95 plainify (Text.replicate (col - colLast) " ")
98 instance Plainify (Trees (Cell Key) Tokens) where
99 plainify = foldMap plainify
100 instance Plainify (Tree (Cell Key) Tokens) where
102 TreeN (Cell bp ep k) ts -> plainify (Cell bp ep (k,ts))
103 Tree0 ts -> plainify ts
104 instance Plainify (Key, Trees (Cell Key) Tokens) where
107 KeyColon n wh -> textKey n wh ":"
108 KeyGreat n wh -> textKey n wh ">"
109 KeyEqual n wh -> textKey n wh "="
110 KeyBar n wh -> textKey n wh "|"
111 KeyDash -> textKey "" "" "- "
112 KeyDashDash -> textKey "" "" "-- "
113 KeyLower name attrs ->
119 plainify (TL.replicate (int64 lvl) "#") <>
121 Tree0 title :< ts' ->
126 plainify ("./"::TL.Text) <>
130 textKey :: Text -> White -> TL.Text -> Plain
131 textKey name wh mark =
136 instance Plainify Tokens where
137 plainify = foldMap plainify
138 instance Plainify Token where
140 TreeN (Cell bp ep k) ts ->
141 plainify (Cell bp ep ()) <>
142 plainify o <> plainify ts <> plainify c
143 where (o,c) = pairBorders k ts
145 -- plainify (Cell bp ep ()) <>
147 TokenPhrases p -> plainify p
148 TokenRaw t -> plainify t
151 let lines = Text.splitOn "\n" txt
152 S.put (lnum - 1 + List.length lines)
156 (l0:ls) -> plainify l0 <> mconcat ((\l -> "\n"<>indent<>plainify l)<$>ls)
158 TokenTag v -> plainify $ ("#"<>) <$> v
160 esc <- S.gets state_escape
162 then plainify $ (('\\' :) . pure) <$> c
164 TokenLink lnk -> plainify lnk
165 instance Plainify Phrases where
166 plainify = foldMap plainify
167 instance Plainify Phrase where
170 PhraseWord t -> plainify t
171 PhraseWhite t -> plainify t
172 PhraseOther t -> plainify t
173 instance Plainify ElemAttrs where
174 plainify = foldMap plainify
175 instance Plainify (Text,ElemAttr) where
176 plainify (elemAttr_white,ElemAttr{..}) =
177 mconcat $ plainify <$>
187 class Textify a where
188 plainify :: a -> TL.Text
189 instance Textify Text where
190 plainify = TL.fromStrict
191 instance Textify TL.Text where
193 instance Textify Tokens where
194 plainify = foldMap plainify
195 instance Textify Token where
197 TreeN (unCell -> p) ts -> plainify o<>plainify ts<>plainify c
198 where (o,c) = pairBorders p ts
199 Tree0 (unCell -> t) ->
201 TokenPlain txt -> plainify txt
202 TokenTag v -> "#"<>plainify v
203 TokenEscape c -> TL.singleton c -- plainify $ Text.pack ['\\',c]
204 TokenLink lnk -> plainify lnk
207 -- * Class 'RackUpLeft'
208 class RackUpLeft a where
209 rackUpLeft :: a -> S.State (Maybe Pos) a
210 instance RackUpLeft Pos where
211 rackUpLeft pos@Pos{..} = do
213 Nothing -> return pos
216 { linePos = linePos - l0 + 1
217 , columnPos = columnPos - c0 + 1
219 instance RackUpLeft (Cell a) where
220 rackUpLeft (Cell bp ep a) = do
228 instance RackUpLeft a => RackUpLeft (Seq a) where
229 rackUpLeft = mapM rackUpLeft
230 instance (RackUpLeft k, RackUpLeft a) => RackUpLeft (Tree k a) where
232 Tree0 a -> Tree0 <$> rackUpLeft a
233 TreeN k ts -> TreeN <$> rackUpLeft k <*> rackUpLeft ts
237 plainifyIndentCell :: (Pos,Pos) -> Plain
238 plainifyIndentCell (Pos lineLast colLast,Pos line col)
241 TL.replicate (int64 $ line - (lineLast+1)) "\n" <>
242 TL.replicate (int64 $ col - 1) " "
243 | lineLast == line && colLast <= col =
245 TL.replicate (int64 $ col - colLast) " "
246 | otherwise = undefined
251 Trees (Cell k) Tokens ->
252 Trees (Pos,Cell k) (Pos,Tokens)
253 treePosLastCell t = S.evalState (go`mapM`t) (Pos 1 1)
255 go :: Tree (Cell k) Tokens ->
256 S.State Pos (Tree (Pos,Cell k) (Pos,Tokens))
261 return $ Tree0 (lastPos,ts)
264 return $ Tree0 (lastPos,ts)
269 return $ TreeN (lastPos,p) ts'
273 int64 :: Integral i => i -> Int64
274 int64 = fromInteger . toInteger