unWord :: Word d -> d
unWord (Word d) = d
instance From [SGR] d => From [SGR] (Word d) where
- from = Word . from
+ from = Word . from
-- * Class 'From'
class From a d where
- from :: a -> d
- default from :: From String d => Show a => a -> d
- from = from . show
+ from :: a -> d
+ default from :: From String d => Show a => a -> d
+ from = from . show
instance From (Line String) d => From Int d where
- from = from . Line . show
+ from = from . Line . show
instance From (Line String) d => From Integer d where
- from = from . Line . show
+ from = from . Line . show
instance From (Line String) d => From Natural d where
- from = from . Line . show
+ from = from . Line . show
-- String
instance From Char String where
- from = pure
+ from = pure
instance From String String where
- from = id
+ from = id
instance From Text String where
- from = Text.unpack
+ from = Text.unpack
instance From TL.Text String where
- from = TL.unpack
+ from = TL.unpack
instance From d String => From (Line d) String where
- from = from . unLine
+ from = from . unLine
instance From d String => From (Word d) String where
- from = from . unWord
+ from = from . unWord
instance From [SGR] String where
- from = ANSI.setSGRCode
+ from = ANSI.setSGRCode
-- Text
instance From Char Text where
- from = Text.singleton
+ from = Text.singleton
instance From String Text where
- from = Text.pack
+ from = Text.pack
instance From Text Text where
- from = id
+ from = id
instance From TL.Text Text where
- from = TL.toStrict
+ from = TL.toStrict
instance From d Text => From (Line d) Text where
- from = from . unLine
+ from = from . unLine
instance From d Text => From (Word d) Text where
- from = from . unWord
+ from = from . unWord
instance From [SGR] Text where
- from = from . ANSI.setSGRCode
+ from = from . ANSI.setSGRCode
-- TL.Text
instance From Char TL.Text where
- from = TL.singleton
+ from = TL.singleton
instance From String TL.Text where
- from = TL.pack
+ from = TL.pack
instance From Text TL.Text where
- from = TL.fromStrict
+ from = TL.fromStrict
instance From TL.Text TL.Text where
- from = id
+ from = id
instance From d TL.Text => From (Line d) TL.Text where
- from = from . unLine
+ from = from . unLine
instance From d TL.Text => From (Word d) TL.Text where
- from = from . unWord
+ from = from . unWord
instance From [SGR] TL.Text where
- from = from . ANSI.setSGRCode
+ from = from . ANSI.setSGRCode
-- TLB.Builder
instance From Char TLB.Builder where
- from = TLB.singleton
+ from = TLB.singleton
instance From String TLB.Builder where
- from = fromString
+ from = fromString
instance From Text TLB.Builder where
- from = TLB.fromText
+ from = TLB.fromText
instance From TL.Text TLB.Builder where
- from = TLB.fromLazyText
+ from = TLB.fromLazyText
instance From TLB.Builder TLB.Builder where
- from = id
+ from = id
instance From d TLB.Builder => From (Line d) TLB.Builder where
- from = from . unLine
+ from = from . unLine
instance From d TLB.Builder => From (Word d) TLB.Builder where
- from = from . unWord
+ from = from . unWord
instance From [SGR] TLB.Builder where
- from = from . ANSI.setSGRCode
+ from = from . ANSI.setSGRCode
runTextBuilder :: TLB.Builder -> TL.Text
runTextBuilder = TLB.toLazyText
-- * Class 'Lengthable'
class Lengthable d where
- width :: d -> Column
- nullWidth :: d -> Bool
- nullWidth d = width d == 0
+ width :: d -> Column
+ nullWidth :: d -> Bool
+ nullWidth d = width d == 0
instance Lengthable Char where
- width _ = 1
- nullWidth = const False
+ width _ = 1
+ nullWidth = const False
instance Lengthable String where
- width = fromIntegral . List.length
- nullWidth = Fold.null
+ width = fromIntegral . List.length
+ nullWidth = Fold.null
instance Lengthable Text.Text where
- width = fromIntegral . Text.length
- nullWidth = Text.null
+ width = fromIntegral . Text.length
+ nullWidth = Text.null
instance Lengthable TL.Text where
- width = fromIntegral . TL.length
- nullWidth = TL.null
+ width = fromIntegral . TL.length
+ nullWidth = TL.null
instance Lengthable d => Lengthable (Line d) where
- width = fromIntegral . width . unLine
- nullWidth = nullWidth . unLine
+ width = fromIntegral . width . unLine
+ nullWidth = nullWidth . unLine
instance Lengthable d => Lengthable (Word d) where
- width = fromIntegral . width . unWord
- nullWidth = nullWidth . unWord
+ width = fromIntegral . width . unWord
+ nullWidth = nullWidth . unWord
-- * Class 'Spaceable'
class Monoid d => Spaceable d where
- newline :: d
- space :: d
- default newline :: Spaceable (UnTrans d) => Trans d => d
- default space :: Spaceable (UnTrans d) => Trans d => d
- newline = noTrans newline
- space = noTrans space
-
- -- | @'spaces' ind = 'replicate' ind 'space'@
- spaces :: Column -> d
- default spaces :: Monoid d => Column -> d
- spaces i = replicate (fromIntegral i) space
- unlines :: Foldable f => f (Line d) -> d
- unlines = Fold.foldr (\(Line x) acc -> x<>newline<>acc) mempty
- unwords :: Foldable f => Functor f => f (Word d) -> d
- unwords = intercalate space . (unWord <$>)
- -- | Like 'unlines' but without the trailing 'newline'.
- catLines :: Foldable f => Functor f => f (Line d) -> d
- catLines = catV . (unLine <$>)
- -- | @x '<+>' y = x '<>' 'space' '<>' y@
- (<+>) :: d -> d -> d
- -- | @x '</>' y = x '<>' 'newline' '<>' y@
- (</>) :: d -> d -> d
- x <+> y = x <> space <> y
- x </> y = x <> newline <> y
- catH :: Foldable f => f d -> d
- catV :: Foldable f => f d -> d
- catH = Fold.foldr (<>) mempty
- catV = intercalate newline
+ newline :: d
+ space :: d
+ default newline :: Spaceable (UnTrans d) => Trans d => d
+ default space :: Spaceable (UnTrans d) => Trans d => d
+ newline = noTrans newline
+ space = noTrans space
+
+ -- | @'spaces' ind = 'replicate' ind 'space'@
+ spaces :: Column -> d
+ default spaces :: Monoid d => Column -> d
+ spaces i = replicate (fromIntegral i) space
+ unlines :: Foldable f => f (Line d) -> d
+ unlines = Fold.foldr (\(Line x) acc -> x<>newline<>acc) mempty
+ unwords :: Foldable f => Functor f => f (Word d) -> d
+ unwords = intercalate space . (unWord <$>)
+ -- | Like 'unlines' but without the trailing 'newline'.
+ catLines :: Foldable f => Functor f => f (Line d) -> d
+ catLines = catV . (unLine <$>)
+ -- | @x '<+>' y = x '<>' 'space' '<>' y@
+ (<+>) :: d -> d -> d
+ -- | @x '</>' y = x '<>' 'newline' '<>' y@
+ (</>) :: d -> d -> d
+ x <+> y = x <> space <> y
+ x </> y = x <> newline <> y
+ catH :: Foldable f => f d -> d
+ catV :: Foldable f => f d -> d
+ catH = Fold.foldr (<>) mempty
+ catV = intercalate newline
infixr 6 <+>
infixr 6 </>
instance Spaceable String where
- newline = "\n"
- space = " "
- spaces n = List.replicate (fromIntegral n) ' '
+ newline = "\n"
+ space = " "
+ spaces n = List.replicate (fromIntegral n) ' '
instance Spaceable Text where
- newline = "\n"
- space = " "
- spaces n = Text.replicate (fromIntegral n) " "
+ newline = "\n"
+ space = " "
+ spaces n = Text.replicate (fromIntegral n) " "
instance Spaceable TL.Text where
- newline = "\n"
- space = " "
- spaces n = TL.replicate (fromIntegral n) " "
+ newline = "\n"
+ space = " "
+ spaces n = TL.replicate (fromIntegral n) " "
instance Spaceable TLB.Builder where
- newline = TLB.singleton '\n'
- space = TLB.singleton ' '
- spaces = TLB.fromText . spaces
+ newline = TLB.singleton '\n'
+ space = TLB.singleton ' '
+ spaces = TLB.fromText . spaces
intercalate :: (Foldable f, Monoid d) => d -> f d -> d
intercalate sep ds = if Fold.null ds then mempty else Fold.foldr1 (\x y -> x<>sep<>y) ds
-- * Class 'Splitable'
class (Lengthable d, Monoid d) => Splitable d where
- tail :: d -> Maybe d
- break :: (Char -> Bool) -> d -> (d, d)
- span :: (Char -> Bool) -> d -> (d, d)
- span f = break (not . f)
- lines :: d -> [Line d]
- words :: d -> [Word d]
- linesNoEmpty :: d -> [Line d]
- wordsNoEmpty :: d -> [Word d]
- lines = (Line <$>) . splitOnChar (== '\n')
- words = (Word <$>) . splitOnChar (== ' ')
- linesNoEmpty = (Line <$>) . splitOnCharNoEmpty (== '\n')
- wordsNoEmpty = (Word <$>) . splitOnCharNoEmpty (== ' ')
-
- splitOnChar :: (Char -> Bool) -> d -> [d]
- splitOnChar f d0 =
- if nullWidth d0 then [] else go d0
- where
- go d =
- let (l,r) = f`break`d in
- l : case tail r of
- Nothing -> []
- Just rt | nullWidth rt -> [mempty]
- | otherwise -> go rt
- splitOnCharNoEmpty :: (Char -> Bool) -> d -> [d]
- splitOnCharNoEmpty f d =
- let (l,r) = f`break`d in
- (if nullWidth l then [] else [l]) <>
- case tail r of
- Nothing -> []
- Just rt -> splitOnCharNoEmpty f rt
+ tail :: d -> Maybe d
+ break :: (Char -> Bool) -> d -> (d, d)
+ span :: (Char -> Bool) -> d -> (d, d)
+ span f = break (not . f)
+ lines :: d -> [Line d]
+ words :: d -> [Word d]
+ linesNoEmpty :: d -> [Line d]
+ wordsNoEmpty :: d -> [Word d]
+ lines = (Line <$>) . splitOnChar (== '\n')
+ words = (Word <$>) . splitOnChar (== ' ')
+ linesNoEmpty = (Line <$>) . splitOnCharNoEmpty (== '\n')
+ wordsNoEmpty = (Word <$>) . splitOnCharNoEmpty (== ' ')
+
+ splitOnChar :: (Char -> Bool) -> d -> [d]
+ splitOnChar f d0 =
+ if nullWidth d0 then [] else go d0
+ where
+ go d =
+ let (l,r) = f`break`d in
+ l : case tail r of
+ Nothing -> []
+ Just rt | nullWidth rt -> [mempty]
+ | otherwise -> go rt
+ splitOnCharNoEmpty :: (Char -> Bool) -> d -> [d]
+ splitOnCharNoEmpty f d =
+ let (l,r) = f`break`d in
+ (if nullWidth l then [] else [l]) <>
+ case tail r of
+ Nothing -> []
+ Just rt -> splitOnCharNoEmpty f rt
instance Splitable String where
- tail [] = Nothing
- tail s = Just $ List.tail s
- break = List.break
+ tail [] = Nothing
+ tail s = Just $ List.tail s
+ break = List.break
instance Splitable Text.Text where
- tail "" = Nothing
- tail s = Just $ Text.tail s
- break = Text.break
+ tail "" = Nothing
+ tail s = Just $ Text.tail s
+ break = Text.break
instance Splitable TL.Text where
- tail "" = Nothing
- tail s = Just $ TL.tail s
- break = TL.break
+ tail "" = Nothing
+ tail s = Just $ TL.tail s
+ break = TL.break
-- * Class 'Decorable'
class Decorable d where
- bold :: d -> d
- underline :: d -> d
- italic :: d -> d
- default bold :: Decorable (UnTrans d) => Trans d => d -> d
- default underline :: Decorable (UnTrans d) => Trans d => d -> d
- default italic :: Decorable (UnTrans d) => Trans d => d -> d
- bold = noTrans1 bold
- underline = noTrans1 underline
- italic = noTrans1 italic
+ bold :: d -> d
+ underline :: d -> d
+ italic :: d -> d
+ default bold :: Decorable (UnTrans d) => Trans d => d -> d
+ default underline :: Decorable (UnTrans d) => Trans d => d -> d
+ default italic :: Decorable (UnTrans d) => Trans d => d -> d
+ bold = noTrans1 bold
+ underline = noTrans1 underline
+ italic = noTrans1 italic
-- * Class 'Colorable16'
class Colorable16 d where
- reverse :: d -> d
-
- -- Foreground colors
- -- Dull
- black :: d -> d
- red :: d -> d
- green :: d -> d
- yellow :: d -> d
- blue :: d -> d
- magenta :: d -> d
- cyan :: d -> d
- white :: d -> d
-
- -- Vivid
- blacker :: d -> d
- redder :: d -> d
- greener :: d -> d
- yellower :: d -> d
- bluer :: d -> d
- magentaer :: d -> d
- cyaner :: d -> d
- whiter :: d -> d
-
- -- Background colors
- -- Dull
- onBlack :: d -> d
- onRed :: d -> d
- onGreen :: d -> d
- onYellow :: d -> d
- onBlue :: d -> d
- onMagenta :: d -> d
- onCyan :: d -> d
- onWhite :: d -> d
-
- -- Vivid
- onBlacker :: d -> d
- onRedder :: d -> d
- onGreener :: d -> d
- onYellower :: d -> d
- onBluer :: d -> d
- onMagentaer :: d -> d
- onCyaner :: d -> d
- onWhiter :: d -> d
-
- default reverse :: Colorable16 (UnTrans d) => Trans d => d -> d
- default black :: Colorable16 (UnTrans d) => Trans d => d -> d
- default red :: Colorable16 (UnTrans d) => Trans d => d -> d
- default green :: Colorable16 (UnTrans d) => Trans d => d -> d
- default yellow :: Colorable16 (UnTrans d) => Trans d => d -> d
- default blue :: Colorable16 (UnTrans d) => Trans d => d -> d
- default magenta :: Colorable16 (UnTrans d) => Trans d => d -> d
- default cyan :: Colorable16 (UnTrans d) => Trans d => d -> d
- default white :: Colorable16 (UnTrans d) => Trans d => d -> d
- default blacker :: Colorable16 (UnTrans d) => Trans d => d -> d
- default redder :: Colorable16 (UnTrans d) => Trans d => d -> d
- default greener :: Colorable16 (UnTrans d) => Trans d => d -> d
- default yellower :: Colorable16 (UnTrans d) => Trans d => d -> d
- default bluer :: Colorable16 (UnTrans d) => Trans d => d -> d
- default magentaer :: Colorable16 (UnTrans d) => Trans d => d -> d
- default cyaner :: Colorable16 (UnTrans d) => Trans d => d -> d
- default whiter :: Colorable16 (UnTrans d) => Trans d => d -> d
- default onBlack :: Colorable16 (UnTrans d) => Trans d => d -> d
- default onRed :: Colorable16 (UnTrans d) => Trans d => d -> d
- default onGreen :: Colorable16 (UnTrans d) => Trans d => d -> d
- default onYellow :: Colorable16 (UnTrans d) => Trans d => d -> d
- default onBlue :: Colorable16 (UnTrans d) => Trans d => d -> d
- default onMagenta :: Colorable16 (UnTrans d) => Trans d => d -> d
- default onCyan :: Colorable16 (UnTrans d) => Trans d => d -> d
- default onWhite :: Colorable16 (UnTrans d) => Trans d => d -> d
- default onBlacker :: Colorable16 (UnTrans d) => Trans d => d -> d
- default onRedder :: Colorable16 (UnTrans d) => Trans d => d -> d
- default onGreener :: Colorable16 (UnTrans d) => Trans d => d -> d
- default onYellower :: Colorable16 (UnTrans d) => Trans d => d -> d
- default onBluer :: Colorable16 (UnTrans d) => Trans d => d -> d
- default onMagentaer :: Colorable16 (UnTrans d) => Trans d => d -> d
- default onCyaner :: Colorable16 (UnTrans d) => Trans d => d -> d
- default onWhiter :: Colorable16 (UnTrans d) => Trans d => d -> d
-
- reverse = noTrans1 reverse
- black = noTrans1 black
- red = noTrans1 red
- green = noTrans1 green
- yellow = noTrans1 yellow
- blue = noTrans1 blue
- magenta = noTrans1 magenta
- cyan = noTrans1 cyan
- white = noTrans1 white
- blacker = noTrans1 blacker
- redder = noTrans1 redder
- greener = noTrans1 greener
- yellower = noTrans1 yellower
- bluer = noTrans1 bluer
- magentaer = noTrans1 magentaer
- cyaner = noTrans1 cyaner
- whiter = noTrans1 whiter
- onBlack = noTrans1 onBlack
- onRed = noTrans1 onRed
- onGreen = noTrans1 onGreen
- onYellow = noTrans1 onYellow
- onBlue = noTrans1 onBlue
- onMagenta = noTrans1 onMagenta
- onCyan = noTrans1 onCyan
- onWhite = noTrans1 onWhite
- onBlacker = noTrans1 onBlacker
- onRedder = noTrans1 onRedder
- onGreener = noTrans1 onGreener
- onYellower = noTrans1 onYellower
- onBluer = noTrans1 onBluer
- onMagentaer = noTrans1 onMagentaer
- onCyaner = noTrans1 onCyaner
- onWhiter = noTrans1 onWhiter
+ reverse :: d -> d
+
+ -- Foreground colors
+ -- Dull
+ black :: d -> d
+ red :: d -> d
+ green :: d -> d
+ yellow :: d -> d
+ blue :: d -> d
+ magenta :: d -> d
+ cyan :: d -> d
+ white :: d -> d
+
+ -- Vivid
+ blacker :: d -> d
+ redder :: d -> d
+ greener :: d -> d
+ yellower :: d -> d
+ bluer :: d -> d
+ magentaer :: d -> d
+ cyaner :: d -> d
+ whiter :: d -> d
+
+ -- Background colors
+ -- Dull
+ onBlack :: d -> d
+ onRed :: d -> d
+ onGreen :: d -> d
+ onYellow :: d -> d
+ onBlue :: d -> d
+ onMagenta :: d -> d
+ onCyan :: d -> d
+ onWhite :: d -> d
+
+ -- Vivid
+ onBlacker :: d -> d
+ onRedder :: d -> d
+ onGreener :: d -> d
+ onYellower :: d -> d
+ onBluer :: d -> d
+ onMagentaer :: d -> d
+ onCyaner :: d -> d
+ onWhiter :: d -> d
+
+ default reverse :: Colorable16 (UnTrans d) => Trans d => d -> d
+ default black :: Colorable16 (UnTrans d) => Trans d => d -> d
+ default red :: Colorable16 (UnTrans d) => Trans d => d -> d
+ default green :: Colorable16 (UnTrans d) => Trans d => d -> d
+ default yellow :: Colorable16 (UnTrans d) => Trans d => d -> d
+ default blue :: Colorable16 (UnTrans d) => Trans d => d -> d
+ default magenta :: Colorable16 (UnTrans d) => Trans d => d -> d
+ default cyan :: Colorable16 (UnTrans d) => Trans d => d -> d
+ default white :: Colorable16 (UnTrans d) => Trans d => d -> d
+ default blacker :: Colorable16 (UnTrans d) => Trans d => d -> d
+ default redder :: Colorable16 (UnTrans d) => Trans d => d -> d
+ default greener :: Colorable16 (UnTrans d) => Trans d => d -> d
+ default yellower :: Colorable16 (UnTrans d) => Trans d => d -> d
+ default bluer :: Colorable16 (UnTrans d) => Trans d => d -> d
+ default magentaer :: Colorable16 (UnTrans d) => Trans d => d -> d
+ default cyaner :: Colorable16 (UnTrans d) => Trans d => d -> d
+ default whiter :: Colorable16 (UnTrans d) => Trans d => d -> d
+ default onBlack :: Colorable16 (UnTrans d) => Trans d => d -> d
+ default onRed :: Colorable16 (UnTrans d) => Trans d => d -> d
+ default onGreen :: Colorable16 (UnTrans d) => Trans d => d -> d
+ default onYellow :: Colorable16 (UnTrans d) => Trans d => d -> d
+ default onBlue :: Colorable16 (UnTrans d) => Trans d => d -> d
+ default onMagenta :: Colorable16 (UnTrans d) => Trans d => d -> d
+ default onCyan :: Colorable16 (UnTrans d) => Trans d => d -> d
+ default onWhite :: Colorable16 (UnTrans d) => Trans d => d -> d
+ default onBlacker :: Colorable16 (UnTrans d) => Trans d => d -> d
+ default onRedder :: Colorable16 (UnTrans d) => Trans d => d -> d
+ default onGreener :: Colorable16 (UnTrans d) => Trans d => d -> d
+ default onYellower :: Colorable16 (UnTrans d) => Trans d => d -> d
+ default onBluer :: Colorable16 (UnTrans d) => Trans d => d -> d
+ default onMagentaer :: Colorable16 (UnTrans d) => Trans d => d -> d
+ default onCyaner :: Colorable16 (UnTrans d) => Trans d => d -> d
+ default onWhiter :: Colorable16 (UnTrans d) => Trans d => d -> d
+
+ reverse = noTrans1 reverse
+ black = noTrans1 black
+ red = noTrans1 red
+ green = noTrans1 green
+ yellow = noTrans1 yellow
+ blue = noTrans1 blue
+ magenta = noTrans1 magenta
+ cyan = noTrans1 cyan
+ white = noTrans1 white
+ blacker = noTrans1 blacker
+ redder = noTrans1 redder
+ greener = noTrans1 greener
+ yellower = noTrans1 yellower
+ bluer = noTrans1 bluer
+ magentaer = noTrans1 magentaer
+ cyaner = noTrans1 cyaner
+ whiter = noTrans1 whiter
+ onBlack = noTrans1 onBlack
+ onRed = noTrans1 onRed
+ onGreen = noTrans1 onGreen
+ onYellow = noTrans1 onYellow
+ onBlue = noTrans1 onBlue
+ onMagenta = noTrans1 onMagenta
+ onCyan = noTrans1 onCyan
+ onWhite = noTrans1 onWhite
+ onBlacker = noTrans1 onBlacker
+ onRedder = noTrans1 onRedder
+ onGreener = noTrans1 onGreener
+ onYellower = noTrans1 onYellower
+ onBluer = noTrans1 onBluer
+ onMagentaer = noTrans1 onMagentaer
+ onCyaner = noTrans1 onCyaner
+ onWhiter = noTrans1 onWhiter
-- | For debugging purposes.
instance Colorable16 String where
- reverse = xmlSGR "reverse"
- black = xmlSGR "black"
- red = xmlSGR "red"
- green = xmlSGR "green"
- yellow = xmlSGR "yellow"
- blue = xmlSGR "blue"
- magenta = xmlSGR "magenta"
- cyan = xmlSGR "cyan"
- white = xmlSGR "white"
- blacker = xmlSGR "blacker"
- redder = xmlSGR "redder"
- greener = xmlSGR "greener"
- yellower = xmlSGR "yellower"
- bluer = xmlSGR "bluer"
- magentaer = xmlSGR "magentaer"
- cyaner = xmlSGR "cyaner"
- whiter = xmlSGR "whiter"
- onBlack = xmlSGR "onBlack"
- onRed = xmlSGR "onRed"
- onGreen = xmlSGR "onGreen"
- onYellow = xmlSGR "onYellow"
- onBlue = xmlSGR "onBlue"
- onMagenta = xmlSGR "onMagenta"
- onCyan = xmlSGR "onCyan"
- onWhite = xmlSGR "onWhite"
- onBlacker = xmlSGR "onBlacker"
- onRedder = xmlSGR "onRedder"
- onGreener = xmlSGR "onGreener"
- onYellower = xmlSGR "onYellower"
- onBluer = xmlSGR "onBluer"
- onMagentaer = xmlSGR "onMagentaer"
- onCyaner = xmlSGR "onCyaner"
- onWhiter = xmlSGR "onWhiter"
+ reverse = xmlSGR "reverse"
+ black = xmlSGR "black"
+ red = xmlSGR "red"
+ green = xmlSGR "green"
+ yellow = xmlSGR "yellow"
+ blue = xmlSGR "blue"
+ magenta = xmlSGR "magenta"
+ cyan = xmlSGR "cyan"
+ white = xmlSGR "white"
+ blacker = xmlSGR "blacker"
+ redder = xmlSGR "redder"
+ greener = xmlSGR "greener"
+ yellower = xmlSGR "yellower"
+ bluer = xmlSGR "bluer"
+ magentaer = xmlSGR "magentaer"
+ cyaner = xmlSGR "cyaner"
+ whiter = xmlSGR "whiter"
+ onBlack = xmlSGR "onBlack"
+ onRed = xmlSGR "onRed"
+ onGreen = xmlSGR "onGreen"
+ onYellow = xmlSGR "onYellow"
+ onBlue = xmlSGR "onBlue"
+ onMagenta = xmlSGR "onMagenta"
+ onCyan = xmlSGR "onCyan"
+ onWhite = xmlSGR "onWhite"
+ onBlacker = xmlSGR "onBlacker"
+ onRedder = xmlSGR "onRedder"
+ onGreener = xmlSGR "onGreener"
+ onYellower = xmlSGR "onYellower"
+ onBluer = xmlSGR "onBluer"
+ onMagentaer = xmlSGR "onMagentaer"
+ onCyaner = xmlSGR "onCyaner"
+ onWhiter = xmlSGR "onWhiter"
-- | For debugging purposes.
xmlSGR :: Semigroup d => From String d => String -> d -> d
-- * Class 'Indentable'
class Spaceable d => Indentable d where
- -- | @('align' d)@ make @d@ uses current 'Column' as 'Indent' level.
- align :: d -> d
- -- | @('setIndent' p ind d)@ make @d@ uses @ind@ as 'Indent' level.
- -- Using @p@ as 'Indent' text.
- setIndent :: d -> Indent -> d -> d
- -- | @('incrIndent' p ind d)@ make @d@ uses current 'Indent' plus @ind@ as 'Indent' level.
- -- Appending @p@ to the current 'Indent' text.
- incrIndent :: d -> Indent -> d -> d
- hang :: Indent -> d -> d
- hang ind = align . incrIndent (spaces ind) ind
- -- | @('fill' w d)@ write @d@,
- -- then if @d@ is not wider than @w@,
- -- write the difference with 'spaces'.
- fill :: Width -> d -> d
- -- | @('fillOrBreak' w d)@ write @d@,
- -- then if @d@ is not wider than @w@, write the difference with 'spaces'
- -- otherwise write a 'newline' indented to to the start 'Column' of @d@ plus @w@.
- fillOrBreak :: Width -> d -> d
-
- default align :: Indentable (UnTrans d) => Trans d => d -> d
- default incrIndent :: Indentable (UnTrans d) => Trans d => d -> Indent -> d -> d
- default setIndent :: Indentable (UnTrans d) => Trans d => d -> Indent -> d -> d
- default fill :: Indentable (UnTrans d) => Trans d => Width -> d -> d
- default fillOrBreak :: Indentable (UnTrans d) => Trans d => Width -> d -> d
-
- align = noTrans1 align
- setIndent p i = noTrans . setIndent (unTrans p) i . unTrans
- incrIndent p i = noTrans . incrIndent (unTrans p) i . unTrans
- fill = noTrans1 . fill
- fillOrBreak = noTrans1 . fillOrBreak
+ -- | @('align' d)@ make @d@ uses current 'Column' as 'Indent' level.
+ align :: d -> d
+ -- | @('setIndent' p ind d)@ make @d@ uses @ind@ as 'Indent' level.
+ -- Using @p@ as 'Indent' text.
+ setIndent :: d -> Indent -> d -> d
+ -- | @('incrIndent' p ind d)@ make @d@ uses current 'Indent' plus @ind@ as 'Indent' level.
+ -- Appending @p@ to the current 'Indent' text.
+ incrIndent :: d -> Indent -> d -> d
+ hang :: Indent -> d -> d
+ hang ind = align . incrIndent (spaces ind) ind
+ -- | @('fill' w d)@ write @d@,
+ -- then if @d@ is not wider than @w@,
+ -- write the difference with 'spaces'.
+ fill :: Width -> d -> d
+ -- | @('fillOrBreak' w d)@ write @d@,
+ -- then if @d@ is not wider than @w@, write the difference with 'spaces'
+ -- otherwise write a 'newline' indented to to the start 'Column' of @d@ plus @w@.
+ fillOrBreak :: Width -> d -> d
+
+ default align :: Indentable (UnTrans d) => Trans d => d -> d
+ default incrIndent :: Indentable (UnTrans d) => Trans d => d -> Indent -> d -> d
+ default setIndent :: Indentable (UnTrans d) => Trans d => d -> Indent -> d -> d
+ default fill :: Indentable (UnTrans d) => Trans d => Width -> d -> d
+ default fillOrBreak :: Indentable (UnTrans d) => Trans d => Width -> d -> d
+
+ align = noTrans1 align
+ setIndent p i = noTrans . setIndent (unTrans p) i . unTrans
+ incrIndent p i = noTrans . incrIndent (unTrans p) i . unTrans
+ fill = noTrans1 . fill
+ fillOrBreak = noTrans1 . fillOrBreak
class Listable d where
- ul :: Traversable f => f d -> d
- ol :: Traversable f => f d -> d
- default ul ::
- Listable (UnTrans d) => Trans d =>
- Traversable f => f d -> d
- default ol ::
- Listable (UnTrans d) => Trans d =>
- Traversable f => f d -> d
- ul ds = noTrans $ ul $ unTrans <$> ds
- ol ds = noTrans $ ol $ unTrans <$> ds
+ ul :: Traversable f => f d -> d
+ ol :: Traversable f => f d -> d
+ default ul ::
+ Listable (UnTrans d) => Trans d =>
+ Traversable f => f d -> d
+ default ol ::
+ Listable (UnTrans d) => Trans d =>
+ Traversable f => f d -> d
+ ul ds = noTrans $ ul $ unTrans <$> ds
+ ol ds = noTrans $ ol $ unTrans <$> ds
-- * Class 'Wrappable'
class Wrappable d where
- setWidth :: Maybe Width -> d -> d
- -- getWidth :: (Maybe Width -> d) -> d
- breakpoint :: d
- breakspace :: d
- breakalt :: d -> d -> d
- endline :: d
- default breakpoint :: Wrappable (UnTrans d) => Trans d => d
- default breakspace :: Wrappable (UnTrans d) => Trans d => d
- default breakalt :: Wrappable (UnTrans d) => Trans d => d -> d -> d
- default endline :: Wrappable (UnTrans d) => Trans d => d
- breakpoint = noTrans breakpoint
- breakspace = noTrans breakspace
- breakalt = noTrans2 breakalt
- endline = noTrans endline
+ setWidth :: Maybe Width -> d -> d
+ -- getWidth :: (Maybe Width -> d) -> d
+ breakpoint :: d
+ breakspace :: d
+ breakalt :: d -> d -> d
+ endline :: d
+ default breakpoint :: Wrappable (UnTrans d) => Trans d => d
+ default breakspace :: Wrappable (UnTrans d) => Trans d => d
+ default breakalt :: Wrappable (UnTrans d) => Trans d => d -> d -> d
+ default endline :: Wrappable (UnTrans d) => Trans d => d
+ breakpoint = noTrans breakpoint
+ breakspace = noTrans breakspace
+ breakalt = noTrans2 breakalt
+ endline = noTrans endline
-- * Class 'Justifiable'
class Justifiable d where
- justify :: d -> d
+ justify :: d -> d
-- * Class 'Trans'
class Trans repr where
- -- | Return the underlying @repr@ of the transformer.
- type UnTrans repr :: Type
-
- -- | Lift a repr to the transformer's.
- noTrans :: UnTrans repr -> repr
- -- | Unlift a repr from the transformer's.
- unTrans :: repr -> UnTrans repr
-
- -- | Identity transformation for a unary symantic method.
- noTrans1 :: (UnTrans repr -> UnTrans repr) -> (repr -> repr)
- noTrans1 f = noTrans . f . unTrans
-
- -- | Identity transformation for a binary symantic method.
- noTrans2
- :: (UnTrans repr -> UnTrans repr -> UnTrans repr)
- -> (repr -> repr -> repr)
- noTrans2 f a b = noTrans (f (unTrans a) (unTrans b))
-
- -- | Identity transformation for a ternary symantic method.
- noTrans3
- :: (UnTrans repr -> UnTrans repr -> UnTrans repr -> UnTrans repr)
- -> (repr -> repr -> repr -> repr)
- noTrans3 f a b c = noTrans (f (unTrans a) (unTrans b) (unTrans c))
+ -- | Return the underlying @repr@ of the transformer.
+ type UnTrans repr :: Type
+
+ -- | Lift a repr to the transformer's.
+ noTrans :: UnTrans repr -> repr
+ -- | Unlift a repr from the transformer's.
+ unTrans :: repr -> UnTrans repr
+
+ -- | Identity transformation for a unary symantic method.
+ noTrans1 :: (UnTrans repr -> UnTrans repr) -> (repr -> repr)
+ noTrans1 f = noTrans . f . unTrans
+
+ -- | Identity transformation for a binary symantic method.
+ noTrans2
+ :: (UnTrans repr -> UnTrans repr -> UnTrans repr)
+ -> (repr -> repr -> repr)
+ noTrans2 f a b = noTrans (f (unTrans a) (unTrans b))
+
+ -- | Identity transformation for a ternary symantic method.
+ noTrans3
+ :: (UnTrans repr -> UnTrans repr -> UnTrans repr -> UnTrans repr)
+ -> (repr -> repr -> repr -> repr)
+ noTrans3 f a b c = noTrans (f (unTrans a) (unTrans b) (unTrans c))
-- ReaderT PlainInh (StateT (PlainState d) (Cont (PlainFit d))) (d->d)
}
instance (Show d, Spaceable d) => Show (Plain d) where
- show = show . runPlain
+ show = show . runPlain
runPlain :: Spaceable d => Plain d -> d
runPlain x =
- unPlain x
- defPlainInh
- defPlainState
- {-k-}(\(px,_sx) fits _overflow ->
- -- NOTE: if px fits, then appending mempty fits
- fits (px mempty) )
- {-fits-}id
- {-overflow-}id
+ unPlain x
+ defPlainInh
+ defPlainState
+ {-k-}(\(px,_sx) fits _overflow ->
+ -- NOTE: if px fits, then appending mempty fits
+ fits (px mempty) )
+ {-fits-}id
+ {-overflow-}id
-- ** Type 'PlainState'
data PlainState d = PlainState
-- ^ 'spaces' preserved to be interleaved
-- correctly with 'PlainChunk_Ignored'.
instance Show d => Show (PlainChunk d) where
- showsPrec p x =
- showParen (p>10) $
- case x of
- PlainChunk_Ignored d ->
- showString "Z " .
- showsPrec 11 d
- PlainChunk_Word (Word d) ->
- showString "W " .
- showsPrec 11 d
- PlainChunk_Spaces s ->
- showString "S " .
- showsPrec 11 s
+ showsPrec p x =
+ showParen (p>10) $
+ case x of
+ PlainChunk_Ignored d ->
+ showString "Z " .
+ showsPrec 11 d
+ PlainChunk_Word (Word d) ->
+ showString "W " .
+ showsPrec 11 d
+ PlainChunk_Spaces s ->
+ showString "S " .
+ showsPrec 11 s
instance Lengthable d => Lengthable (PlainChunk d) where
- width = \case
- PlainChunk_Ignored{} -> 0
- PlainChunk_Word d -> width d
- PlainChunk_Spaces s -> s
- nullWidth = \case
- PlainChunk_Ignored{} -> True
- PlainChunk_Word d -> nullWidth d
- PlainChunk_Spaces s -> s == 0
+ width = \case
+ PlainChunk_Ignored{} -> 0
+ PlainChunk_Word d -> width d
+ PlainChunk_Spaces s -> s
+ nullWidth = \case
+ PlainChunk_Ignored{} -> True
+ PlainChunk_Word d -> nullWidth d
+ PlainChunk_Spaces s -> s == 0
instance From [SGR] d => From [SGR] (PlainChunk d) where
- from sgr = PlainChunk_Ignored (from sgr)
+ from sgr = PlainChunk_Ignored (from sgr)
runPlainChunk :: Spaceable d => PlainChunk d -> d
runPlainChunk = \case
PlainChunk_Spaces s -> spaces s
instance Semigroup d => Semigroup (Plain d) where
- Plain x <> Plain y = Plain $ \inh st k ->
- x inh st $ \(px,sx) ->
- y inh sx $ \(py,sy) ->
- k (px.py,sy)
+ Plain x <> Plain y = Plain $ \inh st k ->
+ x inh st $ \(px,sx) ->
+ y inh sx $ \(py,sy) ->
+ k (px.py,sy)
instance Monoid d => Monoid (Plain d) where
- mempty = Plain $ \_inh st k -> k (id,st)
- mappend = (<>)
+ mempty = Plain $ \_inh st k -> k (id,st)
+ mappend = (<>)
instance Spaceable d => Spaceable (Plain d) where
- -- | The default 'newline' does not justify 'plainState_buffer',
- -- for that use 'newlineJustifyingPlain'.
- newline = Plain $ \inh st ->
- unPlain
- ( newlinePlain
- <> indentPlain
- <> propagatePlain (plainState_breakIndent st)
- <> flushlinePlain
- ) inh st
- where
- indentPlain = Plain $ \inh ->
- unPlain
- (plainInh_indenting inh)
- inh{plainInh_justify=False}
- newlinePlain = Plain $ \inh st k ->
- k (\next ->
- (if plainInh_justify inh
- then joinLinePlainChunk $ List.reverse $ plainState_buffer st
- else mempty
- )<>newline<>next
- , st
- { plainState_bufferStart = 0
- , plainState_bufferWidth = 0
- , plainState_buffer = mempty
- })
- propagatePlain breakIndent = Plain $ \inh st1 k fits overflow ->
- k (id,st1)
- fits
- {-overflow-}(
- -- NOTE: the text after this newline overflows,
- -- so propagate the overflow before this 'newline',
- -- if and only if there is a 'breakspace' before this 'newline'
- -- whose replacement by a 'newline' indents to a lower indent
- -- than this 'newline''s indent.
- -- Otherwise there is no point in propagating the overflow.
- if breakIndent < plainInh_indent inh
- then overflow
- else fits
- )
- space = spaces 1
- spaces n = Plain $ \inh st@PlainState{..} k fits overflow ->
- let newWidth = plainState_bufferStart + plainState_bufferWidth + n in
- if plainInh_justify inh
- then
- let newState = st
- { plainState_buffer =
- case plainState_buffer of
- PlainChunk_Spaces s:buf -> PlainChunk_Spaces (s+n):buf
- buf -> PlainChunk_Spaces n:buf
- , plainState_bufferWidth = plainState_bufferWidth + n
- } in
- case plainInh_width inh of
- Just maxWidth | maxWidth < newWidth ->
- overflow $ k (id{-(d<>)-}, newState) fits overflow
- _ -> k (id{-(d<>)-}, newState) fits overflow
- else
- let newState = st
- { plainState_bufferWidth = plainState_bufferWidth + n
- } in
- case plainInh_width inh of
- Just maxWidth | maxWidth < newWidth ->
- overflow $ k ((spaces n <>), newState) fits fits
- _ -> k ((spaces n <>), newState) fits overflow
+ -- | The default 'newline' does not justify 'plainState_buffer',
+ -- for that use 'newlineJustifyingPlain'.
+ newline = Plain $ \inh st ->
+ unPlain
+ ( newlinePlain
+ <> indentPlain
+ <> propagatePlain (plainState_breakIndent st)
+ <> flushlinePlain
+ ) inh st
+ where
+ indentPlain = Plain $ \inh ->
+ unPlain
+ (plainInh_indenting inh)
+ inh{plainInh_justify=False}
+ newlinePlain = Plain $ \inh st k ->
+ k (\next ->
+ (if plainInh_justify inh
+ then joinLinePlainChunk $ List.reverse $ plainState_buffer st
+ else mempty
+ )<>newline<>next
+ , st
+ { plainState_bufferStart = 0
+ , plainState_bufferWidth = 0
+ , plainState_buffer = mempty
+ })
+ propagatePlain breakIndent = Plain $ \inh st1 k fits overflow ->
+ k (id,st1)
+ fits
+ {-overflow-}(
+ -- NOTE: the text after this newline overflows,
+ -- so propagate the overflow before this 'newline',
+ -- if and only if there is a 'breakspace' before this 'newline'
+ -- whose replacement by a 'newline' indents to a lower indent
+ -- than this 'newline''s indent.
+ -- Otherwise there is no point in propagating the overflow.
+ if breakIndent < plainInh_indent inh
+ then overflow
+ else fits
+ )
+ space = spaces 1
+ spaces n = Plain $ \inh st@PlainState{..} k fits overflow ->
+ let newWidth = plainState_bufferStart + plainState_bufferWidth + n in
+ if plainInh_justify inh
+ then
+ let newState = st
+ { plainState_buffer =
+ case plainState_buffer of
+ PlainChunk_Spaces s:buf -> PlainChunk_Spaces (s+n):buf
+ buf -> PlainChunk_Spaces n:buf
+ , plainState_bufferWidth = plainState_bufferWidth + n
+ } in
+ case plainInh_width inh of
+ Just maxWidth | maxWidth < newWidth ->
+ overflow $ k (id{-(d<>)-}, newState) fits overflow
+ _ -> k (id{-(d<>)-}, newState) fits overflow
+ else
+ let newState = st
+ { plainState_bufferWidth = plainState_bufferWidth + n
+ } in
+ case plainInh_width inh of
+ Just maxWidth | maxWidth < newWidth ->
+ overflow $ k ((spaces n <>), newState) fits fits
+ _ -> k ((spaces n <>), newState) fits overflow
instance (From (Word s) d, Semigroup d, Lengthable s) =>
From (Word s) (Plain d) where
- from s = Plain $ \inh st@PlainState{..} k fits overflow ->
- let wordWidth = width s in
- if wordWidth <= 0
- then k (id,st) fits overflow
- else
- let newBufferWidth = plainState_bufferWidth + wordWidth in
- let newWidth = plainState_bufferStart + newBufferWidth in
- if plainInh_justify inh
- then
- let newState = st
- { plainState_buffer =
- PlainChunk_Word (Word (from s)) :
- plainState_buffer
- , plainState_bufferWidth = newBufferWidth
- } in
- case plainInh_width inh of
- Just maxWidth | maxWidth < newWidth ->
- overflow $ k (id, newState) fits overflow
- _ -> k (id, newState) fits overflow
- else
- let newState = st
- { plainState_bufferWidth = newBufferWidth
- } in
- case plainInh_width inh of
- Just maxWidth | maxWidth < newWidth ->
- overflow $ k ((from s <>), newState) fits fits
- _ -> k ((from s <>), newState) fits overflow
+ from s = Plain $ \inh st@PlainState{..} k fits overflow ->
+ let wordWidth = width s in
+ if wordWidth <= 0
+ then k (id,st) fits overflow
+ else
+ let newBufferWidth = plainState_bufferWidth + wordWidth in
+ let newWidth = plainState_bufferStart + newBufferWidth in
+ if plainInh_justify inh
+ then
+ let newState = st
+ { plainState_buffer =
+ PlainChunk_Word (Word (from s)) :
+ plainState_buffer
+ , plainState_bufferWidth = newBufferWidth
+ } in
+ case plainInh_width inh of
+ Just maxWidth | maxWidth < newWidth ->
+ overflow $ k (id, newState) fits overflow
+ _ -> k (id, newState) fits overflow
+ else
+ let newState = st
+ { plainState_bufferWidth = newBufferWidth
+ } in
+ case plainInh_width inh of
+ Just maxWidth | maxWidth < newWidth ->
+ overflow $ k ((from s <>), newState) fits fits
+ _ -> k ((from s <>), newState) fits overflow
instance (From (Word s) d, Lengthable s, Spaceable d, Splitable s) =>
From (Line s) (Plain d) where
- from =
- mconcat .
- List.intersperse breakspace .
- (from <$>) .
- words .
- unLine
+ from =
+ mconcat .
+ List.intersperse breakspace .
+ (from <$>) .
+ words .
+ unLine
instance Spaceable d => Indentable (Plain d) where
- align p = (flushlinePlain <>) $ Plain $ \inh st ->
- let col = plainState_bufferStart st + plainState_bufferWidth st in
- unPlain p inh
- { plainInh_indent = col
- , plainInh_indenting =
- if plainInh_indent inh <= col
- then
- plainInh_indenting inh <>
- spaces (col`minusNatural`plainInh_indent inh)
- else spaces col
- } st
- setIndent d i p = Plain $ \inh ->
- unPlain p inh
- { plainInh_indent = i
- , plainInh_indenting = d
- }
- incrIndent d i p = Plain $ \inh ->
- unPlain p inh
- { plainInh_indent = plainInh_indent inh + i
- , plainInh_indenting = plainInh_indenting inh <> d
- }
-
- fill m p = Plain $ \inh0 st0 ->
- let maxCol = plainState_bufferStart st0 + plainState_bufferWidth st0 + m in
- let p1 = Plain $ \inh1 st1 ->
- let col = plainState_bufferStart st1 + plainState_bufferWidth st1 in
- unPlain
- (if col <= maxCol
- then spaces (maxCol`minusNatural`col)
- else mempty)
- inh1 st1
- in
- unPlain (p <> p1) inh0 st0
- fillOrBreak m p = Plain $ \inh0 st0 ->
- let maxCol = plainState_bufferStart st0 + plainState_bufferWidth st0 + m in
- let p1 = Plain $ \inh1 st1 ->
- let col = plainState_bufferStart st1 + plainState_bufferWidth st1 in
- unPlain
- (case col`compare`maxCol of
- LT -> spaces (maxCol`minusNatural`col)
- EQ -> mempty
- GT -> incrIndent (spaces m) m newline
- ) inh1 st1
- in
- unPlain (p <> p1) inh0 st0
+ align p = (flushlinePlain <>) $ Plain $ \inh st ->
+ let col = plainState_bufferStart st + plainState_bufferWidth st in
+ unPlain p inh
+ { plainInh_indent = col
+ , plainInh_indenting =
+ if plainInh_indent inh <= col
+ then
+ plainInh_indenting inh <>
+ spaces (col`minusNatural`plainInh_indent inh)
+ else spaces col
+ } st
+ setIndent d i p = Plain $ \inh ->
+ unPlain p inh
+ { plainInh_indent = i
+ , plainInh_indenting = d
+ }
+ incrIndent d i p = Plain $ \inh ->
+ unPlain p inh
+ { plainInh_indent = plainInh_indent inh + i
+ , plainInh_indenting = plainInh_indenting inh <> d
+ }
+
+ fill m p = Plain $ \inh0 st0 ->
+ let maxCol = plainState_bufferStart st0 + plainState_bufferWidth st0 + m in
+ let p1 = Plain $ \inh1 st1 ->
+ let col = plainState_bufferStart st1 + plainState_bufferWidth st1 in
+ unPlain
+ (if col <= maxCol
+ then spaces (maxCol`minusNatural`col)
+ else mempty)
+ inh1 st1
+ in
+ unPlain (p <> p1) inh0 st0
+ fillOrBreak m p = Plain $ \inh0 st0 ->
+ let maxCol = plainState_bufferStart st0 + plainState_bufferWidth st0 + m in
+ let p1 = Plain $ \inh1 st1 ->
+ let col = plainState_bufferStart st1 + plainState_bufferWidth st1 in
+ unPlain
+ (case col`compare`maxCol of
+ LT -> spaces (maxCol`minusNatural`col)
+ EQ -> mempty
+ GT -> incrIndent (spaces m) m newline
+ ) inh1 st1
+ in
+ unPlain (p <> p1) inh0 st0
instance (Spaceable d, From (Word Char) d, From (Word String) d) => Listable (Plain d) where
- ul ds =
- catV $
- (<$> ds) $ \d ->
- from (Word '-')<>space<>flushlinePlain<>align d{-<>flushlinePlain-}
- ol ds =
- catV $ snd $
- Fold.foldr
- (\d (i, acc) ->
- (pred i, (from i<>from (Word '.')<>space<>flushlinePlain<>align d{-<>flushlinePlain-}) : acc)
- ) (Fold.length ds, []) ds
+ ul ds =
+ catV $
+ (<$> ds) $ \d ->
+ from (Word '-')<>space<>flushlinePlain<>align d{-<>flushlinePlain-}
+ ol ds =
+ catV $ snd $
+ Fold.foldr
+ (\d (i, acc) ->
+ (pred i, (from i<>from (Word '.')<>space<>flushlinePlain<>align d{-<>flushlinePlain-}) : acc)
+ ) (Fold.length ds, []) ds
instance Spaceable d => Justifiable (Plain d) where
- justify p = (\x -> flushlinePlain <> x <> flushlinePlain) $ Plain $ \inh ->
- unPlain p inh{plainInh_justify=True}
+ justify p = (\x -> flushlinePlain <> x <> flushlinePlain) $ Plain $ \inh ->
+ unPlain p inh{plainInh_justify=True}
-- | Commit 'plainState_buffer' upto there, so that it won't be justified.
flushlinePlain :: Spaceable d => Plain d
flushlinePlain = Plain $ \_inh st k ->
- k( (joinLinePlainChunk (collapsePlainChunkSpaces <$> List.reverse (plainState_buffer st)) <>)
- , st
- { plainState_bufferStart = plainState_bufferStart st + plainState_bufferWidth st
- , plainState_bufferWidth = 0
- , plainState_buffer = mempty
- }
- )
+ k( (joinLinePlainChunk (collapsePlainChunkSpaces <$> List.reverse (plainState_buffer st)) <>)
+ , st
+ { plainState_bufferStart = plainState_bufferStart st + plainState_bufferWidth st
+ , plainState_bufferWidth = 0
+ , plainState_buffer = mempty
+ }
+ )
collapsePlainChunkSpaces :: PlainChunk d -> PlainChunk d
collapsePlainChunkSpaces = \case
x -> x
instance Spaceable d => Wrappable (Plain d) where
- setWidth w p = Plain $ \inh ->
- unPlain p inh{plainInh_width=w}
- breakpoint = Plain $ \inh st k fits overflow ->
- k(id, st {plainState_breakIndent = plainInh_indent inh})
- fits
- {-overflow-}(\_r -> unPlain newlineJustifyingPlain inh st k fits overflow)
- breakspace = Plain $ \inh st k fits overflow ->
- k( if plainInh_justify inh then id else (space <>)
- , st
- { plainState_buffer =
- if plainInh_justify inh
- then case plainState_buffer st of
- PlainChunk_Spaces s:bs -> PlainChunk_Spaces (s+1):bs
- bs -> PlainChunk_Spaces 1:bs
- else plainState_buffer st
- , plainState_bufferWidth = plainState_bufferWidth st + 1
- , plainState_breakIndent = plainInh_indent inh
- }
- )
- fits
- {-overflow-}(\_r -> unPlain newlineJustifyingPlain inh st k fits overflow)
- breakalt x y = Plain $ \inh st k fits overflow ->
- -- NOTE: breakalt must be y if and only if x does not fit,
- -- hence the use of dummyK to limit the test
- -- to overflows raised within x, and drop those raised after x.
- unPlain x inh st dummyK
- {-fits-} (\_r -> unPlain x inh st k fits overflow)
- {-overflow-}(\_r -> unPlain y inh st k fits overflow)
- where
- dummyK (px,_sx) fits _overflow =
- -- NOTE: if px fits, then appending mempty fits
- fits (px mempty)
- endline = Plain $ \inh st k fits _overflow ->
- let col = plainState_bufferStart st + plainState_bufferWidth st in
- case plainInh_width inh >>= (`minusNaturalMaybe` col) of
- Nothing -> k (id, st) fits fits
- Just w ->
- let newState = st
- { plainState_bufferWidth = plainState_bufferWidth st + w
- } in
- k (id,newState) fits fits
+ setWidth w p = Plain $ \inh ->
+ unPlain p inh{plainInh_width=w}
+ breakpoint = Plain $ \inh st k fits overflow ->
+ k(id, st {plainState_breakIndent = plainInh_indent inh})
+ fits
+ {-overflow-}(\_r -> unPlain newlineJustifyingPlain inh st k fits overflow)
+ breakspace = Plain $ \inh st k fits overflow ->
+ k( if plainInh_justify inh then id else (space <>)
+ , st
+ { plainState_buffer =
+ if plainInh_justify inh
+ then case plainState_buffer st of
+ PlainChunk_Spaces s:bs -> PlainChunk_Spaces (s+1):bs
+ bs -> PlainChunk_Spaces 1:bs
+ else plainState_buffer st
+ , plainState_bufferWidth = plainState_bufferWidth st + 1
+ , plainState_breakIndent = plainInh_indent inh
+ }
+ )
+ fits
+ {-overflow-}(\_r -> unPlain newlineJustifyingPlain inh st k fits overflow)
+ breakalt x y = Plain $ \inh st k fits overflow ->
+ -- NOTE: breakalt must be y if and only if x does not fit,
+ -- hence the use of dummyK to limit the test
+ -- to overflows raised within x, and drop those raised after x.
+ unPlain x inh st dummyK
+ {-fits-} (\_r -> unPlain x inh st k fits overflow)
+ {-overflow-}(\_r -> unPlain y inh st k fits overflow)
+ where
+ dummyK (px,_sx) fits _overflow =
+ -- NOTE: if px fits, then appending mempty fits
+ fits (px mempty)
+ endline = Plain $ \inh st k fits _overflow ->
+ let col = plainState_bufferStart st + plainState_bufferWidth st in
+ case plainInh_width inh >>= (`minusNaturalMaybe` col) of
+ Nothing -> k (id, st) fits fits
+ Just w ->
+ let newState = st
+ { plainState_bufferWidth = plainState_bufferWidth st + w
+ } in
+ k (id,newState) fits fits
-- | Like 'newline', but justify 'plainState_buffer' before.
newlineJustifyingPlain :: Spaceable d => Plain d
newlineJustifyingPlain = Plain $ \inh st ->
- unPlain
- ( newlinePlain
- <> indentPlain
- <> propagatePlain (plainState_breakIndent st)
- <> flushlinePlain
- ) inh st
- where
- indentPlain = Plain $ \inh ->
- unPlain
- (plainInh_indenting inh)
- inh{plainInh_justify=False}
- newlinePlain = Plain $ \inh st k ->
- k (\next ->
- (if plainInh_justify inh
- then justifyLinePlain inh st
- else mempty
- )<>newline<>next
- , st
- { plainState_bufferStart = 0
- , plainState_bufferWidth = 0
- , plainState_buffer = mempty
- })
- propagatePlain breakIndent = Plain $ \inh st1 k fits overflow ->
- k (id,st1)
- fits
- {-overflow-}(
- -- NOTE: the text after this newline overflows,
- -- so propagate the overflow before this 'newline',
- -- if and only if there is a 'breakspace' before this 'newline'
- -- whose replacement by a 'newline' indents to a lower indent
- -- than this 'newline''s indent.
- -- Otherwise there is no point in propagating the overflow.
- if breakIndent < plainInh_indent inh
- then overflow
- else fits
- )
+ unPlain
+ ( newlinePlain
+ <> indentPlain
+ <> propagatePlain (plainState_breakIndent st)
+ <> flushlinePlain
+ ) inh st
+ where
+ indentPlain = Plain $ \inh ->
+ unPlain
+ (plainInh_indenting inh)
+ inh{plainInh_justify=False}
+ newlinePlain = Plain $ \inh st k ->
+ k (\next ->
+ (if plainInh_justify inh
+ then justifyLinePlain inh st
+ else mempty
+ )<>newline<>next
+ , st
+ { plainState_bufferStart = 0
+ , plainState_bufferWidth = 0
+ , plainState_buffer = mempty
+ })
+ propagatePlain breakIndent = Plain $ \inh st1 k fits overflow ->
+ k (id,st1)
+ fits
+ {-overflow-}(
+ -- NOTE: the text after this newline overflows,
+ -- so propagate the overflow before this 'newline',
+ -- if and only if there is a 'breakspace' before this 'newline'
+ -- whose replacement by a 'newline' indents to a lower indent
+ -- than this 'newline''s indent.
+ -- Otherwise there is no point in propagating the overflow.
+ if breakIndent < plainInh_indent inh
+ then overflow
+ else fits
+ )
-- String
instance (From (Word String) d, Spaceable d) =>
From String (Plain d) where
- from =
- mconcat .
- List.intersperse newline .
- (from <$>) .
- lines
+ from =
+ mconcat .
+ List.intersperse newline .
+ (from <$>) .
+ lines
instance (From (Word String) d, Spaceable d) =>
IsString (Plain d) where
- fromString = from
+ fromString = from
-- Text
instance (From (Word Text) d, Spaceable d) =>
From Text (Plain d) where
- from =
- mconcat .
- List.intersperse newline .
- (from <$>) .
- lines
+ from =
+ mconcat .
+ List.intersperse newline .
+ (from <$>) .
+ lines
instance (From (Word TL.Text) d, Spaceable d) =>
From TL.Text (Plain d) where
- from =
- mconcat .
- List.intersperse newline .
- (from <$>) .
- lines
+ from =
+ mconcat .
+ List.intersperse newline .
+ (from <$>) .
+ lines
-- Char
instance (From (Word Char) d, Spaceable d) =>
From Char (Plain d) where
- from ' ' = breakspace
- from '\n' = newline
- from c = from (Word c)
+ from ' ' = breakspace
+ from '\n' = newline
+ from c = from (Word c)
instance (From [SGR] d, Semigroup d) => From [SGR] (Plain d) where
- from sgr = Plain $ \inh st k ->
- if plainInh_justify inh
- then k (id, st {plainState_buffer = PlainChunk_Ignored (from sgr) : plainState_buffer st})
- else k ((from sgr <>), st)
+ from sgr = Plain $ \inh st k ->
+ if plainInh_justify inh
+ then k (id, st {plainState_buffer = PlainChunk_Ignored (from sgr) : plainState_buffer st})
+ else k ((from sgr <>), st)
-- * Justifying
justifyLinePlain ::
Spaceable d =>
PlainInh d -> PlainState d -> d
justifyLinePlain inh PlainState{..} =
- case plainInh_width inh of
- Nothing -> joinLinePlainChunk $ List.reverse plainState_buffer
- Just maxWidth ->
- if maxWidth < plainState_bufferStart
- || maxWidth < plainInh_indent inh
- then joinLinePlainChunk $ List.reverse plainState_buffer
- else
- let superfluousSpaces = Fold.foldr
- (\c acc ->
- acc + case c of
- PlainChunk_Ignored{} -> 0
- PlainChunk_Word{} -> 0
- PlainChunk_Spaces s -> s`minusNatural`(min 1 s))
- 0 plainState_buffer in
- let minBufferWidth =
- -- NOTE: cap the spaces at 1,
- -- to let justifyWidth decide where to add spaces.
- plainState_bufferWidth`minusNatural`superfluousSpaces in
- let justifyWidth =
- -- NOTE: when minBufferWidth is not breakable,
- -- the width of justification can be wider than
- -- what remains to reach maxWidth.
- max minBufferWidth $
- maxWidth`minusNatural`plainState_bufferStart
- in
- let wordCount = countWordsPlain plainState_buffer in
- unLine $ padLinePlainChunkInits justifyWidth $
- (minBufferWidth,wordCount,List.reverse plainState_buffer)
+ case plainInh_width inh of
+ Nothing -> joinLinePlainChunk $ List.reverse plainState_buffer
+ Just maxWidth ->
+ if maxWidth < plainState_bufferStart
+ || maxWidth < plainInh_indent inh
+ then joinLinePlainChunk $ List.reverse plainState_buffer
+ else
+ let superfluousSpaces = Fold.foldr
+ (\c acc ->
+ acc + case c of
+ PlainChunk_Ignored{} -> 0
+ PlainChunk_Word{} -> 0
+ PlainChunk_Spaces s -> s`minusNatural`(min 1 s))
+ 0 plainState_buffer in
+ let minBufferWidth =
+ -- NOTE: cap the spaces at 1,
+ -- to let justifyWidth decide where to add spaces.
+ plainState_bufferWidth`minusNatural`superfluousSpaces in
+ let justifyWidth =
+ -- NOTE: when minBufferWidth is not breakable,
+ -- the width of justification can be wider than
+ -- what remains to reach maxWidth.
+ max minBufferWidth $
+ maxWidth`minusNatural`plainState_bufferStart
+ in
+ let wordCount = countWordsPlain plainState_buffer in
+ unLine $ padLinePlainChunkInits justifyWidth $
+ (minBufferWidth,wordCount,List.reverse plainState_buffer)
-- | @('countWordsPlain' ps)@ returns the number of words in @(ps)@
-- clearly separated by spaces.
countWordsPlain :: [PlainChunk d] -> Natural
countWordsPlain = go False 0
where
- go inWord acc = \case
- [] -> acc
- PlainChunk_Word{}:xs ->
- if inWord
- then go inWord acc xs
- else go True (acc+1) xs
- PlainChunk_Spaces s:xs
- | s == 0 -> go inWord acc xs
- | otherwise -> go False acc xs
- PlainChunk_Ignored{}:xs -> go inWord acc xs
+ go inWord acc = \case
+ [] -> acc
+ PlainChunk_Word{}:xs ->
+ if inWord
+ then go inWord acc xs
+ else go True (acc+1) xs
+ PlainChunk_Spaces s:xs
+ | s == 0 -> go inWord acc xs
+ | otherwise -> go False acc xs
+ PlainChunk_Ignored{}:xs -> go inWord acc xs
-- | @('justifyPadding' a b)@ returns the padding lengths
-- to reach @(a)@ in @(b)@ pads,
-- @
justifyPadding :: Natural -> Natural -> [Natural]
justifyPadding a b = go r (b-r) -- NOTE: r >= 0 && b-r >= 0 due to 'divMod'
- where
- (q,r) = a`quotRemNatural`b
-
- go 0 bmr = List.replicate (fromIntegral bmr) q -- when min (b-r) r == b-r
- go rr 0 = List.replicate (fromIntegral rr) (q+1) -- when min (b-r) r == r
- go rr bmr = q:(q+1) : go (rr`minusNatural`1) (bmr`minusNatural`1)
+ where
+ (q,r) = a`quotRemNatural`b
+
+ go 0 bmr = List.replicate (fromIntegral bmr) q -- when min (b-r) r == b-r
+ go rr 0 = List.replicate (fromIntegral rr) (q+1) -- when min (b-r) r == r
+ go rr bmr = q:(q+1) : go (rr`minusNatural`1) (bmr`minusNatural`1)
padLinePlainChunkInits ::
Spaceable d =>
Width -> (Natural, Natural, [PlainChunk d]) -> Line d
padLinePlainChunkInits maxWidth (lineWidth,wordCount,line) = Line $
- if maxWidth <= lineWidth
- -- The gathered line reached or overreached the maxWidth,
- -- hence no padding id needed.
- || wordCount <= 1
- -- The case maxWidth <= lineWidth && wordCount == 1
- -- can happen if first word's length is < maxWidth
- -- but second word's len is >= maxWidth.
- then joinLinePlainChunk line
- else
- -- Share the missing spaces as evenly as possible
- -- between the words of the line.
- padLinePlainChunk line $ justifyPadding (maxWidth-lineWidth) (wordCount-1)
+ if maxWidth <= lineWidth
+ -- The gathered line reached or overreached the maxWidth,
+ -- hence no padding id needed.
+ || wordCount <= 1
+ -- The case maxWidth <= lineWidth && wordCount == 1
+ -- can happen if first word's length is < maxWidth
+ -- but second word's len is >= maxWidth.
+ then joinLinePlainChunk line
+ else
+ -- Share the missing spaces as evenly as possible
+ -- between the words of the line.
+ padLinePlainChunk line $ justifyPadding (maxWidth-lineWidth) (wordCount-1)
-- | Just concat 'PlainChunk's with no justification.
joinLinePlainChunk :: Monoid d => Spaceable d => [PlainChunk d] -> d
-- | Interleave 'PlainChunk's with 'Width's from 'justifyPadding'.
padLinePlainChunk :: Spaceable d => [PlainChunk d] -> [Width] -> d
padLinePlainChunk = go
- where
- go (w:ws) lls@(l:ls) =
- case w of
- PlainChunk_Spaces _s -> spaces (fromIntegral (l+1)) <> go ws ls
- _ -> runPlainChunk w <> go ws lls
- go (w:ws) [] = runPlainChunk w <> go ws []
- go [] _ls = mempty
+ where
+ go (w:ws) lls@(l:ls) =
+ case w of
+ PlainChunk_Spaces _s -> spaces (fromIntegral (l+1)) <> go ws ls
+ _ -> runPlainChunk w <> go ws lls
+ go (w:ws) [] = runPlainChunk w <> go ws []
+ go [] _ls = mempty
-- * Escaping
instance (Semigroup d, From [SGR] d) => Colorable16 (Plain d) where
- reverse = plainSGR $ SetSwapForegroundBackground True
- black = plainSGR $ SetColor Foreground Dull Black
- red = plainSGR $ SetColor Foreground Dull Red
- green = plainSGR $ SetColor Foreground Dull Green
- yellow = plainSGR $ SetColor Foreground Dull Yellow
- blue = plainSGR $ SetColor Foreground Dull Blue
- magenta = plainSGR $ SetColor Foreground Dull Magenta
- cyan = plainSGR $ SetColor Foreground Dull Cyan
- white = plainSGR $ SetColor Foreground Dull White
- blacker = plainSGR $ SetColor Foreground Vivid Black
- redder = plainSGR $ SetColor Foreground Vivid Red
- greener = plainSGR $ SetColor Foreground Vivid Green
- yellower = plainSGR $ SetColor Foreground Vivid Yellow
- bluer = plainSGR $ SetColor Foreground Vivid Blue
- magentaer = plainSGR $ SetColor Foreground Vivid Magenta
- cyaner = plainSGR $ SetColor Foreground Vivid Cyan
- whiter = plainSGR $ SetColor Foreground Vivid White
- onBlack = plainSGR $ SetColor Background Dull Black
- onRed = plainSGR $ SetColor Background Dull Red
- onGreen = plainSGR $ SetColor Background Dull Green
- onYellow = plainSGR $ SetColor Background Dull Yellow
- onBlue = plainSGR $ SetColor Background Dull Blue
- onMagenta = plainSGR $ SetColor Background Dull Magenta
- onCyan = plainSGR $ SetColor Background Dull Cyan
- onWhite = plainSGR $ SetColor Background Dull White
- onBlacker = plainSGR $ SetColor Background Vivid Black
- onRedder = plainSGR $ SetColor Background Vivid Red
- onGreener = plainSGR $ SetColor Background Vivid Green
- onYellower = plainSGR $ SetColor Background Vivid Yellow
- onBluer = plainSGR $ SetColor Background Vivid Blue
- onMagentaer = plainSGR $ SetColor Background Vivid Magenta
- onCyaner = plainSGR $ SetColor Background Vivid Cyan
- onWhiter = plainSGR $ SetColor Background Vivid White
+ reverse = plainSGR $ SetSwapForegroundBackground True
+ black = plainSGR $ SetColor Foreground Dull Black
+ red = plainSGR $ SetColor Foreground Dull Red
+ green = plainSGR $ SetColor Foreground Dull Green
+ yellow = plainSGR $ SetColor Foreground Dull Yellow
+ blue = plainSGR $ SetColor Foreground Dull Blue
+ magenta = plainSGR $ SetColor Foreground Dull Magenta
+ cyan = plainSGR $ SetColor Foreground Dull Cyan
+ white = plainSGR $ SetColor Foreground Dull White
+ blacker = plainSGR $ SetColor Foreground Vivid Black
+ redder = plainSGR $ SetColor Foreground Vivid Red
+ greener = plainSGR $ SetColor Foreground Vivid Green
+ yellower = plainSGR $ SetColor Foreground Vivid Yellow
+ bluer = plainSGR $ SetColor Foreground Vivid Blue
+ magentaer = plainSGR $ SetColor Foreground Vivid Magenta
+ cyaner = plainSGR $ SetColor Foreground Vivid Cyan
+ whiter = plainSGR $ SetColor Foreground Vivid White
+ onBlack = plainSGR $ SetColor Background Dull Black
+ onRed = plainSGR $ SetColor Background Dull Red
+ onGreen = plainSGR $ SetColor Background Dull Green
+ onYellow = plainSGR $ SetColor Background Dull Yellow
+ onBlue = plainSGR $ SetColor Background Dull Blue
+ onMagenta = plainSGR $ SetColor Background Dull Magenta
+ onCyan = plainSGR $ SetColor Background Dull Cyan
+ onWhite = plainSGR $ SetColor Background Dull White
+ onBlacker = plainSGR $ SetColor Background Vivid Black
+ onRedder = plainSGR $ SetColor Background Vivid Red
+ onGreener = plainSGR $ SetColor Background Vivid Green
+ onYellower = plainSGR $ SetColor Background Vivid Yellow
+ onBluer = plainSGR $ SetColor Background Vivid Blue
+ onMagentaer = plainSGR $ SetColor Background Vivid Magenta
+ onCyaner = plainSGR $ SetColor Background Vivid Cyan
+ onWhiter = plainSGR $ SetColor Background Vivid White
instance (Semigroup d, From [SGR] d) => Decorable (Plain d) where
- bold = plainSGR $ SetConsoleIntensity BoldIntensity
- underline = plainSGR $ SetUnderlining SingleUnderline
- italic = plainSGR $ SetItalicized True
+ bold = plainSGR $ SetConsoleIntensity BoldIntensity
+ underline = plainSGR $ SetUnderlining SingleUnderline
+ italic = plainSGR $ SetItalicized True
plainSGR ::
Semigroup d =>
From [SGR] d =>
SGR -> Plain d -> Plain d
plainSGR newSGR p = before <> middle <> after
- where
- before = Plain $ \inh st k ->
- let d = from [newSGR] in
- if plainInh_justify inh
- then k (id, st
- { plainState_buffer =
- PlainChunk_Ignored d :
- plainState_buffer st
- })
- else k ((d <>), st)
- middle = Plain $ \inh ->
- unPlain p inh{plainInh_sgr=newSGR:plainInh_sgr inh}
- after = Plain $ \inh st k ->
- let d = from $ Reset : List.reverse (plainInh_sgr inh) in
- if plainInh_justify inh
- then k (id, st
- { plainState_buffer =
- PlainChunk_Ignored d :
- plainState_buffer st
- })
- else k ((d <>), st)
+ where
+ before = Plain $ \inh st k ->
+ let d = from [newSGR] in
+ if plainInh_justify inh
+ then k (id, st
+ { plainState_buffer =
+ PlainChunk_Ignored d :
+ plainState_buffer st
+ })
+ else k ((d <>), st)
+ middle = Plain $ \inh ->
+ unPlain p inh{plainInh_sgr=newSGR:plainInh_sgr inh}
+ after = Plain $ \inh st k ->
+ let d = from $ Reset : List.reverse (plainInh_sgr inh) in
+ if plainInh_justify inh
+ then k (id, st
+ { plainState_buffer =
+ PlainChunk_Ignored d :
+ plainState_buffer st
+ })
+ else k ((d <>), st)