1 module Language.Symantic.Document.Term
2 ( module Language.Symantic.Document.Sym
3 , module Language.Symantic.Document.Term
6 import Control.Applicative (Applicative(..))
8 import Data.Function (($), (.), id)
10 import Data.Monoid (Monoid(..))
11 import Data.Ord (Ord(..))
12 import Data.Semigroup (Semigroup(..))
13 import Data.String (IsString(..))
14 import GHC.Exts (IsList(..))
15 import Prelude ((+), pred)
16 import System.Console.ANSI
17 import Text.Show (Show(..))
18 import qualified Data.List as List
19 import qualified Data.Text as Text
20 import qualified Data.Text.Lazy as TL
21 import qualified Data.Text.Lazy.Builder as TLB
23 import Language.Symantic.Document.Sym
28 { reader_indent :: !(Indent Term) -- ^ Current indentation level, used by 'newline'.
29 , reader_newline :: Term -- ^ How to display 'newline'.
30 , reader_wrap_column :: !(Column Term) -- ^ 'Column' after which 'wrap' breaks on a 'breakpoint' or 'breakspace'.
31 , reader_sgr :: ![SGR] -- ^ Active ANSI codes.
32 , reader_colorable :: !Bool -- ^ Whether colors are activated or not.
33 , reader_decorable :: !Bool -- ^ Whether decorations are activated or not.
36 -- | Default 'Reader'.
40 , reader_newline = newlineWithIndent
41 , reader_wrap_column = 80
43 , reader_colorable = True
44 , reader_decorable = True
48 type State = Column Term
59 (State -> TLB.Builder -> TLB.Builder) -> -- normal continuation
60 (State -> TLB.Builder -> TLB.Builder) -> -- should-wrap continuation
63 type instance Column Term = Int
64 type instance Indent Term = Int
66 -- | Render a 'Term' into a 'TL.Text'.
67 textTerm :: Term -> TL.Text
68 textTerm = TLB.toLazyText . buildTerm
70 -- | Render a 'Term' into a 'TLB.Builder'.
71 buildTerm :: Term -> TLB.Builder
72 buildTerm (Term t) = t defReader defState oko oko
75 instance IsList Term where
79 instance Semigroup Term where
80 x <> y = Term $ \ro st ok ko ->
82 (\sx tx -> unTerm y ro sx
83 (\sy ty -> ok sy (tx<>ty))
84 (\sy ty -> ko sy (tx<>ty)))
85 (\sx tx -> unTerm y ro sx
86 (\sy ty -> ko sy (tx<>ty))
87 (\sy ty -> ko sy (tx<>ty)))
88 instance Monoid Term where
91 instance IsString Term where
94 writeH :: Column Term -> TLB.Builder -> Term
96 Term $ \ro st ok ko ->
97 let newCol = st + len in
98 (if newCol <= reader_wrap_column ro then ok else ko)
101 instance Doc_Text Term where
102 empty = Term $ \_ro st ok _ko -> ok st mempty
103 charH t = writeH 1 $ TLB.singleton t
104 stringH t = writeH (List.length t) (fromString t)
105 textH t = writeH (Text.length t) (TLB.fromText t)
106 ltextH t = writeH (intOfInt64 $ TL.length t) (TLB.fromLazyText t)
108 integer = stringH . show
109 replicate cnt t | cnt <= 0 = empty
110 | otherwise = t <> replicate (pred cnt) t
111 newline = Term $ \ro -> unTerm (reader_newline ro) ro
112 instance Doc_Align Term where
113 align t = Term $ \ro st -> unTerm t ro{reader_indent=st} st
114 withNewline nl t = Term $ \ro -> unTerm t ro{reader_newline=nl}
115 withIndent ind t = Term $ \ro -> unTerm t ro{reader_indent=ind}
116 incrIndent ind t = Term $ \ro -> unTerm t ro{reader_indent=reader_indent ro + ind}
117 column f = Term $ \ro st -> unTerm (f st) ro st
118 newlineWithoutIndent = Term $ \_ro _st ok _ko ->
119 ok 0 $ TLB.singleton '\n'
120 newlineWithIndent = Term $ \ro _st ok _ko ->
121 ok (reader_indent ro) $
122 TLB.singleton '\n' <>
123 fromString (List.replicate (reader_indent ro) ' ')
124 instance Doc_Wrap Term where
125 ifFit x y = Term $ \ro st ok ko ->
126 unTerm x ro st ok (\_sx _tx -> unTerm y ro st ok ko)
127 breakpoint onNoBreak onBreak t = Term $ \ro st ok ko ->
128 unTerm (onNoBreak <> t) ro st ok
129 (\_sp _tp -> unTerm (onBreak <> t) ro st ok ko)
130 withWrapColumn col t = Term $ \ro -> unTerm t ro{reader_wrap_column=col}
132 writeSGR :: SGR -> Term -> Term
133 writeSGR s (Term t) =
135 if reader_colorable ro
136 then unTerm (o <> m <> c) ro
139 o = Term $ \_ro st ok _ko -> ok st $ fromString $ setSGRCode [s]
140 m = Term $ \ro -> t ro{reader_sgr=s:reader_sgr ro}
141 c = Term $ \ro st ok _ko -> ok st $ fromString $ setSGRCode $ Reset:List.reverse (reader_sgr ro)
143 instance Doc_Color Term where
144 colorable f = Term $ \ro -> unTerm (f (reader_colorable ro)) ro
145 withColorable b t = Term $ \ro -> unTerm t ro{reader_colorable=b}
146 reverse = writeSGR $ SetSwapForegroundBackground True
147 black = writeSGR $ SetColor Foreground Dull Black
148 red = writeSGR $ SetColor Foreground Dull Red
149 green = writeSGR $ SetColor Foreground Dull Green
150 yellow = writeSGR $ SetColor Foreground Dull Yellow
151 blue = writeSGR $ SetColor Foreground Dull Blue
152 magenta = writeSGR $ SetColor Foreground Dull Magenta
153 cyan = writeSGR $ SetColor Foreground Dull Cyan
154 white = writeSGR $ SetColor Foreground Dull White
155 blacker = writeSGR $ SetColor Foreground Vivid Black
156 redder = writeSGR $ SetColor Foreground Vivid Red
157 greener = writeSGR $ SetColor Foreground Vivid Green
158 yellower = writeSGR $ SetColor Foreground Vivid Yellow
159 bluer = writeSGR $ SetColor Foreground Vivid Blue
160 magentaer = writeSGR $ SetColor Foreground Vivid Magenta
161 cyaner = writeSGR $ SetColor Foreground Vivid Cyan
162 whiter = writeSGR $ SetColor Foreground Vivid White
163 onBlack = writeSGR $ SetColor Background Dull Black
164 onRed = writeSGR $ SetColor Background Dull Red
165 onGreen = writeSGR $ SetColor Background Dull Green
166 onYellow = writeSGR $ SetColor Background Dull Yellow
167 onBlue = writeSGR $ SetColor Background Dull Blue
168 onMagenta = writeSGR $ SetColor Background Dull Magenta
169 onCyan = writeSGR $ SetColor Background Dull Cyan
170 onWhite = writeSGR $ SetColor Background Dull White
171 onBlacker = writeSGR $ SetColor Background Vivid Black
172 onRedder = writeSGR $ SetColor Background Vivid Red
173 onGreener = writeSGR $ SetColor Background Vivid Green
174 onYellower = writeSGR $ SetColor Background Vivid Yellow
175 onBluer = writeSGR $ SetColor Background Vivid Blue
176 onMagentaer = writeSGR $ SetColor Background Vivid Magenta
177 onCyaner = writeSGR $ SetColor Background Vivid Cyan
178 onWhiter = writeSGR $ SetColor Background Vivid White
179 instance Doc_Decoration Term where
180 decorable f = Term $ \ro -> unTerm (f (reader_decorable ro)) ro
181 withDecorable b t = Term $ \ro -> unTerm t ro{reader_decorable=b}
182 bold = writeSGR $ SetConsoleIntensity BoldIntensity
183 underline = writeSGR $ SetUnderlining SingleUnderline
184 italic = writeSGR $ SetItalicized True