-- | This module defines the 'Block' data type. module CabalGild.Unstable.Type.Block where import qualified CabalGild.Unstable.Type.Line as Line import qualified Data.ByteString as ByteString import qualified Distribution.Compat.Lens as Lens import Prelude hiding (lines) -- | A block of text, which is made up of multiple lines and can have blank -- lines before and/or after it. data Block = Block { -- | Does this block have a blank line before it? lineBefore :: Bool, lines :: [Line.Line], -- | Does this block have a blank line after it? lineAfter :: Bool } deriving (Eq, Show) -- | Joins two blocks together by adding a blank line between them if -- necessary. (A blank line is necessary if /either/ block needs a space.) If -- either block is empty, the other block is returned. instance Semigroup Block where x <> y = let s = [Line.empty | lineAfter x || lineBefore y] z = Block { lineBefore = lineBefore x, lines = lines x <> s <> lines y, lineAfter = lineAfter y } in if isEmpty x then y else if isEmpty y then x else z -- | The empty block has no lines and also no blank lines before or after. instance Monoid Block where mempty = Block { lineBefore = False, lines = [], lineAfter = False } -- | Converts a single line into a block without blank lines before or after. fromLine :: Line.Line -> Block fromLine l = mempty {lines = [l]} -- | Returns 'True' if the block has no lines. isEmpty :: Block -> Bool isEmpty = null . lines -- | A lens for the 'lineAfter' field. lineAfterLens :: Lens.Lens' Block Bool lineAfterLens f s = fmap (\a -> s {lineAfter = a}) . f $ lineAfter s -- | A lens for the 'lineBefore' field. lineBeforeLens :: Lens.Lens' Block Bool lineBeforeLens f s = fmap (\a -> s {lineBefore = a}) . f $ lineBefore s -- | Converts a block into a 'ByteString.ByteString' by joining the lines -- together with newline characters. Note that unline 'unlines', there will be -- no trailing newline unless 'lineAfter' is 'True'. toByteString :: Block -> ByteString.ByteString toByteString b = if isEmpty b then ByteString.empty else ByteString.intercalate (ByteString.singleton 0x0a) . fmap Line.toByteString $ concat [ [Line.empty | lineBefore b], lines b, [Line.empty | lineAfter b] ]