1 module Language.Symantic.Document.Term.IO
2 ( module Language.Symantic.Document.Sym
3 , module Language.Symantic.Document.Term.IO
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
18 import Text.Show (Show(..))
19 import qualified Data.List as List
20 import qualified Data.Text as Text
21 import qualified Data.Text.IO as Text
22 import qualified Data.Text.Lazy as TL
23 import qualified Data.Text.Lazy.IO as TL
24 import qualified System.IO as IO
26 import Language.Symantic.Document.Sym
31 { reader_indent :: !(Indent TermIO) -- ^ Current indentation level, used by 'newline'.
32 , reader_newline :: TermIO -- ^ How to display 'newline'.
33 , reader_wrap_column :: !(Column TermIO) -- ^ 'Column' after which 'wrap' breaks on a 'breakpoint' or 'breakspace'.
34 , reader_sgr :: ![SGR] -- ^ Active ANSI codes.
35 , reader_handle :: !IO.Handle -- ^ Where to write.
38 -- | Default 'Reader'.
42 , reader_newline = newlineWithIndent
43 , reader_wrap_column = 80
45 , reader_handle = IO.stdout
49 type State = Column TermIO
58 { unTermIO :: Reader -> State ->
59 (State -> IO () -> IO ()) -> -- normal continuation
60 (State -> IO () -> IO ()) -> -- should-wrap continuation
63 type instance Column TermIO = Int
64 type instance Indent TermIO = Int
66 -- | Write a 'TermIO'.
67 runTermIO :: IO.Handle -> TermIO -> IO ()
68 runTermIO h (TermIO p) = p defReader{reader_handle=h} defState oko oko
71 instance IsList TermIO where
72 type Item TermIO = TermIO
75 instance Semigroup TermIO where
76 x <> y = TermIO $ \ro st ok ko ->
78 (\sx tx -> unTermIO y ro sx
79 (\sy ty -> ok sy (tx<>ty))
80 (\sy ty -> ko sy (tx<>ty)))
81 (\sx tx -> unTermIO y ro sx
82 (\sy ty -> ko sy (tx<>ty))
83 (\sy ty -> ko sy (tx<>ty)))
84 instance Monoid TermIO where
87 instance IsString TermIO where
90 writeH :: Column TermIO -> (IO.Handle -> IO ()) -> TermIO
92 TermIO $ \ro st ok ko ->
93 let newCol = st + len in
94 (if newCol <= reader_wrap_column ro then ok else ko)
95 newCol (t (reader_handle ro))
97 instance Doc_Text TermIO where
98 empty = TermIO $ \_ro st ok _ko -> ok st mempty
99 charH t = writeH 1 (`IO.hPutChar` t)
100 stringH t = writeH (List.length t) (`IO.hPutStr` t)
101 textH t = writeH (Text.length t) (`Text.hPutStr` t)
102 ltextH t = writeH (intOfInt64 $ TL.length t) (`TL.hPutStr` t)
104 integer = stringH . show
105 replicate cnt p | cnt <= 0 = empty
106 | otherwise = p <> replicate (pred cnt) p
107 newline = TermIO $ \ro -> unTermIO (reader_newline ro) ro
108 instance Doc_Align TermIO where
109 align p = TermIO $ \ro st -> unTermIO p ro{reader_indent=st} st
110 withNewline nl p = TermIO $ \ro -> unTermIO p ro{reader_newline=nl}
111 withIndent ind p = TermIO $ \ro -> unTermIO p ro{reader_indent=ind}
112 incrIndent ind p = TermIO $ \ro -> unTermIO p ro{reader_indent=reader_indent ro + ind}
113 column f = TermIO $ \ro st -> unTermIO (f st) ro st
114 newlineWithoutIndent = TermIO $ \ro _st ok _ko ->
115 ok 0 $ IO.hPutChar (reader_handle ro) '\n'
116 newlineWithIndent = TermIO $ \ro@Reader{reader_handle=h} _st ok _ko ->
117 ok (reader_indent ro) $ do
119 IO.hPutStr h $ List.replicate (reader_indent ro) ' '
120 instance Doc_Wrap TermIO where
121 ifFit x y = TermIO $ \ro st ok ko ->
122 unTermIO x ro st ok (\_sx _tx -> unTermIO y ro st ok ko)
123 breakpoint onNoBreak onBreak p = TermIO $ \ro st ok ko ->
124 unTermIO (onNoBreak <> p) ro st ok
125 (\_sp _tp -> unTermIO (onBreak <> p) ro st ok ko)
126 withWrapColumn col p = TermIO $ \ro -> unTermIO p ro{reader_wrap_column=col}
128 writeSGR :: SGR -> TermIO -> TermIO
129 writeSGR s p = o <> m <> c
131 o = TermIO $ \ro st ok _ko -> ok st $ hSetSGR (reader_handle ro) [s]
132 m = TermIO $ \ro -> unTermIO p ro{reader_sgr=s:reader_sgr ro}
133 c = TermIO $ \ro st ok _ko -> ok st $ hSetSGR (reader_handle ro) $ Reset:List.reverse (reader_sgr ro)
135 instance Doc_Color TermIO where
136 reverse = writeSGR $ SetSwapForegroundBackground True
137 black = writeSGR $ SetColor Foreground Dull Black
138 red = writeSGR $ SetColor Foreground Dull Red
139 green = writeSGR $ SetColor Foreground Dull Green
140 yellow = writeSGR $ SetColor Foreground Dull Yellow
141 blue = writeSGR $ SetColor Foreground Dull Blue
142 magenta = writeSGR $ SetColor Foreground Dull Magenta
143 cyan = writeSGR $ SetColor Foreground Dull Cyan
144 white = writeSGR $ SetColor Foreground Dull White
145 blacker = writeSGR $ SetColor Foreground Vivid Black
146 redder = writeSGR $ SetColor Foreground Vivid Red
147 greener = writeSGR $ SetColor Foreground Vivid Green
148 yellower = writeSGR $ SetColor Foreground Vivid Yellow
149 bluer = writeSGR $ SetColor Foreground Vivid Blue
150 magentaer = writeSGR $ SetColor Foreground Vivid Magenta
151 cyaner = writeSGR $ SetColor Foreground Vivid Cyan
152 whiter = writeSGR $ SetColor Foreground Vivid White
153 onBlack = writeSGR $ SetColor Background Dull Black
154 onRed = writeSGR $ SetColor Background Dull Red
155 onGreen = writeSGR $ SetColor Background Dull Green
156 onYellow = writeSGR $ SetColor Background Dull Yellow
157 onBlue = writeSGR $ SetColor Background Dull Blue
158 onMagenta = writeSGR $ SetColor Background Dull Magenta
159 onCyan = writeSGR $ SetColor Background Dull Cyan
160 onWhite = writeSGR $ SetColor Background Dull White
161 onBlacker = writeSGR $ SetColor Background Vivid Black
162 onRedder = writeSGR $ SetColor Background Vivid Red
163 onGreener = writeSGR $ SetColor Background Vivid Green
164 onYellower = writeSGR $ SetColor Background Vivid Yellow
165 onBluer = writeSGR $ SetColor Background Vivid Blue
166 onMagentaer = writeSGR $ SetColor Background Vivid Magenta
167 onCyaner = writeSGR $ SetColor Background Vivid Cyan
168 onWhiter = writeSGR $ SetColor Background Vivid White
169 instance Doc_Decoration TermIO where
170 bold = writeSGR $ SetConsoleIntensity BoldIntensity
171 underline = writeSGR $ SetUnderlining SingleUnderline
172 italic = writeSGR $ SetItalicized True