1 module Language.Symantic.Document.Plain where
3 import Control.Applicative (Applicative(..))
6 import Data.Function (($), (.), id)
7 import Data.Monoid (Monoid(..))
8 import Data.Ord (Ord(..))
9 import Data.Semigroup (Semigroup(..))
10 import Data.String (IsString(..))
11 import Prelude ((+), pred)
12 import GHC.Exts (IsList(..))
13 import System.Console.ANSI
14 import Text.Show (Show(..))
15 import qualified Data.List as List
16 import qualified Data.Text as Text
17 import qualified Data.Text.Lazy as TL
18 import qualified Data.Text.Lazy.Builder as TLB
19 -- import qualified Data.Text.Lazy.IO as TL
20 -- import qualified System.IO as IO
22 import Language.Symantic.Document.Sym
27 { inh_indent :: !(Indent Plain) -- ^ Current indentation level, used by 'newline'.
28 , inh_newline :: Plain -- ^ How to display 'newline'.
29 , inh_wrap_column :: !(Column Plain) -- ^ 'Column' after which 'wrap' breaks on a 'breakpoint' or 'breakspace'.
30 , inh_sgr :: ![SGR] -- ^ Active ANSI codes.
36 , inh_newline = newlineWithIndent
37 , inh_wrap_column = 80
44 { state_column :: !(Column Plain)
45 , state_column_max :: !(Column Plain)
51 , state_column_max = 0
57 { unPlain :: Inh -> State
58 -> (State -> TLB.Builder -> TLB.Builder) -- normal continuation
59 -> (State -> TLB.Builder -> TLB.Builder) -- wrapping continuation
62 buildPlain :: Plain -> TLB.Builder
63 buildPlain (Plain p) = p defInh defState oko oko
66 textPlain :: Plain -> TL.Text
67 textPlain = TLB.toLazyText . buildPlain
69 instance IsList Plain where
70 type Item Plain = Plain
73 instance Semigroup Plain where
74 x <> y = Plain $ \inh st ok ko ->
76 (\sx tx -> unPlain y inh sx
77 (\sy ty -> ok sy (tx<>ty))
78 (\sy ty -> ko sy (tx<>ty)))
79 (\sx tx -> unPlain y inh sx
80 (\sy ty -> ko sy (tx<>ty))
81 (\sy ty -> ko sy (tx<>ty)))
82 instance Monoid Plain where
85 instance IsString Plain where
88 plainWrite :: Column Plain -> TLB.Builder -> Plain
90 Plain $ \inh st ok ko ->
91 let newCol = state_column st + len in
92 (if newCol <= inh_wrap_column inh then ok else ko)
93 st{ state_column = newCol
94 , state_column_max = max (state_column_max st) newCol
97 instance Doc_Text Plain where
98 empty = Plain $ \_inh st ok _ko -> ok st ""
99 charH t = plainWrite 1 $ TLB.singleton t
100 stringH t = plainWrite (List.length t) (fromString t)
101 textH t = plainWrite (Text.length t) (TLB.fromText t)
102 ltextH t = plainWrite (intOfInt64 $ TL.length t) (TLB.fromLazyText t)
104 integer = stringH . show
105 replicate cnt p | cnt <= 0 = empty
106 | otherwise = p <> replicate (pred cnt) p
107 newline = Plain $ \inh -> unPlain (inh_newline inh) inh
109 newlineWithoutIndent :: Plain
110 newlineWithoutIndent = Plain $ \_inh st ok _ko ->
111 ok st{state_column=0} $ TLB.singleton '\n'
113 newlineWithIndent :: Plain
114 newlineWithIndent = Plain $ \inh st ok _ko ->
116 { state_column = inh_indent inh
117 , state_column_max = max (state_column_max st) (inh_indent inh)
119 TLB.singleton '\n' <>
120 fromString (List.replicate (inh_indent inh) ' ')
122 instance Doc_Align Plain where
123 type Column Plain = Int
124 type Indent Plain = Int
125 align p = Plain $ \inh st -> unPlain p inh{inh_indent=state_column st} st
126 withNewline nl p = Plain $ \inh -> unPlain p inh{inh_newline=nl}
127 withIndent ind p = Plain $ \inh -> unPlain p inh{inh_indent=ind}
128 incrIndent ind p = Plain $ \inh -> unPlain p inh{inh_indent=inh_indent inh + ind}
129 instance Doc_Wrap Plain where
130 ifFit x y = Plain $ \inh st ok ko ->
131 unPlain x inh st ok (\_sx _tx -> unPlain y inh st ok ko)
132 breakpoint onNoBreak onBreak p = Plain $ \inh st ok ko ->
133 unPlain (onNoBreak <> p) inh st ok
134 (\_sp _tp -> unPlain (onBreak <> p) inh st ok ko)
135 withWrapColumn col p = Plain $ \inh -> unPlain p inh{inh_wrap_column=col}
137 writeSGR :: SGR -> Plain -> Plain
138 writeSGR s p = Plain $ \inh@Inh{inh_sgr=ss} st ok ko ->
139 let o = Plain $ \_inh st' ok' _ko -> ok' st' $ fromString $ setSGRCode [s] in
140 let c :: TLB.Builder = fromString $ setSGRCode $ Reset:List.reverse ss in
141 unPlain (o<>p) inh{inh_sgr=s:ss} st
142 (\_st t -> ok st $ t<>c)
143 (\_st t -> ko st $ t<>c)
145 instance Doc_Color Plain where
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 Plain where
180 bold = writeSGR $ SetConsoleIntensity BoldIntensity
181 underline = writeSGR $ SetUnderlining SingleUnderline
182 italic = writeSGR $ SetItalicized True
190 = PlainIO { unPlainIO :: IO.Handle -> IO () }
191 instance IsString PlainIO where
192 fromString s = PlainIO $ \h -> IO.hPutStr h s
194 plainIO :: PlainIO -> IO.Handle -> IO ()
195 plainIO (PlainIO d) = d
197 instance Semigroup PlainIO where
198 PlainIO x <> PlainIO y = PlainIO $ \h -> do {x h; y h}
199 instance Monoid PlainIO where
202 instance Doc_Text PlainIO where
203 empty = PlainIO $ \_ -> return ()
204 int i = PlainIO $ \h -> IO.hPutStr h (show i)
205 integer i = PlainIO $ \h -> IO.hPutStr h (show i)
206 replicate i d = PlainIO $ replicateM_ i . plainIO d
207 charH x = PlainIO $ \h -> IO.hPutChar h x
208 stringH x = PlainIO $ \h -> IO.hPutStr h x
209 textH x = PlainIO $ \h -> Text.hPutStr h x
210 ltextH x = PlainIO $ \h -> TL.hPutStr h x
211 -- NOTE: PlainIO has no support for indentation, hence char = charH, etc.
216 instance Doc_Color PlainIO where
250 instance Doc_Decoration PlainIO where