packages feed

cabal-gild-0.3.0.1: source/library/CabalGild/Type/Chunk.hs

-- | This module defines the 'Chunk' data type.
module CabalGild.Type.Chunk where

import qualified Data.ByteString as ByteString
import qualified Distribution.Compat.Lens as Lens

-- | A chunk of text, which is made up of a byte string and can have blank
-- spaces before and/or after it.
data Chunk = Chunk
  { -- | Does this chunk have a blank space before it?
    spaceBefore :: Bool,
    value :: ByteString.ByteString,
    -- | Does this chunk have a blank space after it?
    spaceAfter :: Bool
  }
  deriving (Eq, Show)

-- | Joins two chunks together by adding a blank space between them if
-- necessary. (A blank space is necessary if /both/ chunks need a space.) If
-- either chunk is empty, the other chunk is returned.
instance Semigroup Chunk where
  x <> y =
    let s =
          if spaceAfter x && spaceBefore y
            then ByteString.singleton 0x20
            else ByteString.empty
        z =
          Chunk
            { spaceBefore = spaceBefore x,
              value = value x <> s <> value y,
              spaceAfter = spaceAfter y
            }
     in if isEmpty x then y else if isEmpty y then x else z

-- | The empty chunk has no value and also no blank spaces before or after.
instance Monoid Chunk where
  mempty =
    Chunk
      { spaceBefore = False,
        value = ByteString.empty,
        spaceAfter = False
      }

-- | A colon with a space after.
colon :: Chunk
colon = Lens.set spaceAfterLens True . fromByteString $ ByteString.singleton 0x3a

-- | Converts a byte string into a chunk without blank spaces before or after.
fromByteString :: ByteString.ByteString -> Chunk
fromByteString bs = mempty {value = bs}

-- | Returns 'True' if the chunk's byte string is empty.
isEmpty :: Chunk -> Bool
isEmpty = ByteString.null . value

-- | A lens for the 'spaceAfter' field.
spaceAfterLens :: Lens.Lens' Chunk Bool
spaceAfterLens f s = fmap (\a -> s {spaceAfter = a}) . f $ spaceAfter s

-- | A lens for the 'spaceBefore' field.
spaceBeforeLens :: Lens.Lens' Chunk Bool
spaceBeforeLens f s = fmap (\a -> s {spaceBefore = a}) . f $ spaceBefore s